xref: /freebsd/contrib/llvm-project/clang/include/clang/Basic/DirectoryEntry.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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