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