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