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