1 //===- clang/Basic/DirectoryEntry.h - Directory references ------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// Defines interfaces for clang::DirectoryEntry and clang::DirectoryEntryRef. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CLANG_BASIC_DIRECTORYENTRY_H 15 #define LLVM_CLANG_BASIC_DIRECTORYENTRY_H 16 17 #include "clang/Basic/LLVM.h" 18 #include "llvm/ADT/DenseMapInfo.h" 19 #include "llvm/ADT/Hashing.h" 20 #include "llvm/ADT/StringMap.h" 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/Support/ErrorOr.h" 23 24 namespace clang { 25 namespace FileMgr { 26 27 template <class RefTy> class MapEntryOptionalStorage; 28 29 } // end namespace FileMgr 30 31 /// Cached information about one directory (either on disk or in 32 /// the virtual file system). 33 class DirectoryEntry { 34 friend class FileManager; 35 36 // FIXME: We should not be storing a directory entry name here. 37 StringRef Name; // Name of the directory. 38 39 public: getName()40 StringRef getName() const { return Name; } 41 }; 42 43 /// A reference to a \c DirectoryEntry that includes the name of the directory 44 /// as it was accessed by the FileManager's client. 45 class DirectoryEntryRef { 46 public: getDirEntry()47 const DirectoryEntry &getDirEntry() const { return *ME->getValue(); } 48 getName()49 StringRef getName() const { return ME->getKey(); } 50 51 /// Hash code is based on the DirectoryEntry, not the specific named 52 /// reference. hash_value(DirectoryEntryRef Ref)53 friend llvm::hash_code hash_value(DirectoryEntryRef Ref) { 54 return llvm::hash_value(&Ref.getDirEntry()); 55 } 56 57 using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>>; 58 getMapEntry()59 const MapEntry &getMapEntry() const { return *ME; } 60 61 /// Check if RHS referenced the file in exactly the same way. isSameRef(DirectoryEntryRef RHS)62 bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; } 63 64 DirectoryEntryRef() = delete; DirectoryEntryRef(const MapEntry & ME)65 DirectoryEntryRef(const MapEntry &ME) : ME(&ME) {} 66 67 /// Allow DirectoryEntryRef to degrade into 'const DirectoryEntry*' to 68 /// facilitate incremental adoption. 69 /// 70 /// The goal is to avoid code churn due to dances like the following: 71 /// \code 72 /// // Old code. 73 /// lvalue = rvalue; 74 /// 75 /// // Temporary code from an incremental patch. 76 /// lvalue = &rvalue.getDirectoryEntry(); 77 /// 78 /// // Final code. 79 /// lvalue = rvalue; 80 /// \endcode 81 /// 82 /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::getName 83 /// has been deleted, delete this implicit conversion. 84 operator const DirectoryEntry *() const { return &getDirEntry(); } 85 86 private: 87 friend class FileMgr::MapEntryOptionalStorage<DirectoryEntryRef>; 88 struct optional_none_tag {}; 89 90 // Private constructor for use by OptionalStorage. DirectoryEntryRef(optional_none_tag)91 DirectoryEntryRef(optional_none_tag) : ME(nullptr) {} hasOptionalValue()92 bool hasOptionalValue() const { return ME; } 93 94 friend struct llvm::DenseMapInfo<DirectoryEntryRef>; 95 struct dense_map_empty_tag {}; 96 struct dense_map_tombstone_tag {}; 97 98 // Private constructors for use by DenseMapInfo. 99 DirectoryEntryRef(dense_map_empty_tag) 100 : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {} 101 DirectoryEntryRef(dense_map_tombstone_tag) 102 : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {} 103 bool isSpecialDenseMapKey() const { 104 return isSameRef(DirectoryEntryRef(dense_map_empty_tag())) || 105 isSameRef(DirectoryEntryRef(dense_map_tombstone_tag())); 106 } 107 108 const MapEntry *ME; 109 }; 110 111 namespace FileMgr { 112 113 /// Customized storage for refs derived from map entires in FileManager, using 114 /// the private optional_none_tag to keep it to the size of a single pointer. 115 template <class RefTy> class MapEntryOptionalStorage { 116 using optional_none_tag = typename RefTy::optional_none_tag; 117 RefTy MaybeRef; 118 119 public: 120 MapEntryOptionalStorage() : MaybeRef(optional_none_tag()) {} 121 122 template <class... ArgTypes> 123 explicit MapEntryOptionalStorage(llvm::optional_detail::in_place_t, 124 ArgTypes &&...Args) 125 : MaybeRef(std::forward<ArgTypes>(Args)...) {} 126 127 void reset() { MaybeRef = optional_none_tag(); } 128 129 bool hasValue() const { return MaybeRef.hasOptionalValue(); } 130 131 RefTy &getValue() LLVM_LVALUE_FUNCTION { 132 assert(hasValue()); 133 return MaybeRef; 134 } 135 RefTy const &getValue() const LLVM_LVALUE_FUNCTION { 136 assert(hasValue()); 137 return MaybeRef; 138 } 139 #if LLVM_HAS_RVALUE_REFERENCE_THIS 140 RefTy &&getValue() && { 141 assert(hasValue()); 142 return std::move(MaybeRef); 143 } 144 #endif 145 146 template <class... Args> void emplace(Args &&...args) { 147 MaybeRef = RefTy(std::forward<Args>(args)...); 148 } 149 150 MapEntryOptionalStorage &operator=(RefTy Ref) { 151 MaybeRef = Ref; 152 return *this; 153 } 154 }; 155 156 } // end namespace FileMgr 157 } // end namespace clang 158 159 namespace llvm { 160 namespace optional_detail { 161 162 /// Customize OptionalStorage<DirectoryEntryRef> to use DirectoryEntryRef and 163 /// its optional_none_tag to keep it the size of a single pointer. 164 template <> 165 class OptionalStorage<clang::DirectoryEntryRef> 166 : public clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef> { 167 using StorageImpl = 168 clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef>; 169 170 public: 171 OptionalStorage() = default; 172 173 template <class... ArgTypes> 174 explicit OptionalStorage(in_place_t, ArgTypes &&...Args) 175 : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {} 176 177 OptionalStorage &operator=(clang::DirectoryEntryRef Ref) { 178 StorageImpl::operator=(Ref); 179 return *this; 180 } 181 }; 182 183 static_assert(sizeof(Optional<clang::DirectoryEntryRef>) == 184 sizeof(clang::DirectoryEntryRef), 185 "Optional<DirectoryEntryRef> must avoid size overhead"); 186 187 static_assert( 188 std::is_trivially_copyable<Optional<clang::DirectoryEntryRef>>::value, 189 "Optional<DirectoryEntryRef> should be trivially copyable"); 190 191 } // end namespace optional_detail 192 193 /// Specialisation of DenseMapInfo for DirectoryEntryRef. 194 template <> struct DenseMapInfo<clang::DirectoryEntryRef> { 195 static inline clang::DirectoryEntryRef getEmptyKey() { 196 return clang::DirectoryEntryRef( 197 clang::DirectoryEntryRef::dense_map_empty_tag()); 198 } 199 200 static inline clang::DirectoryEntryRef getTombstoneKey() { 201 return clang::DirectoryEntryRef( 202 clang::DirectoryEntryRef::dense_map_tombstone_tag()); 203 } 204 205 static unsigned getHashValue(clang::DirectoryEntryRef Val) { 206 return hash_value(Val); 207 } 208 209 static bool isEqual(clang::DirectoryEntryRef LHS, 210 clang::DirectoryEntryRef RHS) { 211 // Catch the easy cases: both empty, both tombstone, or the same ref. 212 if (LHS.isSameRef(RHS)) 213 return true; 214 215 // Confirm LHS and RHS are valid. 216 if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey()) 217 return false; 218 219 // It's safe to use operator==. 220 return LHS == RHS; 221 } 222 }; 223 224 } // end namespace llvm 225 226 namespace clang { 227 228 /// Wrapper around Optional<DirectoryEntryRef> that degrades to 'const 229 /// DirectoryEntry*', facilitating incremental patches to propagate 230 /// DirectoryEntryRef. 231 /// 232 /// This class can be used as return value or field where it's convenient for 233 /// an Optional<DirectoryEntryRef> to degrade to a 'const DirectoryEntry*'. The 234 /// purpose is to avoid code churn due to dances like the following: 235 /// \code 236 /// // Old code. 237 /// lvalue = rvalue; 238 /// 239 /// // Temporary code from an incremental patch. 240 /// Optional<DirectoryEntryRef> MaybeF = rvalue; 241 /// lvalue = MaybeF ? &MaybeF.getDirectoryEntry() : nullptr; 242 /// 243 /// // Final code. 244 /// lvalue = rvalue; 245 /// \endcode 246 /// 247 /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::LastRef 248 /// and DirectoryEntry::getName have been deleted, delete this class and 249 /// replace instances with Optional<DirectoryEntryRef>. 250 class OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr 251 : public Optional<DirectoryEntryRef> { 252 public: 253 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr() = default; 254 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr( 255 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default; 256 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr( 257 const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default; 258 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr & 259 operator=(OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default; 260 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr & 261 operator=(const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default; 262 263 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(llvm::NoneType) {} 264 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(DirectoryEntryRef Ref) 265 : Optional<DirectoryEntryRef>(Ref) {} 266 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(Optional<DirectoryEntryRef> MaybeRef) 267 : Optional<DirectoryEntryRef>(MaybeRef) {} 268 269 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(llvm::NoneType) { 270 Optional<DirectoryEntryRef>::operator=(None); 271 return *this; 272 } 273 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(DirectoryEntryRef Ref) { 274 Optional<DirectoryEntryRef>::operator=(Ref); 275 return *this; 276 } 277 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr & 278 operator=(Optional<DirectoryEntryRef> MaybeRef) { 279 Optional<DirectoryEntryRef>::operator=(MaybeRef); 280 return *this; 281 } 282 283 /// Degrade to 'const DirectoryEntry *' to allow DirectoryEntry::LastRef and 284 /// DirectoryEntry::getName have been deleted, delete this class and replace 285 /// instances with Optional<DirectoryEntryRef> 286 operator const DirectoryEntry *() const { 287 return hasValue() ? &getValue().getDirEntry() : nullptr; 288 } 289 }; 290 291 static_assert(std::is_trivially_copyable< 292 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr>::value, 293 "OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr should be " 294 "trivially copyable"); 295 296 } // end namespace clang 297 298 #endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H 299