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