diff options
Diffstat (limited to 'include/clang/Basic/FileManager.h')
-rw-r--r-- | include/clang/Basic/FileManager.h | 204 |
1 files changed, 174 insertions, 30 deletions
diff --git a/include/clang/Basic/FileManager.h b/include/clang/Basic/FileManager.h index 96983475f454..28cd05818087 100644 --- a/include/clang/Basic/FileManager.h +++ b/include/clang/Basic/FileManager.h @@ -45,12 +45,31 @@ class FileSystemStatCache; class DirectoryEntry { friend class FileManager; + // FIXME: We should not be storing a directory entry name here. StringRef Name; // Name of the directory. public: StringRef getName() const { return Name; } }; +/// A reference to a \c DirectoryEntry that includes the name of the directory +/// as it was accessed by the FileManager's client. +class DirectoryEntryRef { +public: + const DirectoryEntry &getDirEntry() const { return *Entry->getValue(); } + + StringRef getName() const { return Entry->getKey(); } + +private: + friend class FileManager; + + DirectoryEntryRef( + llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>> *Entry) + : Entry(Entry) {} + + const llvm::StringMapEntry<llvm::ErrorOr<DirectoryEntry &>> *Entry; +}; + /// Cached information about one file (either on disk /// or in the virtual file system). /// @@ -64,8 +83,8 @@ class FileEntry { off_t Size; // File size in bytes. time_t ModTime; // Modification time of file. const DirectoryEntry *Dir; // Directory file lives in. - unsigned UID; // A unique (small) ID for the file. llvm::sys::fs::UniqueID UniqueID; + unsigned UID; // A unique (small) ID for the file. bool IsNamedPipe; bool IsValid; // Is this \c FileEntry initialized and valid? @@ -106,6 +125,42 @@ public: bool isOpenForTests() const { return File != nullptr; } }; +/// A reference to a \c FileEntry that includes the name of the file as it was +/// accessed by the FileManager's client. +class FileEntryRef { +public: + FileEntryRef() = delete; + FileEntryRef(StringRef Name, const FileEntry &Entry) + : Name(Name), Entry(&Entry) {} + + const StringRef getName() const { return Name; } + + bool isValid() const { return Entry->isValid(); } + + const FileEntry &getFileEntry() const { return *Entry; } + + off_t getSize() const { return Entry->getSize(); } + + unsigned getUID() const { return Entry->getUID(); } + + const llvm::sys::fs::UniqueID &getUniqueID() const { + return Entry->getUniqueID(); + } + + time_t getModificationTime() const { return Entry->getModificationTime(); } + + friend bool operator==(const FileEntryRef &LHS, const FileEntryRef &RHS) { + return LHS.Entry == RHS.Entry && LHS.Name == RHS.Name; + } + friend bool operator!=(const FileEntryRef &LHS, const FileEntryRef &RHS) { + return !(LHS == RHS); + } + +private: + StringRef Name; + const FileEntry *Entry; +}; + /// Implements support for file system lookup, file system caching, /// and directory search management. /// @@ -131,21 +186,41 @@ class FileManager : public RefCountedBase<FileManager> { /// The virtual files that we have allocated. SmallVector<std::unique_ptr<FileEntry>, 4> VirtualFileEntries; + /// A set of files that bypass the maps and uniquing. They can have + /// conflicting filenames. + SmallVector<std::unique_ptr<FileEntry>, 0> BypassFileEntries; + /// A cache that maps paths to directory entries (either real or - /// virtual) we have looked up + /// virtual) we have looked up, or an error that occurred when we looked up + /// the directory. /// /// The actual Entries for real directories/files are /// owned by UniqueRealDirs/UniqueRealFiles above, while the Entries /// for virtual directories/files are owned by /// VirtualDirectoryEntries/VirtualFileEntries above. /// - llvm::StringMap<DirectoryEntry*, llvm::BumpPtrAllocator> SeenDirEntries; + llvm::StringMap<llvm::ErrorOr<DirectoryEntry &>, llvm::BumpPtrAllocator> + SeenDirEntries; + + /// A reference to the file entry that is associated with a particular + /// filename, or a reference to another filename that should be looked up + /// instead of the accessed filename. + /// + /// The reference to another filename is specifically useful for Redirecting + /// VFSs that use external names. In that case, the \c FileEntryRef returned + /// by the \c FileManager will have the external name, and not the name that + /// was used to lookup the file. + using SeenFileEntryOrRedirect = + llvm::PointerUnion<FileEntry *, const StringRef *>; /// A cache that maps paths to file entries (either real or - /// virtual) we have looked up. + /// virtual) we have looked up, or an error that occurred when we looked up + /// the file. /// /// \see SeenDirEntries - llvm::StringMap<FileEntry*, llvm::BumpPtrAllocator> SeenFileEntries; + llvm::StringMap<llvm::ErrorOr<SeenFileEntryOrRedirect>, + llvm::BumpPtrAllocator> + SeenFileEntries; /// The canonical names of directories. llvm::DenseMap<const DirectoryEntry *, llvm::StringRef> CanonicalDirNames; @@ -157,15 +232,12 @@ class FileManager : public RefCountedBase<FileManager> { /// unsigned NextFileUID; - // Statistics. - unsigned NumDirLookups, NumFileLookups; - unsigned NumDirCacheMisses, NumFileCacheMisses; - // Caching. std::unique_ptr<FileSystemStatCache> StatCache; - bool getStatValue(StringRef Path, llvm::vfs::Status &Status, bool isFile, - std::unique_ptr<llvm::vfs::File> *F); + std::error_code getStatValue(StringRef Path, llvm::vfs::Status &Status, + bool isFile, + std::unique_ptr<llvm::vfs::File> *F); /// Add all ancestors of the given path (pointing to either a file /// or a directory) as virtual directories. @@ -195,27 +267,86 @@ public: /// Removes the FileSystemStatCache object from the manager. void clearStatCache(); + /// Returns the number of unique real file entries cached by the file manager. + size_t getNumUniqueRealFiles() const { return UniqueRealFiles.size(); } + /// Lookup, cache, and verify the specified directory (real or /// virtual). /// - /// This returns NULL if the directory doesn't exist. + /// This returns a \c std::error_code if there was an error reading the + /// directory. On success, returns the reference to the directory entry + /// together with the exact path that was used to access a file by a + /// particular call to getDirectoryRef. /// /// \param CacheFailure If true and the file does not exist, we'll cache /// the failure to find this file. - const DirectoryEntry *getDirectory(StringRef DirName, - bool CacheFailure = true); + llvm::Expected<DirectoryEntryRef> getDirectoryRef(StringRef DirName, + bool CacheFailure = true); + + /// Get a \c DirectoryEntryRef if it exists, without doing anything on error. + llvm::Optional<DirectoryEntryRef> + getOptionalDirectoryRef(StringRef DirName, bool CacheFailure = true) { + return llvm::expectedToOptional(getDirectoryRef(DirName, CacheFailure)); + } + + /// Lookup, cache, and verify the specified directory (real or + /// virtual). + /// + /// This function is deprecated and will be removed at some point in the + /// future, new clients should use + /// \c getDirectoryRef. + /// + /// This returns a \c std::error_code if there was an error reading the + /// directory. If there is no error, the DirectoryEntry is guaranteed to be + /// non-NULL. + /// + /// \param CacheFailure If true and the file does not exist, we'll cache + /// the failure to find this file. + llvm::ErrorOr<const DirectoryEntry *> + getDirectory(StringRef DirName, bool CacheFailure = true); /// Lookup, cache, and verify the specified file (real or /// virtual). /// - /// This returns NULL if the file doesn't exist. + /// This function is deprecated and will be removed at some point in the + /// future, new clients should use + /// \c getFileRef. + /// + /// This returns a \c std::error_code if there was an error loading the file. + /// If there is no error, the FileEntry is guaranteed to be non-NULL. /// /// \param OpenFile if true and the file exists, it will be opened. /// /// \param CacheFailure If true and the file does not exist, we'll cache /// the failure to find this file. - const FileEntry *getFile(StringRef Filename, bool OpenFile = false, - bool CacheFailure = true); + llvm::ErrorOr<const FileEntry *> + getFile(StringRef Filename, bool OpenFile = false, bool CacheFailure = true); + + /// Lookup, cache, and verify the specified file (real or virtual). Return the + /// reference to the file entry together with the exact path that was used to + /// access a file by a particular call to getFileRef. If the underlying VFS is + /// a redirecting VFS that uses external file names, the returned FileEntryRef + /// will use the external name instead of the filename that was passed to this + /// method. + /// + /// This returns a \c std::error_code if there was an error loading the file, + /// or a \c FileEntryRef otherwise. + /// + /// \param OpenFile if true and the file exists, it will be opened. + /// + /// \param CacheFailure If true and the file does not exist, we'll cache + /// the failure to find this file. + llvm::Expected<FileEntryRef> getFileRef(StringRef Filename, + bool OpenFile = false, + bool CacheFailure = true); + + /// Get a FileEntryRef if it exists, without doing anything on error. + llvm::Optional<FileEntryRef> getOptionalFileRef(StringRef Filename, + bool OpenFile = false, + bool CacheFailure = true) { + return llvm::expectedToOptional( + getFileRef(Filename, OpenFile, CacheFailure)); + } /// Returns the current file system options FileSystemOptions &getFileSystemOpts() { return FileSystemOpts; } @@ -223,6 +354,10 @@ public: llvm::vfs::FileSystem &getVirtualFileSystem() const { return *FS; } + void setVirtualFileSystem(IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) { + this->FS = std::move(FS); + } + /// Retrieve a file entry for a "virtual" file that acts as /// if there were a file with the given name on disk. /// @@ -230,24 +365,38 @@ public: const FileEntry *getVirtualFile(StringRef Filename, off_t Size, time_t ModificationTime); + /// Retrieve a FileEntry that bypasses VFE, which is expected to be a virtual + /// file entry, to access the real file. The returned FileEntry will have + /// the same filename as FE but a different identity and its own stat. + /// + /// This should be used only for rare error recovery paths because it + /// bypasses all mapping and uniquing, blindly creating a new FileEntry. + /// There is no attempt to deduplicate these; if you bypass the same file + /// twice, you get two new file entries. + llvm::Optional<FileEntryRef> getBypassFile(FileEntryRef VFE); + /// Open the specified file as a MemoryBuffer, returning a new /// MemoryBuffer if successful, otherwise returning null. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> - getBufferForFile(const FileEntry *Entry, bool isVolatile = false, - bool ShouldCloseOpenFile = true); + getBufferForFile(const FileEntry *Entry, bool isVolatile = false); + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBufferForFile(StringRef Filename, bool isVolatile = false) { + return getBufferForFileImpl(Filename, /*FileSize=*/-1, isVolatile); + } + +private: llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> - getBufferForFile(StringRef Filename, bool isVolatile = false); + getBufferForFileImpl(StringRef Filename, int64_t FileSize, bool isVolatile); +public: /// Get the 'stat' information for the given \p Path. /// /// If the path is relative, it will be resolved against the WorkingDir of the /// FileManager's FileSystemOptions. /// - /// \returns false on success, true on error. - bool getNoncachedStatValue(StringRef Path, llvm::vfs::Status &Result); - - /// Remove the real file \p Entry from the cache. - void invalidateCache(const FileEntry *Entry); + /// \returns a \c std::error_code describing an error, if there was one + std::error_code getNoncachedStatValue(StringRef Path, + llvm::vfs::Status &Result); /// If path is not absolute and FileSystemOptions set the working /// directory, the path is modified to be relative to the given @@ -265,11 +414,6 @@ public: void GetUniqueIDMapping( SmallVectorImpl<const FileEntry *> &UIDToFiles) const; - /// Modifies the size and modification time of a previously created - /// FileEntry. Use with caution. - static void modifyFileEntry(FileEntry *File, off_t Size, - time_t ModificationTime); - /// Retrieve the canonical name for a given directory. /// /// This is a very expensive operation, despite its results being cached, |