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/LLVM.h"
18#include "llvm/ADT/DenseMapInfo.h"
19#include "llvm/ADT/Hashing.h"
20#include "llvm/ADT/StringMap.h"
21#include "llvm/ADT/StringRef.h"
22#include "llvm/Support/ErrorOr.h"
23
24namespace clang {
25namespace FileMgr {
26
27template <class RefTy> class MapEntryOptionalStorage;
28
29} // end namespace FileMgr
30
31/// Cached information about one directory (either on disk or in
32/// the virtual file system).
33class DirectoryEntry {
34 friend class FileManager;
35
36 // FIXME: We should not be storing a directory entry name here.
37 StringRef Name; // Name of the directory.
38
39public:
40 StringRef getName() const { return Name; }
41};
42
43/// A reference to a \c DirectoryEntry that includes the name of the directory
44/// as it was accessed by the FileManager's client.
45class DirectoryEntryRef {
46public:
47 const DirectoryEntry &getDirEntry() const { return *ME->getValue(); }
48
49 StringRef getName() const { return ME->getKey(); }
50
51 /// Hash code is based on the DirectoryEntry, not the specific named
52 /// reference.
53 friend llvm::hash_code hash_value(DirectoryEntryRef Ref) {
54 return llvm::hash_value(&Ref.getDirEntry());
55 }
56
57 using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>>;
58
59 const MapEntry &getMapEntry() const { return *ME; }
60
61 /// Check if RHS referenced the file in exactly the same way.
62 bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; }
63
64 DirectoryEntryRef() = delete;
65 DirectoryEntryRef(const MapEntry &ME) : ME(&ME) {}
66
67 /// Allow DirectoryEntryRef to degrade into 'const DirectoryEntry*' to
68 /// facilitate incremental adoption.
69 ///
70 /// The goal is to avoid code churn due to dances like the following:
71 /// \code
72 /// // Old code.
73 /// lvalue = rvalue;
74 ///
75 /// // Temporary code from an incremental patch.
76 /// lvalue = &rvalue.getDirectoryEntry();
77 ///
78 /// // Final code.
79 /// lvalue = rvalue;
80 /// \endcode
81 ///
82 /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::getName
83 /// has been deleted, delete this implicit conversion.
84 operator const DirectoryEntry *() const { return &getDirEntry(); }
85
86private:
87 friend class FileMgr::MapEntryOptionalStorage<DirectoryEntryRef>;
88 struct optional_none_tag {};
89
90 // Private constructor for use by OptionalStorage.
91 DirectoryEntryRef(optional_none_tag) : ME(nullptr) {}
92 bool hasOptionalValue() const { return ME; }
93
94 friend struct llvm::DenseMapInfo<DirectoryEntryRef>;
95 struct dense_map_empty_tag {};
96 struct dense_map_tombstone_tag {};
97
98 // Private constructors for use by DenseMapInfo.
99 DirectoryEntryRef(dense_map_empty_tag)
100 : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {}
101 DirectoryEntryRef(dense_map_tombstone_tag)
102 : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {}
103 bool isSpecialDenseMapKey() const {
104 return isSameRef(DirectoryEntryRef(dense_map_empty_tag())) ||
105 isSameRef(DirectoryEntryRef(dense_map_tombstone_tag()));
106 }
107
108 const MapEntry *ME;
109};
110
111namespace FileMgr {
112
113/// Customized storage for refs derived from map entires in FileManager, using
114/// the private optional_none_tag to keep it to the size of a single pointer.
115template <class RefTy> class MapEntryOptionalStorage {
116 using optional_none_tag = typename RefTy::optional_none_tag;
117 RefTy MaybeRef;
118
119public:
120 MapEntryOptionalStorage() : MaybeRef(optional_none_tag()) {}
121
122 template <class... ArgTypes>
123 explicit MapEntryOptionalStorage(llvm::optional_detail::in_place_t,
124 ArgTypes &&...Args)
125 : MaybeRef(std::forward<ArgTypes>(Args)...) {}
126
127 void reset() { MaybeRef = optional_none_tag(); }
128
129 bool hasValue() const { return MaybeRef.hasOptionalValue(); }
130
131 RefTy &getValue() LLVM_LVALUE_FUNCTION {
132 assert(hasValue());
133 return MaybeRef;
134 }
135 RefTy const &getValue() const LLVM_LVALUE_FUNCTION {
136 assert(hasValue());
137 return MaybeRef;
138 }
139#if LLVM_HAS_RVALUE_REFERENCE_THIS
140 RefTy &&getValue() && {
141 assert(hasValue());
142 return std::move(MaybeRef);
143 }
144#endif
145
146 template <class... Args> void emplace(Args &&...args) {
147 MaybeRef = RefTy(std::forward<Args>(args)...);
148 }
149
150 MapEntryOptionalStorage &operator=(RefTy Ref) {
151 MaybeRef = Ref;
152 return *this;
153 }
154};
155
156} // end namespace FileMgr
157} // end namespace clang
158
159namespace llvm {
160namespace 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.
164template <>
165class OptionalStorage<clang::DirectoryEntryRef>
166 : public clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef> {
167 using StorageImpl =
168 clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef>;
169
170public:
171 OptionalStorage() = default;
172
173 template <class... ArgTypes>
174 explicit OptionalStorage(in_place_t, ArgTypes &&...Args)
175 : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {}
176
177 OptionalStorage &operator=(clang::DirectoryEntryRef Ref) {
178 StorageImpl::operator=(Ref);
179 return *this;
180 }
181};
182
183static_assert(sizeof(Optional<clang::DirectoryEntryRef>) ==
184 sizeof(clang::DirectoryEntryRef),
185 "Optional<DirectoryEntryRef> must avoid size overhead");
186
187static_assert(
188 std::is_trivially_copyable<Optional<clang::DirectoryEntryRef>>::value,
189 "Optional<DirectoryEntryRef> should be trivially copyable");
190
191} // end namespace optional_detail
192
193/// Specialisation of DenseMapInfo for DirectoryEntryRef.
194template <> struct DenseMapInfo<clang::DirectoryEntryRef> {
195 static inline clang::DirectoryEntryRef getEmptyKey() {
196 return clang::DirectoryEntryRef(
197 clang::DirectoryEntryRef::dense_map_empty_tag());
198 }
199
200 static inline clang::DirectoryEntryRef getTombstoneKey() {
201 return clang::DirectoryEntryRef(
202 clang::DirectoryEntryRef::dense_map_tombstone_tag());
203 }
204
205 static unsigned getHashValue(clang::DirectoryEntryRef Val) {
206 return hash_value(Val);
207 }
208
209 static bool isEqual(clang::DirectoryEntryRef LHS,
210 clang::DirectoryEntryRef RHS) {
211 // Catch the easy cases: both empty, both tombstone, or the same ref.
212 if (LHS.isSameRef(RHS))
213 return true;
214
215 // Confirm LHS and RHS are valid.
216 if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey())
217 return false;
218
219 // It's safe to use operator==.
220 return LHS == RHS;
221 }
222};
223
224} // end namespace llvm
225
226namespace clang {
227
228/// Wrapper around Optional<DirectoryEntryRef> that degrades to 'const
229/// DirectoryEntry*', facilitating incremental patches to propagate
230/// DirectoryEntryRef.
231///
232/// This class can be used as return value or field where it's convenient for
233/// an Optional<DirectoryEntryRef> to degrade to a 'const DirectoryEntry*'. The
234/// purpose is to avoid code churn due to dances like the following:
235/// \code
236/// // Old code.
237/// lvalue = rvalue;
238///
239/// // Temporary code from an incremental patch.
240/// Optional<DirectoryEntryRef> MaybeF = rvalue;
241/// lvalue = MaybeF ? &MaybeF.getDirectoryEntry() : nullptr;
242///
243/// // Final code.
244/// lvalue = rvalue;
245/// \endcode
246///
247/// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::LastRef
248/// and DirectoryEntry::getName have been deleted, delete this class and
249/// replace instances with Optional<DirectoryEntryRef>.
250class OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr
251 : public Optional<DirectoryEntryRef> {
252public:
253 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr() = default;
254 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
255 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
256 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
257 const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
258 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
259 operator=(OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
260 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
261 operator=(const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
262
263 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(llvm::NoneType) {}
264 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(DirectoryEntryRef Ref)
265 : Optional<DirectoryEntryRef>(Ref) {}
266 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(Optional<DirectoryEntryRef> MaybeRef)
267 : Optional<DirectoryEntryRef>(MaybeRef) {}
268
269 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(llvm::NoneType) {
270 Optional<DirectoryEntryRef>::operator=(None);
271 return *this;
272 }
273 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(DirectoryEntryRef Ref) {
274 Optional<DirectoryEntryRef>::operator=(Ref);
275 return *this;
276 }
277 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
278 operator=(Optional<DirectoryEntryRef> MaybeRef) {
279 Optional<DirectoryEntryRef>::operator=(MaybeRef);
280 return *this;
281 }
282
283 /// Degrade to 'const DirectoryEntry *' to allow DirectoryEntry::LastRef and
284 /// DirectoryEntry::getName have been deleted, delete this class and replace
285 /// instances with Optional<DirectoryEntryRef>
286 operator const DirectoryEntry *() const {
287 return hasValue() ? &getValue().getDirEntry() : nullptr;
288 }
289};
290
291static_assert(std::is_trivially_copyable<
292 OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr>::value,
293 "OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr should be "
294 "trivially copyable");
295
296} // end namespace clang
297
298#endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H
299