1e8d8bef9SDimitry Andric //===- clang/Basic/DirectoryEntry.h - Directory references ------*- C++ -*-===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric /// 9e8d8bef9SDimitry Andric /// \file 10e8d8bef9SDimitry Andric /// Defines interfaces for clang::DirectoryEntry and clang::DirectoryEntryRef. 11e8d8bef9SDimitry Andric /// 12e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 13e8d8bef9SDimitry Andric 14e8d8bef9SDimitry Andric #ifndef LLVM_CLANG_BASIC_DIRECTORYENTRY_H 15e8d8bef9SDimitry Andric #define LLVM_CLANG_BASIC_DIRECTORYENTRY_H 16e8d8bef9SDimitry Andric 17bdd1243dSDimitry Andric #include "clang/Basic/CustomizableOptional.h" 18e8d8bef9SDimitry Andric #include "clang/Basic/LLVM.h" 19e8d8bef9SDimitry Andric #include "llvm/ADT/DenseMapInfo.h" 20e8d8bef9SDimitry Andric #include "llvm/ADT/Hashing.h" 21bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 22e8d8bef9SDimitry Andric #include "llvm/ADT/StringMap.h" 23e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h" 24e8d8bef9SDimitry Andric #include "llvm/Support/ErrorOr.h" 25e8d8bef9SDimitry Andric 26bdd1243dSDimitry Andric #include <optional> 27bdd1243dSDimitry Andric #include <utility> 28bdd1243dSDimitry Andric 29e8d8bef9SDimitry Andric namespace clang { 30e8d8bef9SDimitry Andric namespace FileMgr { 31e8d8bef9SDimitry Andric 32e8d8bef9SDimitry Andric template <class RefTy> class MapEntryOptionalStorage; 33e8d8bef9SDimitry Andric 34e8d8bef9SDimitry Andric } // end namespace FileMgr 35e8d8bef9SDimitry Andric 36e8d8bef9SDimitry Andric /// Cached information about one directory (either on disk or in 37e8d8bef9SDimitry Andric /// the virtual file system). 38e8d8bef9SDimitry Andric class DirectoryEntry { 3981ad6265SDimitry Andric DirectoryEntry() = default; 4081ad6265SDimitry Andric DirectoryEntry(const DirectoryEntry &) = delete; 4181ad6265SDimitry Andric DirectoryEntry &operator=(const DirectoryEntry &) = delete; 42e8d8bef9SDimitry Andric friend class FileManager; 4381ad6265SDimitry Andric friend class FileEntryTestHelper; 44e8d8bef9SDimitry Andric 45e8d8bef9SDimitry Andric // FIXME: We should not be storing a directory entry name here. 46e8d8bef9SDimitry Andric StringRef Name; // Name of the directory. 47e8d8bef9SDimitry Andric 48e8d8bef9SDimitry Andric public: 49*06c3fb27SDimitry Andric LLVM_DEPRECATED("Use DirectoryEntryRef::getName() instead.", "") getName()50e8d8bef9SDimitry Andric StringRef getName() const { return Name; } 51e8d8bef9SDimitry Andric }; 52e8d8bef9SDimitry Andric 53e8d8bef9SDimitry Andric /// A reference to a \c DirectoryEntry that includes the name of the directory 54e8d8bef9SDimitry Andric /// as it was accessed by the FileManager's client. 55e8d8bef9SDimitry Andric class DirectoryEntryRef { 56e8d8bef9SDimitry Andric public: getDirEntry()57e8d8bef9SDimitry Andric const DirectoryEntry &getDirEntry() const { return *ME->getValue(); } 58e8d8bef9SDimitry Andric getName()59e8d8bef9SDimitry Andric StringRef getName() const { return ME->getKey(); } 60e8d8bef9SDimitry Andric 61e8d8bef9SDimitry Andric /// Hash code is based on the DirectoryEntry, not the specific named 62e8d8bef9SDimitry Andric /// reference. hash_value(DirectoryEntryRef Ref)63e8d8bef9SDimitry Andric friend llvm::hash_code hash_value(DirectoryEntryRef Ref) { 64e8d8bef9SDimitry Andric return llvm::hash_value(&Ref.getDirEntry()); 65e8d8bef9SDimitry Andric } 66e8d8bef9SDimitry Andric 67e8d8bef9SDimitry Andric using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>>; 68e8d8bef9SDimitry Andric getMapEntry()69e8d8bef9SDimitry Andric const MapEntry &getMapEntry() const { return *ME; } 70e8d8bef9SDimitry Andric 71e8d8bef9SDimitry Andric /// Check if RHS referenced the file in exactly the same way. isSameRef(DirectoryEntryRef RHS)72e8d8bef9SDimitry Andric bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; } 73e8d8bef9SDimitry Andric 74e8d8bef9SDimitry Andric DirectoryEntryRef() = delete; DirectoryEntryRef(const MapEntry & ME)75*06c3fb27SDimitry Andric explicit DirectoryEntryRef(const MapEntry &ME) : ME(&ME) {} 76e8d8bef9SDimitry Andric 77e8d8bef9SDimitry Andric /// Allow DirectoryEntryRef to degrade into 'const DirectoryEntry*' to 78e8d8bef9SDimitry Andric /// facilitate incremental adoption. 79e8d8bef9SDimitry Andric /// 80e8d8bef9SDimitry Andric /// The goal is to avoid code churn due to dances like the following: 81e8d8bef9SDimitry Andric /// \code 82e8d8bef9SDimitry Andric /// // Old code. 83e8d8bef9SDimitry Andric /// lvalue = rvalue; 84e8d8bef9SDimitry Andric /// 85e8d8bef9SDimitry Andric /// // Temporary code from an incremental patch. 86e8d8bef9SDimitry Andric /// lvalue = &rvalue.getDirectoryEntry(); 87e8d8bef9SDimitry Andric /// 88e8d8bef9SDimitry Andric /// // Final code. 89e8d8bef9SDimitry Andric /// lvalue = rvalue; 90e8d8bef9SDimitry Andric /// \endcode 91e8d8bef9SDimitry Andric /// 92e8d8bef9SDimitry Andric /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::getName 93e8d8bef9SDimitry Andric /// has been deleted, delete this implicit conversion. 94e8d8bef9SDimitry Andric operator const DirectoryEntry *() const { return &getDirEntry(); } 95e8d8bef9SDimitry Andric 96e8d8bef9SDimitry Andric private: 97e8d8bef9SDimitry Andric friend class FileMgr::MapEntryOptionalStorage<DirectoryEntryRef>; 98e8d8bef9SDimitry Andric struct optional_none_tag {}; 99e8d8bef9SDimitry Andric 100e8d8bef9SDimitry Andric // Private constructor for use by OptionalStorage. DirectoryEntryRef(optional_none_tag)101e8d8bef9SDimitry Andric DirectoryEntryRef(optional_none_tag) : ME(nullptr) {} hasOptionalValue()102e8d8bef9SDimitry Andric bool hasOptionalValue() const { return ME; } 103e8d8bef9SDimitry Andric 104e8d8bef9SDimitry Andric friend struct llvm::DenseMapInfo<DirectoryEntryRef>; 105e8d8bef9SDimitry Andric struct dense_map_empty_tag {}; 106e8d8bef9SDimitry Andric struct dense_map_tombstone_tag {}; 107e8d8bef9SDimitry Andric 108e8d8bef9SDimitry Andric // Private constructors for use by DenseMapInfo. 109e8d8bef9SDimitry Andric DirectoryEntryRef(dense_map_empty_tag) 110e8d8bef9SDimitry Andric : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {} 111e8d8bef9SDimitry Andric DirectoryEntryRef(dense_map_tombstone_tag) 112e8d8bef9SDimitry Andric : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {} 113e8d8bef9SDimitry Andric bool isSpecialDenseMapKey() const { 114e8d8bef9SDimitry Andric return isSameRef(DirectoryEntryRef(dense_map_empty_tag())) || 115e8d8bef9SDimitry Andric isSameRef(DirectoryEntryRef(dense_map_tombstone_tag())); 116e8d8bef9SDimitry Andric } 117e8d8bef9SDimitry Andric 118e8d8bef9SDimitry Andric const MapEntry *ME; 119e8d8bef9SDimitry Andric }; 120e8d8bef9SDimitry Andric 121bdd1243dSDimitry Andric using OptionalDirectoryEntryRef = CustomizableOptional<DirectoryEntryRef>; 122bdd1243dSDimitry Andric 123e8d8bef9SDimitry Andric namespace FileMgr { 124e8d8bef9SDimitry Andric 125e8d8bef9SDimitry Andric /// Customized storage for refs derived from map entires in FileManager, using 126e8d8bef9SDimitry Andric /// the private optional_none_tag to keep it to the size of a single pointer. 127e8d8bef9SDimitry Andric template <class RefTy> class MapEntryOptionalStorage { 128e8d8bef9SDimitry Andric using optional_none_tag = typename RefTy::optional_none_tag; 129e8d8bef9SDimitry Andric RefTy MaybeRef; 130e8d8bef9SDimitry Andric 131e8d8bef9SDimitry Andric public: 132e8d8bef9SDimitry Andric MapEntryOptionalStorage() : MaybeRef(optional_none_tag()) {} 133e8d8bef9SDimitry Andric 134e8d8bef9SDimitry Andric template <class... ArgTypes> 135bdd1243dSDimitry Andric explicit MapEntryOptionalStorage(std::in_place_t, ArgTypes &&...Args) 136e8d8bef9SDimitry Andric : MaybeRef(std::forward<ArgTypes>(Args)...) {} 137e8d8bef9SDimitry Andric 138e8d8bef9SDimitry Andric void reset() { MaybeRef = optional_none_tag(); } 139e8d8bef9SDimitry Andric 14081ad6265SDimitry Andric bool has_value() const { return MaybeRef.hasOptionalValue(); } 141e8d8bef9SDimitry Andric 14281ad6265SDimitry Andric RefTy &value() & { 14381ad6265SDimitry Andric assert(has_value()); 144e8d8bef9SDimitry Andric return MaybeRef; 145e8d8bef9SDimitry Andric } 14681ad6265SDimitry Andric RefTy const &value() const & { 14781ad6265SDimitry Andric assert(has_value()); 14881ad6265SDimitry Andric return MaybeRef; 14981ad6265SDimitry Andric } 15081ad6265SDimitry Andric RefTy &&value() && { 15181ad6265SDimitry Andric assert(has_value()); 152e8d8bef9SDimitry Andric return std::move(MaybeRef); 153e8d8bef9SDimitry Andric } 154e8d8bef9SDimitry Andric 155e8d8bef9SDimitry Andric template <class... Args> void emplace(Args &&...args) { 156e8d8bef9SDimitry Andric MaybeRef = RefTy(std::forward<Args>(args)...); 157e8d8bef9SDimitry Andric } 158e8d8bef9SDimitry Andric 159e8d8bef9SDimitry Andric MapEntryOptionalStorage &operator=(RefTy Ref) { 160e8d8bef9SDimitry Andric MaybeRef = Ref; 161e8d8bef9SDimitry Andric return *this; 162e8d8bef9SDimitry Andric } 163e8d8bef9SDimitry Andric }; 164e8d8bef9SDimitry Andric 165e8d8bef9SDimitry Andric } // end namespace FileMgr 166e8d8bef9SDimitry Andric 167e8d8bef9SDimitry Andric namespace optional_detail { 168e8d8bef9SDimitry Andric 169e8d8bef9SDimitry Andric /// Customize OptionalStorage<DirectoryEntryRef> to use DirectoryEntryRef and 170e8d8bef9SDimitry Andric /// its optional_none_tag to keep it the size of a single pointer. 171e8d8bef9SDimitry Andric template <> 172e8d8bef9SDimitry Andric class OptionalStorage<clang::DirectoryEntryRef> 173e8d8bef9SDimitry Andric : public clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef> { 174e8d8bef9SDimitry Andric using StorageImpl = 175e8d8bef9SDimitry Andric clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef>; 176e8d8bef9SDimitry Andric 177e8d8bef9SDimitry Andric public: 178e8d8bef9SDimitry Andric OptionalStorage() = default; 179e8d8bef9SDimitry Andric 180e8d8bef9SDimitry Andric template <class... ArgTypes> 181bdd1243dSDimitry Andric explicit OptionalStorage(std::in_place_t, ArgTypes &&...Args) 182bdd1243dSDimitry Andric : StorageImpl(std::in_place_t{}, std::forward<ArgTypes>(Args)...) {} 183e8d8bef9SDimitry Andric 184e8d8bef9SDimitry Andric OptionalStorage &operator=(clang::DirectoryEntryRef Ref) { 185e8d8bef9SDimitry Andric StorageImpl::operator=(Ref); 186e8d8bef9SDimitry Andric return *this; 187e8d8bef9SDimitry Andric } 188e8d8bef9SDimitry Andric }; 189e8d8bef9SDimitry Andric 190bdd1243dSDimitry Andric static_assert(sizeof(OptionalDirectoryEntryRef) == sizeof(DirectoryEntryRef), 191bdd1243dSDimitry Andric "OptionalDirectoryEntryRef must avoid size overhead"); 192e8d8bef9SDimitry Andric 193bdd1243dSDimitry Andric static_assert(std::is_trivially_copyable<OptionalDirectoryEntryRef>::value, 194bdd1243dSDimitry Andric "OptionalDirectoryEntryRef should be trivially copyable"); 195e8d8bef9SDimitry Andric 196e8d8bef9SDimitry Andric } // end namespace optional_detail 197bdd1243dSDimitry Andric } // namespace clang 198e8d8bef9SDimitry Andric 199bdd1243dSDimitry Andric namespace llvm { 200*06c3fb27SDimitry Andric 201*06c3fb27SDimitry Andric template <> struct PointerLikeTypeTraits<clang::DirectoryEntryRef> { 202*06c3fb27SDimitry Andric static inline void *getAsVoidPointer(clang::DirectoryEntryRef Dir) { 203*06c3fb27SDimitry Andric return const_cast<clang::DirectoryEntryRef::MapEntry *>(&Dir.getMapEntry()); 204*06c3fb27SDimitry Andric } 205*06c3fb27SDimitry Andric 206*06c3fb27SDimitry Andric static inline clang::DirectoryEntryRef getFromVoidPointer(void *Ptr) { 207*06c3fb27SDimitry Andric return clang::DirectoryEntryRef( 208*06c3fb27SDimitry Andric *reinterpret_cast<const clang::DirectoryEntryRef::MapEntry *>(Ptr)); 209*06c3fb27SDimitry Andric } 210*06c3fb27SDimitry Andric 211*06c3fb27SDimitry Andric static constexpr int NumLowBitsAvailable = PointerLikeTypeTraits< 212*06c3fb27SDimitry Andric const clang::DirectoryEntryRef::MapEntry *>::NumLowBitsAvailable; 213*06c3fb27SDimitry Andric }; 214*06c3fb27SDimitry Andric 215e8d8bef9SDimitry Andric /// Specialisation of DenseMapInfo for DirectoryEntryRef. 216e8d8bef9SDimitry Andric template <> struct DenseMapInfo<clang::DirectoryEntryRef> { 217e8d8bef9SDimitry Andric static inline clang::DirectoryEntryRef getEmptyKey() { 218e8d8bef9SDimitry Andric return clang::DirectoryEntryRef( 219e8d8bef9SDimitry Andric clang::DirectoryEntryRef::dense_map_empty_tag()); 220e8d8bef9SDimitry Andric } 221e8d8bef9SDimitry Andric 222e8d8bef9SDimitry Andric static inline clang::DirectoryEntryRef getTombstoneKey() { 223e8d8bef9SDimitry Andric return clang::DirectoryEntryRef( 224e8d8bef9SDimitry Andric clang::DirectoryEntryRef::dense_map_tombstone_tag()); 225e8d8bef9SDimitry Andric } 226e8d8bef9SDimitry Andric 227e8d8bef9SDimitry Andric static unsigned getHashValue(clang::DirectoryEntryRef Val) { 228e8d8bef9SDimitry Andric return hash_value(Val); 229e8d8bef9SDimitry Andric } 230e8d8bef9SDimitry Andric 231e8d8bef9SDimitry Andric static bool isEqual(clang::DirectoryEntryRef LHS, 232e8d8bef9SDimitry Andric clang::DirectoryEntryRef RHS) { 233e8d8bef9SDimitry Andric // Catch the easy cases: both empty, both tombstone, or the same ref. 234e8d8bef9SDimitry Andric if (LHS.isSameRef(RHS)) 235e8d8bef9SDimitry Andric return true; 236e8d8bef9SDimitry Andric 237e8d8bef9SDimitry Andric // Confirm LHS and RHS are valid. 238e8d8bef9SDimitry Andric if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey()) 239e8d8bef9SDimitry Andric return false; 240e8d8bef9SDimitry Andric 241e8d8bef9SDimitry Andric // It's safe to use operator==. 242e8d8bef9SDimitry Andric return LHS == RHS; 243e8d8bef9SDimitry Andric } 244e8d8bef9SDimitry Andric }; 245e8d8bef9SDimitry Andric 246e8d8bef9SDimitry Andric } // end namespace llvm 247e8d8bef9SDimitry Andric 248e8d8bef9SDimitry Andric #endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H 249