Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:49

0001 //===- clang/Basic/FileEntry.h - File references ----------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 ///
0009 /// \file
0010 /// Defines interfaces for clang::FileEntry and clang::FileEntryRef.
0011 ///
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_BASIC_FILEENTRY_H
0015 #define LLVM_CLANG_BASIC_FILEENTRY_H
0016 
0017 #include "clang/Basic/CustomizableOptional.h"
0018 #include "clang/Basic/DirectoryEntry.h"
0019 #include "clang/Basic/LLVM.h"
0020 #include "llvm/ADT/DenseMapInfo.h"
0021 #include "llvm/ADT/Hashing.h"
0022 #include "llvm/ADT/PointerUnion.h"
0023 #include "llvm/ADT/StringMap.h"
0024 #include "llvm/ADT/StringRef.h"
0025 #include "llvm/Support/ErrorOr.h"
0026 #include "llvm/Support/FileSystem/UniqueID.h"
0027 
0028 #include <optional>
0029 #include <utility>
0030 
0031 namespace llvm {
0032 
0033 class MemoryBuffer;
0034 
0035 namespace vfs {
0036 
0037 class File;
0038 
0039 } // namespace vfs
0040 } // namespace llvm
0041 
0042 namespace clang {
0043 
0044 class FileEntryRef;
0045 
0046 namespace optional_detail {
0047 
0048 /// Forward declare a template specialization for OptionalStorage.
0049 template <> class OptionalStorage<clang::FileEntryRef>;
0050 
0051 } // namespace optional_detail
0052 
0053 class FileEntry;
0054 
0055 /// A reference to a \c FileEntry that includes the name of the file as it was
0056 /// accessed by the FileManager's client.
0057 class FileEntryRef {
0058 public:
0059   /// The name of this FileEntry. If a VFS uses 'use-external-name', this is
0060   /// the redirected name. See getRequestedName().
0061   StringRef getName() const { return getBaseMapEntry().first(); }
0062 
0063   /// The name of this FileEntry, as originally requested without applying any
0064   /// remappings for VFS 'use-external-name'.
0065   ///
0066   /// FIXME: this should be the semantics of getName(). See comment in
0067   /// FileManager::getFileRef().
0068   StringRef getNameAsRequested() const { return ME->first(); }
0069 
0070   const FileEntry &getFileEntry() const {
0071     return *cast<FileEntry *>(getBaseMapEntry().second->V);
0072   }
0073 
0074   // This function is used if the buffer size needs to be increased
0075   // due to potential z/OS EBCDIC -> UTF-8 conversion
0076   inline void updateFileEntryBufferSize(unsigned BufferSize);
0077 
0078   DirectoryEntryRef getDir() const { return ME->second->Dir; }
0079 
0080   inline off_t getSize() const;
0081   inline unsigned getUID() const;
0082   inline const llvm::sys::fs::UniqueID &getUniqueID() const;
0083   inline time_t getModificationTime() const;
0084   inline bool isNamedPipe() const;
0085   inline void closeFile() const;
0086 
0087   /// Check if the underlying FileEntry is the same, intentially ignoring
0088   /// whether the file was referenced with the same spelling of the filename.
0089   friend bool operator==(const FileEntryRef &LHS, const FileEntryRef &RHS) {
0090     return &LHS.getFileEntry() == &RHS.getFileEntry();
0091   }
0092   friend bool operator==(const FileEntry *LHS, const FileEntryRef &RHS) {
0093     return LHS == &RHS.getFileEntry();
0094   }
0095   friend bool operator==(const FileEntryRef &LHS, const FileEntry *RHS) {
0096     return &LHS.getFileEntry() == RHS;
0097   }
0098   friend bool operator!=(const FileEntryRef &LHS, const FileEntryRef &RHS) {
0099     return !(LHS == RHS);
0100   }
0101   friend bool operator!=(const FileEntry *LHS, const FileEntryRef &RHS) {
0102     return !(LHS == RHS);
0103   }
0104   friend bool operator!=(const FileEntryRef &LHS, const FileEntry *RHS) {
0105     return !(LHS == RHS);
0106   }
0107 
0108   /// Hash code is based on the FileEntry, not the specific named reference,
0109   /// just like operator==.
0110   friend llvm::hash_code hash_value(FileEntryRef Ref) {
0111     return llvm::hash_value(&Ref.getFileEntry());
0112   }
0113 
0114   struct MapValue;
0115 
0116   /// Type used in the StringMap.
0117   using MapEntry = llvm::StringMapEntry<llvm::ErrorOr<MapValue>>;
0118 
0119   /// Type stored in the StringMap.
0120   struct MapValue {
0121     /// The pointer at another MapEntry is used when the FileManager should
0122     /// silently forward from one name to another, which occurs in Redirecting
0123     /// VFSs that use external names. In that case, the \c FileEntryRef
0124     /// returned by the \c FileManager will have the external name, and not the
0125     /// name that was used to lookup the file.
0126     llvm::PointerUnion<FileEntry *, const MapEntry *> V;
0127 
0128     /// Directory the file was found in.
0129     DirectoryEntryRef Dir;
0130 
0131     MapValue() = delete;
0132     MapValue(FileEntry &FE, DirectoryEntryRef Dir) : V(&FE), Dir(Dir) {}
0133     MapValue(MapEntry &ME, DirectoryEntryRef Dir) : V(&ME), Dir(Dir) {}
0134   };
0135 
0136   /// Check if RHS referenced the file in exactly the same way.
0137   bool isSameRef(const FileEntryRef &RHS) const { return ME == RHS.ME; }
0138 
0139   /// Allow FileEntryRef to degrade into 'const FileEntry*' to facilitate
0140   /// incremental adoption.
0141   ///
0142   /// The goal is to avoid code churn due to dances like the following:
0143   /// \code
0144   /// // Old code.
0145   /// lvalue = rvalue;
0146   ///
0147   /// // Temporary code from an incremental patch.
0148   /// lvalue = &rvalue.getFileEntry();
0149   ///
0150   /// // Final code.
0151   /// lvalue = rvalue;
0152   /// \endcode
0153   ///
0154   /// FIXME: Once FileEntryRef is "everywhere" and FileEntry::LastRef and
0155   /// FileEntry::getName have been deleted, delete this implicit conversion.
0156   operator const FileEntry *() const { return &getFileEntry(); }
0157 
0158   FileEntryRef() = delete;
0159   explicit FileEntryRef(const MapEntry &ME) : ME(&ME) {
0160     assert(ME.second && "Expected payload");
0161     assert(ME.second->V && "Expected non-null");
0162   }
0163 
0164   /// Expose the underlying MapEntry to simplify packing in a PointerIntPair or
0165   /// PointerUnion and allow construction in Optional.
0166   const clang::FileEntryRef::MapEntry &getMapEntry() const { return *ME; }
0167 
0168   /// Retrieve the base MapEntry after redirects.
0169   const MapEntry &getBaseMapEntry() const {
0170     const MapEntry *Base = ME;
0171     while (const auto *Next = Base->second->V.dyn_cast<const MapEntry *>())
0172       Base = Next;
0173     return *Base;
0174   }
0175 
0176 private:
0177   friend class FileMgr::MapEntryOptionalStorage<FileEntryRef>;
0178   struct optional_none_tag {};
0179 
0180   // Private constructor for use by OptionalStorage.
0181   FileEntryRef(optional_none_tag) : ME(nullptr) {}
0182   bool hasOptionalValue() const { return ME; }
0183 
0184   friend struct llvm::DenseMapInfo<FileEntryRef>;
0185   struct dense_map_empty_tag {};
0186   struct dense_map_tombstone_tag {};
0187 
0188   // Private constructors for use by DenseMapInfo.
0189   FileEntryRef(dense_map_empty_tag)
0190       : ME(llvm::DenseMapInfo<const MapEntry *>::getEmptyKey()) {}
0191   FileEntryRef(dense_map_tombstone_tag)
0192       : ME(llvm::DenseMapInfo<const MapEntry *>::getTombstoneKey()) {}
0193   bool isSpecialDenseMapKey() const {
0194     return isSameRef(FileEntryRef(dense_map_empty_tag())) ||
0195            isSameRef(FileEntryRef(dense_map_tombstone_tag()));
0196   }
0197 
0198   const MapEntry *ME;
0199 };
0200 
0201 static_assert(sizeof(FileEntryRef) == sizeof(const FileEntry *),
0202               "FileEntryRef must avoid size overhead");
0203 
0204 static_assert(std::is_trivially_copyable<FileEntryRef>::value,
0205               "FileEntryRef must be trivially copyable");
0206 
0207 using OptionalFileEntryRef = CustomizableOptional<FileEntryRef>;
0208 
0209 namespace optional_detail {
0210 
0211 /// Customize OptionalStorage<FileEntryRef> to use FileEntryRef and its
0212 /// optional_none_tag to keep it the size of a single pointer.
0213 template <>
0214 class OptionalStorage<clang::FileEntryRef>
0215     : public clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef> {
0216   using StorageImpl =
0217       clang::FileMgr::MapEntryOptionalStorage<clang::FileEntryRef>;
0218 
0219 public:
0220   OptionalStorage() = default;
0221 
0222   template <class... ArgTypes>
0223   explicit OptionalStorage(std::in_place_t, ArgTypes &&...Args)
0224       : StorageImpl(std::in_place_t{}, std::forward<ArgTypes>(Args)...) {}
0225 
0226   OptionalStorage &operator=(clang::FileEntryRef Ref) {
0227     StorageImpl::operator=(Ref);
0228     return *this;
0229   }
0230 };
0231 
0232 static_assert(sizeof(OptionalFileEntryRef) == sizeof(FileEntryRef),
0233               "OptionalFileEntryRef must avoid size overhead");
0234 
0235 static_assert(std::is_trivially_copyable<OptionalFileEntryRef>::value,
0236               "OptionalFileEntryRef should be trivially copyable");
0237 
0238 } // end namespace optional_detail
0239 } // namespace clang
0240 
0241 namespace llvm {
0242 
0243 /// Specialisation of DenseMapInfo for FileEntryRef.
0244 template <> struct DenseMapInfo<clang::FileEntryRef> {
0245   static inline clang::FileEntryRef getEmptyKey() {
0246     return clang::FileEntryRef(clang::FileEntryRef::dense_map_empty_tag());
0247   }
0248 
0249   static inline clang::FileEntryRef getTombstoneKey() {
0250     return clang::FileEntryRef(clang::FileEntryRef::dense_map_tombstone_tag());
0251   }
0252 
0253   static unsigned getHashValue(clang::FileEntryRef Val) {
0254     return hash_value(Val);
0255   }
0256 
0257   static bool isEqual(clang::FileEntryRef LHS, clang::FileEntryRef RHS) {
0258     // Catch the easy cases: both empty, both tombstone, or the same ref.
0259     if (LHS.isSameRef(RHS))
0260       return true;
0261 
0262     // Confirm LHS and RHS are valid.
0263     if (LHS.isSpecialDenseMapKey() || RHS.isSpecialDenseMapKey())
0264       return false;
0265 
0266     // It's safe to use operator==.
0267     return LHS == RHS;
0268   }
0269 
0270   /// Support for finding `const FileEntry *` in a `DenseMap<FileEntryRef, T>`.
0271   /// @{
0272   static unsigned getHashValue(const clang::FileEntry *Val) {
0273     return llvm::hash_value(Val);
0274   }
0275   static bool isEqual(const clang::FileEntry *LHS, clang::FileEntryRef RHS) {
0276     if (RHS.isSpecialDenseMapKey())
0277       return false;
0278     return LHS == RHS;
0279   }
0280   /// @}
0281 };
0282 
0283 } // end namespace llvm
0284 
0285 namespace clang {
0286 
0287 inline bool operator==(const FileEntry *LHS, const OptionalFileEntryRef &RHS) {
0288   return LHS == (RHS ? &RHS->getFileEntry() : nullptr);
0289 }
0290 inline bool operator==(const OptionalFileEntryRef &LHS, const FileEntry *RHS) {
0291   return (LHS ? &LHS->getFileEntry() : nullptr) == RHS;
0292 }
0293 inline bool operator!=(const FileEntry *LHS, const OptionalFileEntryRef &RHS) {
0294   return !(LHS == RHS);
0295 }
0296 inline bool operator!=(const OptionalFileEntryRef &LHS, const FileEntry *RHS) {
0297   return !(LHS == RHS);
0298 }
0299 
0300 /// Cached information about one file (either on disk
0301 /// or in the virtual file system).
0302 ///
0303 /// If the 'File' member is valid, then this FileEntry has an open file
0304 /// descriptor for the file.
0305 class FileEntry {
0306   friend class FileManager;
0307   friend class FileEntryTestHelper;
0308   FileEntry();
0309   FileEntry(const FileEntry &) = delete;
0310   FileEntry &operator=(const FileEntry &) = delete;
0311 
0312   std::string RealPathName;   // Real path to the file; could be empty.
0313   off_t Size = 0;             // File size in bytes.
0314   time_t ModTime = 0;         // Modification time of file.
0315   const DirectoryEntry *Dir = nullptr; // Directory file lives in.
0316   llvm::sys::fs::UniqueID UniqueID;
0317   unsigned UID = 0; // A unique (small) ID for the file.
0318   bool IsNamedPipe = false;
0319 
0320   /// The open file, if it is owned by the \p FileEntry.
0321   mutable std::unique_ptr<llvm::vfs::File> File;
0322 
0323   /// The file content, if it is owned by the \p FileEntry.
0324   std::unique_ptr<llvm::MemoryBuffer> Content;
0325 
0326 public:
0327   ~FileEntry();
0328 
0329   StringRef tryGetRealPathName() const { return RealPathName; }
0330   off_t getSize() const { return Size; }
0331   // Size may increase due to potential z/OS EBCDIC -> UTF-8 conversion.
0332   void setSize(off_t NewSize) { Size = NewSize; }
0333   unsigned getUID() const { return UID; }
0334   const llvm::sys::fs::UniqueID &getUniqueID() const { return UniqueID; }
0335   time_t getModificationTime() const { return ModTime; }
0336 
0337   /// Return the directory the file lives in.
0338   const DirectoryEntry *getDir() const { return Dir; }
0339 
0340   /// Check whether the file is a named pipe (and thus can't be opened by
0341   /// the native FileManager methods).
0342   bool isNamedPipe() const { return IsNamedPipe; }
0343 
0344   void closeFile() const;
0345 };
0346 
0347 off_t FileEntryRef::getSize() const { return getFileEntry().getSize(); }
0348 
0349 unsigned FileEntryRef::getUID() const { return getFileEntry().getUID(); }
0350 
0351 const llvm::sys::fs::UniqueID &FileEntryRef::getUniqueID() const {
0352   return getFileEntry().getUniqueID();
0353 }
0354 
0355 time_t FileEntryRef::getModificationTime() const {
0356   return getFileEntry().getModificationTime();
0357 }
0358 
0359 bool FileEntryRef::isNamedPipe() const { return getFileEntry().isNamedPipe(); }
0360 
0361 void FileEntryRef::closeFile() const { getFileEntry().closeFile(); }
0362 
0363 void FileEntryRef::updateFileEntryBufferSize(unsigned BufferSize) {
0364   cast<FileEntry *>(getBaseMapEntry().second->V)->setSize(BufferSize);
0365 }
0366 
0367 } // end namespace clang
0368 
0369 #endif // LLVM_CLANG_BASIC_FILEENTRY_H