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::in_place_t, ArgTypes &&...Args) 124 : MaybeRef(std::forward<ArgTypes>(Args)...) {} 125 126 void reset() { MaybeRef = optional_none_tag(); } 127 128 bool hasValue() const { return MaybeRef.hasOptionalValue(); } 129 130 RefTy &getValue() LLVM_LVALUE_FUNCTION { 131 assert(hasValue()); 132 return MaybeRef; 133 } 134 RefTy const &getValue() const LLVM_LVALUE_FUNCTION { 135 assert(hasValue()); 136 return MaybeRef; 137 } 138 #if LLVM_HAS_RVALUE_REFERENCE_THIS 139 RefTy &&getValue() && { 140 assert(hasValue()); 141 return std::move(MaybeRef); 142 } 143 #endif 144 145 template <class... Args> void emplace(Args &&...args) { 146 MaybeRef = RefTy(std::forward<Args>(args)...); 147 } 148 149 MapEntryOptionalStorage &operator=(RefTy Ref) { 150 MaybeRef = Ref; 151 return *this; 152 } 153 }; 154 155 } // end namespace FileMgr 156 } // end namespace clang 157 158 namespace llvm { 159 namespace optional_detail { 160 161 /// Customize OptionalStorage<DirectoryEntryRef> to use DirectoryEntryRef and 162 /// its optional_none_tag to keep it the size of a single pointer. 163 template <> 164 class OptionalStorage<clang::DirectoryEntryRef> 165 : public clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef> { 166 using StorageImpl = 167 clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef>; 168 169 public: 170 OptionalStorage() = default; 171 172 template <class... ArgTypes> 173 explicit OptionalStorage(in_place_t, ArgTypes &&...Args) 174 : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {} 175 176 OptionalStorage &operator=(clang::DirectoryEntryRef Ref) { 177 StorageImpl::operator=(Ref); 178 return *this; 179 } 180 }; 181 182 static_assert(sizeof(Optional<clang::DirectoryEntryRef>) == 183 sizeof(clang::DirectoryEntryRef), 184 "Optional<DirectoryEntryRef> must avoid size overhead"); 185 186 static_assert( 187 std::is_trivially_copyable<Optional<clang::DirectoryEntryRef>>::value, 188 "Optional<DirectoryEntryRef> should be trivially copyable"); 189 190 } // end namespace optional_detail 191 192 /// Specialisation of DenseMapInfo for DirectoryEntryRef. 193 template <> struct DenseMapInfo<clang::DirectoryEntryRef> { 194 static inline clang::DirectoryEntryRef getEmptyKey() { 195 return clang::DirectoryEntryRef( 196 clang::DirectoryEntryRef::dense_map_empty_tag()); 197 } 198 199 static inline clang::DirectoryEntryRef getTombstoneKey() { 200 return clang::DirectoryEntryRef( 201 clang::DirectoryEntryRef::dense_map_tombstone_tag()); 202 } 203 204 static unsigned getHashValue(clang::DirectoryEntryRef Val) { 205 return hash_value(Val); 206 } 207 208 static bool isEqual(clang::DirectoryEntryRef LHS, 209 clang::DirectoryEntryRef RHS) { 210 // Catch the easy cases: both empty, both tombstone, or the same ref. 211 if (LHS.isSameRef(RHS)) 212 return true; 213 214 // Confirm LHS and RHS are valid. 215 if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey()) 216 return false; 217 218 // It's safe to use operator==. 219 return LHS == RHS; 220 } 221 }; 222 223 } // end namespace llvm 224 225 namespace clang { 226 227 /// Wrapper around Optional<DirectoryEntryRef> that degrades to 'const 228 /// DirectoryEntry*', facilitating incremental patches to propagate 229 /// DirectoryEntryRef. 230 /// 231 /// This class can be used as return value or field where it's convenient for 232 /// an Optional<DirectoryEntryRef> to degrade to a 'const DirectoryEntry*'. The 233 /// purpose is to avoid code churn due to dances like the following: 234 /// \code 235 /// // Old code. 236 /// lvalue = rvalue; 237 /// 238 /// // Temporary code from an incremental patch. 239 /// Optional<DirectoryEntryRef> MaybeF = rvalue; 240 /// lvalue = MaybeF ? &MaybeF.getDirectoryEntry() : nullptr; 241 /// 242 /// // Final code. 243 /// lvalue = rvalue; 244 /// \endcode 245 /// 246 /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::LastRef 247 /// and DirectoryEntry::getName have been deleted, delete this class and 248 /// replace instances with Optional<DirectoryEntryRef>. 249 class OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr 250 : public Optional<DirectoryEntryRef> { 251 public: 252 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr() = default; 253 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr( 254 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default; 255 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr( 256 const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default; 257 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr & 258 operator=(OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default; 259 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr & 260 operator=(const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default; 261 262 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(llvm::NoneType) {} 263 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(DirectoryEntryRef Ref) 264 : Optional<DirectoryEntryRef>(Ref) {} 265 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(Optional<DirectoryEntryRef> MaybeRef) 266 : Optional<DirectoryEntryRef>(MaybeRef) {} 267 268 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(llvm::NoneType) { 269 Optional<DirectoryEntryRef>::operator=(None); 270 return *this; 271 } 272 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(DirectoryEntryRef Ref) { 273 Optional<DirectoryEntryRef>::operator=(Ref); 274 return *this; 275 } 276 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr & 277 operator=(Optional<DirectoryEntryRef> MaybeRef) { 278 Optional<DirectoryEntryRef>::operator=(MaybeRef); 279 return *this; 280 } 281 282 /// Degrade to 'const DirectoryEntry *' to allow DirectoryEntry::LastRef and 283 /// DirectoryEntry::getName have been deleted, delete this class and replace 284 /// instances with Optional<DirectoryEntryRef> 285 operator const DirectoryEntry *() const { 286 return hasValue() ? &getValue().getDirEntry() : nullptr; 287 } 288 }; 289 290 static_assert(std::is_trivially_copyable< 291 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr>::value, 292 "OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr should be " 293 "trivially copyable"); 294 295 } // end namespace clang 296 297 #endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H 298