Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 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 | 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: |
||
| 56 | const DirectoryEntry &getDirEntry() const { return *ME->getValue(); } |
||
| 57 | |||
| 58 | StringRef getName() const { return ME->getKey(); } |
||
| 59 | |||
| 60 | /// Hash code is based on the DirectoryEntry, not the specific named |
||
| 61 | /// reference. |
||
| 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 | |||
| 68 | const MapEntry &getMapEntry() const { return *ME; } |
||
| 69 | |||
| 70 | /// Check if RHS referenced the file in exactly the same way. |
||
| 71 | bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; } |
||
| 72 | |||
| 73 | DirectoryEntryRef() = delete; |
||
| 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. |
||
| 100 | DirectoryEntryRef(optional_none_tag) : ME(nullptr) {} |
||
| 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 |