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