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