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
29namespace clang {
30namespace FileMgr {
31
32template <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).
38class 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.
48class DirectoryEntryRef {
49public:
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
89private:
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
114using OptionalDirectoryEntryRef = CustomizableOptional<DirectoryEntryRef>;
115
116namespace 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.
120template <class RefTy> class MapEntryOptionalStorage {
121 using optional_none_tag = typename RefTy::optional_none_tag;
122 RefTy MaybeRef;
123
124public:
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
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(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
183static_assert(sizeof(OptionalDirectoryEntryRef) == sizeof(DirectoryEntryRef),
184 "OptionalDirectoryEntryRef must avoid size overhead");
185
186static_assert(std::is_trivially_copyable<OptionalDirectoryEntryRef>::value,
187 "OptionalDirectoryEntryRef should be trivially copyable");
188
189} // end namespace optional_detail
190} // namespace clang
191
192namespace llvm {
193
194template <> 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.
209template <> 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

source code of clang/include/clang/Basic/DirectoryEntry.h