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