xref: /openbsd-src/gnu/llvm/clang/include/clang/Basic/FileEntry.h (revision 12c855180aad702bbcca06e0398d774beeafb155)
1 //===- clang/Basic/FileEntry.h - File 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::FileEntry and clang::FileEntryRef.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CLANG_BASIC_FILEENTRY_H
15 #define LLVM_CLANG_BASIC_FILEENTRY_H
16 
17 #include "clang/Basic/CustomizableOptional.h"
18 #include "clang/Basic/DirectoryEntry.h"
19 #include "clang/Basic/LLVM.h"
20 #include "llvm/ADT/DenseMapInfo.h"
21 #include "llvm/ADT/Hashing.h"
22 #include "llvm/ADT/PointerUnion.h"
23 #include "llvm/ADT/StringMap.h"
24 #include "llvm/ADT/StringRef.h"
25 #include "llvm/Support/ErrorOr.h"
26 #include "llvm/Support/FileSystem/UniqueID.h"
27 
28 #include <optional>
29 #include <utility>
30 
31 namespace llvm {
32 
33 class MemoryBuffer;
34 
35 namespace vfs {
36 
37 class File;
38 
39 } // namespace vfs
40 } // namespace llvm
41 
42 namespace clang {
43 
44 class FileEntryRef;
45 
46 namespace optional_detail {
47 
48 /// Forward declare a template specialization for OptionalStorage.
49 template <> class OptionalStorage<clang::FileEntryRef>;
50 
51 } // namespace optional_detail
52 
53 class FileEntry;
54 
55 /// A reference to a \c FileEntry that includes the name of the file as it was
56 /// accessed by the FileManager's client.
57 class FileEntryRef {
58 public:
59   /// The name of this FileEntry. If a VFS uses 'use-external-name', this is
60   /// the redirected name. See getRequestedName().
getName()61   StringRef getName() const { return getBaseMapEntry().first(); }
62 
63   /// The name of this FileEntry, as originally requested without applying any
64   /// remappings for VFS 'use-external-name'.
65   ///
66   /// FIXME: this should be the semantics of getName(). See comment in
67   /// FileManager::getFileRef().
getNameAsRequested()68   StringRef getNameAsRequested() const { return ME->first(); }
69 
getFileEntry()70   const FileEntry &getFileEntry() const {
71     return *getBaseMapEntry().second->V.get<FileEntry *>();
72   }
getDir()73   DirectoryEntryRef getDir() const { return *getBaseMapEntry().second->Dir; }
74 
75   inline off_t getSize() const;
76   inline unsigned getUID() const;
77   inline const llvm::sys::fs::UniqueID &getUniqueID() const;
78   inline time_t getModificationTime() const;
79   inline bool isNamedPipe() const;
80   inline void closeFile() const;
81 
82   /// Check if the underlying FileEntry is the same, intentially ignoring
83   /// whether the file was referenced with the same spelling of the filename.
84   friend bool operator==(const FileEntryRef &LHS, const FileEntryRef &RHS) {
85     return &LHS.getFileEntry() == &RHS.getFileEntry();
86   }
87   friend bool operator==(const FileEntry *LHS, const FileEntryRef &RHS) {
88     return LHS == &RHS.getFileEntry();
89   }
90   friend bool operator==(const FileEntryRef &LHS, const FileEntry *RHS) {
91     return &LHS.getFileEntry() == RHS;
92   }
93   friend bool operator!=(const FileEntryRef &LHS, const FileEntryRef &RHS) {
94     return !(LHS == RHS);
95   }
96   friend bool operator!=(const FileEntry *LHS, const FileEntryRef &RHS) {
97     return !(LHS == RHS);
98   }
99   friend bool operator!=(const FileEntryRef &LHS, const FileEntry *RHS) {
100     return !(LHS == RHS);
101   }
102 
103   /// Hash code is based on the FileEntry, not the specific named reference,
104   /// just like operator==.
hash_value(FileEntryRef Ref)105   friend llvm::hash_code hash_value(FileEntryRef Ref) {
106     return llvm::hash_value(&Ref.getFileEntry());
107   }
108 
109   struct MapValue;
110 
111   /// Type used in the StringMap.
112   using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<MapValue>>;
113 
114   /// Type stored in the StringMap.
115   struct MapValue {
116     /// The pointer at another MapEntry is used when the FileManager should
117     /// silently forward from one name to another, which occurs in Redirecting
118     /// VFSs that use external names. In that case, the \c FileEntryRef
119     /// returned by the \c FileManager will have the external name, and not the
120     /// name that was used to lookup the file.
121     ///
122     /// The second type is really a `const MapEntry *`, but that confuses
123     /// gcc5.3.  Once that's no longer supported, change this back.
124     llvm::PointerUnion<FileEntry *, const void *> V;
125 
126     /// Directory the file was found in. Set if and only if V is a FileEntry.
127     OptionalDirectoryEntryRef Dir;
128 
129     MapValue() = delete;
MapValueMapValue130     MapValue(FileEntry &FE, DirectoryEntryRef Dir) : V(&FE), Dir(Dir) {}
MapValueMapValue131     MapValue(MapEntry &ME) : V(&ME) {}
132   };
133 
134   /// Check if RHS referenced the file in exactly the same way.
isSameRef(const FileEntryRef & RHS)135   bool isSameRef(const FileEntryRef &RHS) const { return ME == RHS.ME; }
136 
137   /// Allow FileEntryRef to degrade into 'const FileEntry*' to facilitate
138   /// incremental adoption.
139   ///
140   /// The goal is to avoid code churn due to dances like the following:
141   /// \code
142   /// // Old code.
143   /// lvalue = rvalue;
144   ///
145   /// // Temporary code from an incremental patch.
146   /// lvalue = &rvalue.getFileEntry();
147   ///
148   /// // Final code.
149   /// lvalue = rvalue;
150   /// \endcode
151   ///
152   /// FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and
153   /// FileEntry::getName have been deleted, delete this implicit conversion.
154   operator const FileEntry *() const { return &getFileEntry(); }
155 
156   FileEntryRef() = delete;
FileEntryRef(const MapEntry & ME)157   explicit FileEntryRef(const MapEntry &ME) : ME(&ME) {
158     assert(ME.second && "Expected payload");
159     assert(ME.second->V && "Expected non-null");
160   }
161 
162   /// Expose the underlying MapEntry to simplify packing in a PointerIntPair or
163   /// PointerUnion and allow construction in Optional.
getMapEntry()164   const clang::FileEntryRef::MapEntry &getMapEntry() const { return *ME; }
165 
166   /// Retrieve the base MapEntry after redirects.
getBaseMapEntry()167   const MapEntry &getBaseMapEntry() const {
168     const MapEntry *ME = this->ME;
169     while (const void *Next = ME->second->V.dyn_cast<const void *>())
170       ME = static_cast<const MapEntry *>(Next);
171     return *ME;
172   }
173 
174 private:
175   friend class FileMgr::MapEntryOptionalStorage<FileEntryRef>;
176   struct optional_none_tag {};
177 
178   // Private constructor for use by OptionalStorage.
FileEntryRef(optional_none_tag)179   FileEntryRef(optional_none_tag) : ME(nullptr) {}
hasOptionalValue()180   bool hasOptionalValue() const { return ME; }
181 
182   friend struct llvm::DenseMapInfo<FileEntryRef>;
183   struct dense_map_empty_tag {};
184   struct dense_map_tombstone_tag {};
185 
186   // Private constructors for use by DenseMapInfo.
187   FileEntryRef(dense_map_empty_tag)
188       : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {}
189   FileEntryRef(dense_map_tombstone_tag)
190       : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {}
191   bool isSpecialDenseMapKey() const {
192     return isSameRef(FileEntryRef(dense_map_empty_tag())) ||
193            isSameRef(FileEntryRef(dense_map_tombstone_tag()));
194   }
195 
196   const MapEntry *ME;
197 };
198 
199 static_assert(sizeof(FileEntryRef) == sizeof(const FileEntry *),
200               "FileEntryRef must avoid size overhead");
201 
202 static_assert(std::is_trivially_copyable<FileEntryRef>::value,
203               "FileEntryRef must be trivially copyable");
204 
205 using OptionalFileEntryRef = CustomizableOptional<FileEntryRef>;
206 
207 namespace optional_detail {
208 
209 /// Customize OptionalStorage<FileEntryRef> to use FileEntryRef and its
210 /// optional_none_tag to keep it the size of a single pointer.
211 template <>
212 class OptionalStorage<clang::FileEntryRef>
213     : public clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef> {
214   using StorageImpl =
215       clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef>;
216 
217 public:
218   OptionalStorage() = default;
219 
220   template <class... ArgTypes>
221   explicit OptionalStorage(std::in_place_t, ArgTypes &&...Args)
222       : StorageImpl(std::in_place_t{}, std::forward<ArgTypes>(Args)...) {}
223 
224   OptionalStorage &operator=(clang::FileEntryRef Ref) {
225     StorageImpl::operator=(Ref);
226     return *this;
227   }
228 };
229 
230 static_assert(sizeof(OptionalFileEntryRef) == sizeof(FileEntryRef),
231               "OptionalFileEntryRef must avoid size overhead");
232 
233 static_assert(std::is_trivially_copyable<OptionalFileEntryRef>::value,
234               "OptionalFileEntryRef should be trivially copyable");
235 
236 } // end namespace optional_detail
237 } // namespace clang
238 
239 namespace llvm {
240 /// Specialisation of DenseMapInfo for FileEntryRef.
241 template <> struct DenseMapInfo<clang::FileEntryRef> {
242   static inline clang::FileEntryRef getEmptyKey() {
243     return clang::FileEntryRef(clang::FileEntryRef::dense_map_empty_tag());
244   }
245 
246   static inline clang::FileEntryRef getTombstoneKey() {
247     return clang::FileEntryRef(clang::FileEntryRef::dense_map_tombstone_tag());
248   }
249 
250   static unsigned getHashValue(clang::FileEntryRef Val) {
251     return hash_value(Val);
252   }
253 
254   static bool isEqual(clang::FileEntryRef LHS, clang::FileEntryRef RHS) {
255     // Catch the easy cases: both empty, both tombstone, or the same ref.
256     if (LHS.isSameRef(RHS))
257       return true;
258 
259     // Confirm LHS and RHS are valid.
260     if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey())
261       return false;
262 
263     // It's safe to use operator==.
264     return LHS == RHS;
265   }
266 };
267 
268 } // end namespace llvm
269 
270 namespace clang {
271 
272 /// Wrapper around OptionalFileEntryRef that degrades to 'const FileEntry*',
273 /// facilitating incremental patches to propagate FileEntryRef.
274 ///
275 /// This class can be used as return value or field where it's convenient for
276 /// an OptionalFileEntryRef to degrade to a 'const FileEntry*'. The purpose
277 /// is to avoid code churn due to dances like the following:
278 /// \code
279 /// // Old code.
280 /// lvalue = rvalue;
281 ///
282 /// // Temporary code from an incremental patch.
283 /// OptionalFileEntryRef MaybeF = rvalue;
284 /// lvalue = MaybeF ? &MaybeF.getFileEntry() : nullptr;
285 ///
286 /// // Final code.
287 /// lvalue = rvalue;
288 /// \endcode
289 ///
290 /// FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and
291 /// FileEntry::getName have been deleted, delete this class and replace
292 /// instances with OptionalFileEntryRef.
293 class OptionalFileEntryRefDegradesToFileEntryPtr : public OptionalFileEntryRef {
294 public:
295   OptionalFileEntryRefDegradesToFileEntryPtr() = default;
296   OptionalFileEntryRefDegradesToFileEntryPtr(
297       OptionalFileEntryRefDegradesToFileEntryPtr &&) = default;
298   OptionalFileEntryRefDegradesToFileEntryPtr(
299       const OptionalFileEntryRefDegradesToFileEntryPtr &) = default;
300   OptionalFileEntryRefDegradesToFileEntryPtr &
301   operator=(OptionalFileEntryRefDegradesToFileEntryPtr &&) = default;
302   OptionalFileEntryRefDegradesToFileEntryPtr &
303   operator=(const OptionalFileEntryRefDegradesToFileEntryPtr &) = default;
304 
305   OptionalFileEntryRefDegradesToFileEntryPtr(std::nullopt_t) {}
306   OptionalFileEntryRefDegradesToFileEntryPtr(FileEntryRef Ref)
307       : OptionalFileEntryRef(Ref) {}
308   OptionalFileEntryRefDegradesToFileEntryPtr(OptionalFileEntryRef MaybeRef)
309       : OptionalFileEntryRef(MaybeRef) {}
310 
311   OptionalFileEntryRefDegradesToFileEntryPtr &operator=(std::nullopt_t) {
312     OptionalFileEntryRef::operator=(std::nullopt);
313     return *this;
314   }
315   OptionalFileEntryRefDegradesToFileEntryPtr &operator=(FileEntryRef Ref) {
316     OptionalFileEntryRef::operator=(Ref);
317     return *this;
318   }
319   OptionalFileEntryRefDegradesToFileEntryPtr &
320   operator=(OptionalFileEntryRef MaybeRef) {
321     OptionalFileEntryRef::operator=(MaybeRef);
322     return *this;
323   }
324 
325   /// Degrade to 'const FileEntry *' to allow  FileEntry::LastRef and
326   /// FileEntry::getName have been deleted, delete this class and replace
327   /// instances with OptionalFileEntryRef
328   operator const FileEntry *() const {
329     return has_value() ? &(*this)->getFileEntry() : nullptr;
330   }
331 };
332 
333 static_assert(
334     std::is_trivially_copyable<
335         OptionalFileEntryRefDegradesToFileEntryPtr>::value,
336     "OptionalFileEntryRefDegradesToFileEntryPtr should be trivially copyable");
337 
338 inline bool operator==(const FileEntry *LHS, const OptionalFileEntryRef &RHS) {
339   return LHS == (RHS ? &RHS->getFileEntry() : nullptr);
340 }
341 inline bool operator==(const OptionalFileEntryRef &LHS, const FileEntry *RHS) {
342   return (LHS ? &LHS->getFileEntry() : nullptr) == RHS;
343 }
344 inline bool operator!=(const FileEntry *LHS, const OptionalFileEntryRef &RHS) {
345   return !(LHS == RHS);
346 }
347 inline bool operator!=(const OptionalFileEntryRef &LHS, const FileEntry *RHS) {
348   return !(LHS == RHS);
349 }
350 
351 /// Cached information about one file (either on disk
352 /// or in the virtual file system).
353 ///
354 /// If the 'File' member is valid, then this FileEntry has an open file
355 /// descriptor for the file.
356 class FileEntry {
357   friend class FileManager;
358   friend class FileEntryTestHelper;
359   FileEntry();
360   FileEntry(const FileEntry &) = delete;
361   FileEntry &operator=(const FileEntry &) = delete;
362 
363   std::string RealPathName;   // Real path to the file; could be empty.
364   off_t Size = 0;             // File size in bytes.
365   time_t ModTime = 0;         // Modification time of file.
366   const DirectoryEntry *Dir = nullptr; // Directory file lives in.
367   llvm::sys::fs::UniqueID UniqueID;
368   unsigned UID = 0; // A unique (small) ID for the file.
369   bool IsNamedPipe = false;
370 
371   /// The open file, if it is owned by the \p FileEntry.
372   mutable std::unique_ptr<llvm::vfs::File> File;
373 
374   /// The file content, if it is owned by the \p FileEntry.
375   std::unique_ptr<llvm::MemoryBuffer> Content;
376 
377   // First access name for this FileEntry.
378   //
379   // This is Optional only to allow delayed construction (FileEntryRef has no
380   // default constructor). It should always have a value in practice.
381   //
382   // TODO: remove this once everyone that needs a name uses FileEntryRef.
383   OptionalFileEntryRef LastRef;
384 
385 public:
386   ~FileEntry();
387   StringRef getName() const { return LastRef->getName(); }
388   FileEntryRef getLastRef() const { return *LastRef; }
389 
390   StringRef tryGetRealPathName() const { return RealPathName; }
391   off_t getSize() const { return Size; }
392   unsigned getUID() const { return UID; }
393   const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; }
394   time_t getModificationTime() const { return ModTime; }
395 
396   /// Return the directory the file lives in.
397   const DirectoryEntry *getDir() const { return Dir; }
398 
399   /// Check whether the file is a named pipe (and thus can't be opened by
400   /// the native FileManager methods).
401   bool isNamedPipe() const { return IsNamedPipe; }
402 
403   void closeFile() const;
404 };
405 
406 off_t FileEntryRef::getSize() const { return getFileEntry().getSize(); }
407 
408 unsigned FileEntryRef::getUID() const { return getFileEntry().getUID(); }
409 
410 const llvm::sys::fs::UniqueID &FileEntryRef::getUniqueID() const {
411   return getFileEntry().getUniqueID();
412 }
413 
414 time_t FileEntryRef::getModificationTime() const {
415   return getFileEntry().getModificationTime();
416 }
417 
418 bool FileEntryRef::isNamedPipe() const { return getFileEntry().isNamedPipe(); }
419 
420 void FileEntryRef::closeFile() const { getFileEntry().closeFile(); }
421 
422 } // end namespace clang
423 
424 #endif // LLVM_CLANG_BASIC_FILEENTRY_H
425