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 46 /// A reference to a \c DirectoryEntry that includes the name of the directory 47 /// as it was accessed by the FileManager's client. 48 class DirectoryEntryRef { 49 public: getDirEntry()50 const DirectoryEntry &getDirEntry() const { return *ME->getValue(); } 51 getName()52 StringRef getName() const { return ME->getKey(); } 53 54 /// Hash code is based on the DirectoryEntry, not the specific named 55 /// reference. hash_value(DirectoryEntryRef Ref)56 friend llvm::hash_code hash_value(DirectoryEntryRef Ref) { 57 return llvm::hash_value(&Ref.getDirEntry()); 58 } 59 60 using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>>; 61 getMapEntry()62 const MapEntry &getMapEntry() const { return *ME; } 63 64 /// Check if RHS referenced the file in exactly the same way. isSameRef(DirectoryEntryRef RHS)65 bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; } 66 67 DirectoryEntryRef() = delete; DirectoryEntryRef(const MapEntry & ME)68 explicit DirectoryEntryRef(const MapEntry &ME) : ME(&ME) {} 69 70 /// Allow DirectoryEntryRef to degrade into 'const DirectoryEntry*' to 71 /// facilitate incremental adoption. 72 /// 73 /// The goal is to avoid code churn due to dances like the following: 74 /// \code 75 /// // Old code. 76 /// lvalue = rvalue; 77 /// 78 /// // Temporary code from an incremental patch. 79 /// lvalue = &rvalue.getDirectoryEntry(); 80 /// 81 /// // Final code. 82 /// lvalue = rvalue; 83 /// \endcode 84 /// 85 /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::getName 86 /// has been deleted, delete this implicit conversion. 87 operator const DirectoryEntry *() const { return &getDirEntry(); } 88 89 private: 90 friend class FileMgr::MapEntryOptionalStorage<DirectoryEntryRef>; 91 struct optional_none_tag {}; 92 93 // Private constructor for use by OptionalStorage. DirectoryEntryRef(optional_none_tag)94 DirectoryEntryRef(optional_none_tag) : ME(nullptr) {} hasOptionalValue()95 bool hasOptionalValue() const { return ME; } 96 97 friend struct llvm::DenseMapInfo<DirectoryEntryRef>; 98 struct dense_map_empty_tag {}; 99 struct dense_map_tombstone_tag {}; 100 101 // Private constructors for use by DenseMapInfo. 102 DirectoryEntryRef(dense_map_empty_tag) 103 : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {} 104 DirectoryEntryRef(dense_map_tombstone_tag) 105 : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {} 106 bool isSpecialDenseMapKey() const { 107 return isSameRef(DirectoryEntryRef(dense_map_empty_tag())) || 108 isSameRef(DirectoryEntryRef(dense_map_tombstone_tag())); 109 } 110 111 const MapEntry *ME; 112 }; 113 114 using OptionalDirectoryEntryRef = CustomizableOptional<DirectoryEntryRef>; 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(std::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 135 RefTy &value() & { 136 assert(has_value()); 137 return MaybeRef; 138 } 139 RefTy const &value() const & { 140 assert(has_value()); 141 return MaybeRef; 142 } 143 RefTy &&value() && { 144 assert(has_value()); 145 return std::move(MaybeRef); 146 } 147 148 template <class... Args> void emplace(Args &&...args) { 149 MaybeRef = RefTy(std::forward<Args>(args)...); 150 } 151 152 MapEntryOptionalStorage &operator=(RefTy Ref) { 153 MaybeRef = Ref; 154 return *this; 155 } 156 }; 157 158 } // end namespace FileMgr 159 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(std::in_place_t, ArgTypes &&...Args) 175 : StorageImpl(std::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(OptionalDirectoryEntryRef) == sizeof(DirectoryEntryRef), 184 "OptionalDirectoryEntryRef must avoid size overhead"); 185 186 static_assert(std::is_trivially_copyable<OptionalDirectoryEntryRef>::value, 187 "OptionalDirectoryEntryRef should be trivially copyable"); 188 189 } // end namespace optional_detail 190 } // namespace clang 191 192 namespace llvm { 193 194 template <> struct PointerLikeTypeTraits<clang::DirectoryEntryRef> { 195 static inline void *getAsVoidPointer(clang::DirectoryEntryRef Dir) { 196 return const_cast<clang::DirectoryEntryRef::MapEntry *>(&Dir.getMapEntry()); 197 } 198 199 static inline clang::DirectoryEntryRef getFromVoidPointer(void *Ptr) { 200 return clang::DirectoryEntryRef( 201 *reinterpret_cast<const clang::DirectoryEntryRef::MapEntry *>(Ptr)); 202 } 203 204 static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits< 205 const clang::DirectoryEntryRef::MapEntry *>::NumLowBitsAvailable; 206 }; 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 #endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H 242