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: |
50 | const DirectoryEntry &getDirEntry() const { return *ME->getValue(); } |
51 | |
52 | StringRef getName() const { return ME->getKey(); } |
53 | |
54 | /// Hash code is based on the DirectoryEntry, not the specific named |
55 | /// reference. |
56 | friend llvm::hash_code hash_value(DirectoryEntryRef Ref) { |
57 | return llvm::hash_value(ptr: &Ref.getDirEntry()); |
58 | } |
59 | |
60 | using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>>; |
61 | |
62 | const MapEntry &getMapEntry() const { return *ME; } |
63 | |
64 | /// Check if RHS referenced the file in exactly the same way. |
65 | bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; } |
66 | |
67 | DirectoryEntryRef() = delete; |
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. |
94 | DirectoryEntryRef(optional_none_tag) : ME(nullptr) {} |
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(RHS: DirectoryEntryRef(dense_map_empty_tag())) || |
108 | isSameRef(RHS: 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(Ref: 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 | |