xref: /netbsd-src/external/apache2/llvm/dist/clang/include/clang/Basic/DirectoryEntry.h (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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 
24 namespace clang {
25 namespace FileMgr {
26 
27 template <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).
33 class 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 
39 public:
getName()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.
45 class DirectoryEntryRef {
46 public:
getDirEntry()47   const DirectoryEntry &getDirEntry() const { return *ME->getValue(); }
48 
getName()49   StringRef getName() const { return ME->getKey(); }
50 
51   /// Hash code is based on the DirectoryEntry, not the specific named
52   /// reference.
hash_value(DirectoryEntryRef Ref)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 
getMapEntry()59   const MapEntry &getMapEntry() const { return *ME; }
60 
61   /// Check if RHS referenced the file in exactly the same way.
isSameRef(DirectoryEntryRef RHS)62   bool isSameRef(DirectoryEntryRef RHS) const { return ME == RHS.ME; }
63 
64   DirectoryEntryRef() = delete;
DirectoryEntryRef(const MapEntry & ME)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 
86 private:
87   friend class FileMgr::MapEntryOptionalStorage<DirectoryEntryRef>;
88   struct optional_none_tag {};
89 
90   // Private constructor for use by OptionalStorage.
DirectoryEntryRef(optional_none_tag)91   DirectoryEntryRef(optional_none_tag) : ME(nullptr) {}
hasOptionalValue()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 
111 namespace 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.
115 template <class RefTy> class MapEntryOptionalStorage {
116   using optional_none_tag = typename RefTy::optional_none_tag;
117   RefTy MaybeRef;
118 
119 public:
120   MapEntryOptionalStorage() : MaybeRef(optional_none_tag()) {}
121 
122   template <class... ArgTypes>
123   explicit MapEntryOptionalStorage(llvm::in_place_t, ArgTypes &&...Args)
124       : MaybeRef(std::forward<ArgTypes>(Args)...) {}
125 
126   void reset() { MaybeRef = optional_none_tag(); }
127 
128   bool hasValue() const { return MaybeRef.hasOptionalValue(); }
129 
130   RefTy &getValue() LLVM_LVALUE_FUNCTION {
131     assert(hasValue());
132     return MaybeRef;
133   }
134   RefTy const &getValue() const LLVM_LVALUE_FUNCTION {
135     assert(hasValue());
136     return MaybeRef;
137   }
138 #if LLVM_HAS_RVALUE_REFERENCE_THIS
139   RefTy &&getValue() && {
140     assert(hasValue());
141     return std::move(MaybeRef);
142   }
143 #endif
144 
145   template <class... Args> void emplace(Args &&...args) {
146     MaybeRef = RefTy(std::forward<Args>(args)...);
147   }
148 
149   MapEntryOptionalStorage &operator=(RefTy Ref) {
150     MaybeRef = Ref;
151     return *this;
152   }
153 };
154 
155 } // end namespace FileMgr
156 } // end namespace clang
157 
158 namespace llvm {
159 namespace optional_detail {
160 
161 /// Customize OptionalStorage<DirectoryEntryRef> to use DirectoryEntryRef and
162 /// its optional_none_tag to keep it the size of a single pointer.
163 template <>
164 class OptionalStorage<clang::DirectoryEntryRef>
165     : public clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef> {
166   using StorageImpl =
167       clang::FileMgr::MapEntryOptionalStorage<clang::DirectoryEntryRef>;
168 
169 public:
170   OptionalStorage() = default;
171 
172   template <class... ArgTypes>
173   explicit OptionalStorage(in_place_t, ArgTypes &&...Args)
174       : StorageImpl(in_place_t{}, std::forward<ArgTypes>(Args)...) {}
175 
176   OptionalStorage &operator=(clang::DirectoryEntryRef Ref) {
177     StorageImpl::operator=(Ref);
178     return *this;
179   }
180 };
181 
182 static_assert(sizeof(Optional<clang::DirectoryEntryRef>) ==
183                   sizeof(clang::DirectoryEntryRef),
184               "Optional<DirectoryEntryRef> must avoid size overhead");
185 
186 static_assert(
187     std::is_trivially_copyable<Optional<clang::DirectoryEntryRef>>::value,
188     "Optional<DirectoryEntryRef> should be trivially copyable");
189 
190 } // end namespace optional_detail
191 
192 /// Specialisation of DenseMapInfo for DirectoryEntryRef.
193 template <> struct DenseMapInfo<clang::DirectoryEntryRef> {
194   static inline clang::DirectoryEntryRef getEmptyKey() {
195     return clang::DirectoryEntryRef(
196         clang::DirectoryEntryRef::dense_map_empty_tag());
197   }
198 
199   static inline clang::DirectoryEntryRef getTombstoneKey() {
200     return clang::DirectoryEntryRef(
201         clang::DirectoryEntryRef::dense_map_tombstone_tag());
202   }
203 
204   static unsigned getHashValue(clang::DirectoryEntryRef Val) {
205     return hash_value(Val);
206   }
207 
208   static bool isEqual(clang::DirectoryEntryRef LHS,
209                       clang::DirectoryEntryRef RHS) {
210     // Catch the easy cases: both empty, both tombstone, or the same ref.
211     if (LHS.isSameRef(RHS))
212       return true;
213 
214     // Confirm LHS and RHS are valid.
215     if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey())
216       return false;
217 
218     // It's safe to use operator==.
219     return LHS == RHS;
220   }
221 };
222 
223 } // end namespace llvm
224 
225 namespace clang {
226 
227 /// Wrapper around Optional<DirectoryEntryRef> that degrades to 'const
228 /// DirectoryEntry*', facilitating incremental patches to propagate
229 /// DirectoryEntryRef.
230 ///
231 /// This class can be used as return value or field where it's convenient for
232 /// an Optional<DirectoryEntryRef> to degrade to a 'const DirectoryEntry*'. The
233 /// purpose is to avoid code churn due to dances like the following:
234 /// \code
235 /// // Old code.
236 /// lvalue = rvalue;
237 ///
238 /// // Temporary code from an incremental patch.
239 /// Optional<DirectoryEntryRef> MaybeF = rvalue;
240 /// lvalue = MaybeF ? &MaybeF.getDirectoryEntry() : nullptr;
241 ///
242 /// // Final code.
243 /// lvalue = rvalue;
244 /// \endcode
245 ///
246 /// FIXME: Once DirectoryEntryRef is "everywhere" and DirectoryEntry::LastRef
247 /// and DirectoryEntry::getName have been deleted, delete this class and
248 /// replace instances with Optional<DirectoryEntryRef>.
249 class OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr
250     : public Optional<DirectoryEntryRef> {
251 public:
252   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr() = default;
253   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
254       OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
255   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(
256       const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
257   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
258   operator=(OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &&) = default;
259   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
260   operator=(const OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &) = default;
261 
262   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(llvm::NoneType) {}
263   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(DirectoryEntryRef Ref)
264       : Optional<DirectoryEntryRef>(Ref) {}
265   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr(Optional<DirectoryEntryRef> MaybeRef)
266       : Optional<DirectoryEntryRef>(MaybeRef) {}
267 
268   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(llvm::NoneType) {
269     Optional<DirectoryEntryRef>::operator=(None);
270     return *this;
271   }
272   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &operator=(DirectoryEntryRef Ref) {
273     Optional<DirectoryEntryRef>::operator=(Ref);
274     return *this;
275   }
276   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr &
277   operator=(Optional<DirectoryEntryRef> MaybeRef) {
278     Optional<DirectoryEntryRef>::operator=(MaybeRef);
279     return *this;
280   }
281 
282   /// Degrade to 'const DirectoryEntry *' to allow  DirectoryEntry::LastRef and
283   /// DirectoryEntry::getName have been deleted, delete this class and replace
284   /// instances with Optional<DirectoryEntryRef>
285   operator const DirectoryEntry *() const {
286     return hasValue() ? &getValue().getDirEntry() : nullptr;
287   }
288 };
289 
290 static_assert(std::is_trivially_copyable<
291                   OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr>::value,
292               "OptionalDirectoryEntryRefDegradesToDirectoryEntryPtr should be "
293               "trivially copyable");
294 
295 } // end namespace clang
296 
297 #endif // LLVM_CLANG_BASIC_DIRECTORYENTRY_H
298