diff options
Diffstat (limited to 'clang/include/clang')
-rw-r--r-- | clang/include/clang/Basic/FileManager.h | 38 | ||||
-rw-r--r-- | clang/include/clang/Basic/FileSystemStatCache.h | 23 | ||||
-rw-r--r-- | clang/include/clang/Basic/VirtualFileSystem.h | 162 | ||||
-rw-r--r-- | clang/include/clang/Frontend/CompilerInstance.h | 25 |
4 files changed, 223 insertions, 25 deletions
diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h index 5f224818556..6e345b20b39 100644 --- a/clang/include/clang/Basic/FileManager.h +++ b/clang/include/clang/Basic/FileManager.h @@ -17,6 +17,7 @@ #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/VirtualFileSystem.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/ADT/OwningPtr.h" @@ -24,7 +25,6 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/FileSystem.h" // FIXME: Enhance libsystem to support inode and other fields in stat. #include <sys/types.h> @@ -55,7 +55,7 @@ public: /// \brief Cached information about one file (either on disk /// or in the virtual file system). /// -/// If the 'FD' member is valid, then this FileEntry has an open file +/// If the 'File' member is valid, then this FileEntry has an open file /// descriptor for the file. class FileEntry { const char *Name; // Name of the file. @@ -67,31 +67,33 @@ class FileEntry { bool IsNamedPipe; bool InPCH; - /// FD - The file descriptor for the file entry if it is opened and owned - /// by the FileEntry. If not, this is set to -1. - mutable int FD; + /// \brief The open file, if it is owned by the \p FileEntry. + mutable OwningPtr<vfs::File> File; friend class FileManager; + void closeFile() const { + File.reset(0); // rely on destructor to close File + } + public: FileEntry(llvm::sys::fs::UniqueID UniqueID, bool IsNamedPipe, bool InPCH) - : Name(0), UniqueID(UniqueID), IsNamedPipe(IsNamedPipe), InPCH(InPCH), - FD(-1) {} + : Name(0), UniqueID(UniqueID), IsNamedPipe(IsNamedPipe), InPCH(InPCH) + {} // Add a default constructor for use with llvm::StringMap FileEntry() - : Name(0), UniqueID(0, 0), IsNamedPipe(false), InPCH(false), FD(-1) {} + : Name(0), UniqueID(0, 0), IsNamedPipe(false), InPCH(false) + {} FileEntry(const FileEntry &FE) { memcpy(this, &FE, sizeof(FE)); - assert(FD == -1 && "Cannot copy a file-owning FileEntry"); + assert(!File && "Cannot copy a file-owning FileEntry"); } void operator=(const FileEntry &FE) { memcpy(this, &FE, sizeof(FE)); - assert(FD == -1 && "Cannot assign a file-owning FileEntry"); + assert(!File && "Cannot assign a file-owning FileEntry"); } - ~FileEntry(); - const char *getName() const { return Name; } off_t getSize() const { return Size; } unsigned getUID() const { return UID; } @@ -119,6 +121,7 @@ struct FileData; /// as a single file. /// class FileManager : public RefCountedBase<FileManager> { + IntrusiveRefCntPtr<vfs::FileSystem> FS; FileSystemOptions FileSystemOpts; class UniqueDirContainer; @@ -172,14 +175,15 @@ class FileManager : public RefCountedBase<FileManager> { OwningPtr<FileSystemStatCache> StatCache; bool getStatValue(const char *Path, FileData &Data, bool isFile, - int *FileDescriptor); + vfs::File **F); /// Add all ancestors of the given path (pointing to either a file /// or a directory) as virtual directories. void addAncestorsAsVirtualDirs(StringRef Path); public: - FileManager(const FileSystemOptions &FileSystemOpts); + FileManager(const FileSystemOptions &FileSystemOpts, + IntrusiveRefCntPtr<vfs::FileSystem> FS = 0); ~FileManager(); /// \brief Installs the provided FileSystemStatCache object within @@ -226,6 +230,10 @@ public: /// \brief Returns the current file system options const FileSystemOptions &getFileSystemOptions() { return FileSystemOpts; } + IntrusiveRefCntPtr<vfs::FileSystem> getVirtualFileSystem() const { + return FS; + } + /// \brief Retrieve a file entry for a "virtual" file that acts as /// if there were a file with the given name on disk. /// @@ -248,7 +256,7 @@ public: /// /// \returns false on success, true on error. bool getNoncachedStatValue(StringRef Path, - llvm::sys::fs::file_status &Result); + vfs::Status &Result); /// \brief Remove the real file \p Entry from the cache. void invalidateCache(const FileEntry *Entry); diff --git a/clang/include/clang/Basic/FileSystemStatCache.h b/clang/include/clang/Basic/FileSystemStatCache.h index 23d82569437..913e41e4ca8 100644 --- a/clang/include/clang/Basic/FileSystemStatCache.h +++ b/clang/include/clang/Basic/FileSystemStatCache.h @@ -24,6 +24,11 @@ namespace clang { +namespace vfs { +class File; +class FileSystem; +} + struct FileData { uint64_t Size; time_t ModTime; @@ -57,10 +62,11 @@ public: /// If isFile is true, then this lookup should only return success for files /// (not directories). If it is false this lookup should only return /// success for directories (not files). On a successful file lookup, the - /// implementation can optionally fill in FileDescriptor with a valid - /// descriptor and the client guarantees that it will close it. + /// implementation can optionally fill in \p F with a valid \p File object and + /// the client guarantees that it will close it. static bool get(const char *Path, FileData &Data, bool isFile, - int *FileDescriptor, FileSystemStatCache *Cache); + vfs::File **F, FileSystemStatCache *Cache, + vfs::FileSystem &FS); /// \brief Sets the next stat call cache in the chain of stat caches. /// Takes ownership of the given stat cache. @@ -78,17 +84,16 @@ public: protected: virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile, - int *FileDescriptor) = 0; + vfs::File **F, vfs::FileSystem &FS) = 0; LookupResult statChained(const char *Path, FileData &Data, bool isFile, - int *FileDescriptor) { + vfs::File **F, vfs::FileSystem &FS) { if (FileSystemStatCache *Next = getNextStatCache()) - return Next->getStat(Path, Data, isFile, FileDescriptor); + return Next->getStat(Path, Data, isFile, F, FS); // If we hit the end of the list of stat caches to try, just compute and // return it without a cache. - return get(Path, Data, isFile, FileDescriptor, 0) ? CacheMissing - : CacheExists; + return get(Path, Data, isFile, F, 0, FS) ? CacheMissing : CacheExists; } }; @@ -107,7 +112,7 @@ public: iterator end() const { return StatCalls.end(); } virtual LookupResult getStat(const char *Path, FileData &Data, bool isFile, - int *FileDescriptor); + vfs::File **F, vfs::FileSystem &FS); }; } // end namespace clang diff --git a/clang/include/clang/Basic/VirtualFileSystem.h b/clang/include/clang/Basic/VirtualFileSystem.h new file mode 100644 index 00000000000..694c6ddec89 --- /dev/null +++ b/clang/include/clang/Basic/VirtualFileSystem.h @@ -0,0 +1,162 @@ +//===- VirtualFileSystem.h - Virtual File System Layer ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// \brief Defines the virtual file system interface vfs::FileSystem. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H +#define LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H + +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/ErrorOr.h" + +namespace llvm { +class MemoryBuffer; +} + +namespace clang { +namespace vfs { + +/// \brief The result of a \p status operation. +class Status { + std::string Name; + std::string ExternalName; + llvm::sys::fs::UniqueID UID; + llvm::sys::TimeValue MTime; + uint32_t User; + uint32_t Group; + uint64_t Size; + llvm::sys::fs::file_type Type; + llvm::sys::fs::perms Perms; + +public: + Status() : Type(llvm::sys::fs::file_type::status_error) {} + Status(const llvm::sys::fs::file_status &Status); + Status(StringRef Name, StringRef RealName, llvm::sys::fs::UniqueID UID, + llvm::sys::TimeValue MTime, uint32_t User, uint32_t Group, + uint64_t Size, llvm::sys::fs::file_type Type, + llvm::sys::fs::perms Perms); + + /// \brief Returns the name this status was looked up by. + StringRef getName() const { return Name; } + + /// \brief Returns the name to use outside the compiler. + /// + /// For example, in diagnostics or debug info we should use this name. + StringRef getExternalName() const { return ExternalName; } + + void setName(StringRef N) { Name = N; } + void setExternalName(StringRef N) { ExternalName = N; } + + /// @name Status interface from llvm::sys::fs + /// @{ + llvm::sys::fs::file_type getType() const { return Type; } + llvm::sys::fs::perms getPermissions() const { return Perms; } + llvm::sys::TimeValue getLastModificationTime() const { return MTime; } + llvm::sys::fs::UniqueID getUniqueID() const { return UID; } + uint32_t getUser() const { return User; } + uint32_t getGroup() const { return Group; } + uint64_t getSize() const { return Size; } + void setType(llvm::sys::fs::file_type v) { Type = v; } + void setPermissions(llvm::sys::fs::perms p) { Perms = p; } + /// @} + /// @name Status queries + /// These are static queries in llvm::sys::fs. + /// @{ + bool equivalent(const Status &Other) const; + bool isDirectory() const; + bool isRegularFile() const; + bool isOther() const; + bool isSymlink() const; + bool isStatusKnown() const; + bool exists() const; + /// @} +}; + +/// \brief Represents an open file. +class File { +public: + /// \brief Destroy the file after closing it (if open). + /// Sub-classes should generally call close() inside their destructors. We + /// cannot do that from the base class, since close is virtual. + virtual ~File(); + /// \brief Get the status of the file. + virtual llvm::ErrorOr<Status> status() = 0; + /// \brief Get the contents of the file as a \p MemoryBuffer. + virtual llvm::error_code getBuffer(const Twine &Name, + OwningPtr<llvm::MemoryBuffer> &Result, + int64_t FileSize = -1, + bool RequiresNullTerminator = true) = 0; + /// \brief Closes the file. + virtual llvm::error_code close() = 0; +}; + +/// \brief The virtual file system interface. +class FileSystem : public RefCountedBase<FileSystem> { +public: + virtual ~FileSystem(); + + /// \brief Get the status of the entry at \p Path, if one exists. + virtual llvm::ErrorOr<Status> status(const Twine &Path) = 0; + /// \brief Get a \p File object for the file at \p Path, if one exists. + virtual llvm::error_code openFileForRead(const Twine &Path, + OwningPtr<File> &Result) = 0; + + /// This is a convenience method that opens a file, gets its content and then + /// closes the file. + llvm::error_code getBufferForFile(const Twine &Name, + OwningPtr<llvm::MemoryBuffer> &Result, + int64_t FileSize = -1, + bool RequiresNullTerminator = true); +}; + +/// \brief Gets an \p vfs::FileSystem for the 'real' file system, as seen by +/// the operating system. +IntrusiveRefCntPtr<FileSystem> getRealFileSystem(); + +/// \brief A file system that allows overlaying one \p AbstractFileSystem on top +/// of another. +/// +/// Consists of a stack of >=1 \p FileSytem objects, which are treated as being +/// one merged file system. When there is a directory that exists in more than +/// one file system, the \p OverlayFileSystem contains a directory containing +/// the union of their contents. The attributes (permissions, etc.) of the +/// top-most (most recently added) directory are used. When there is a file +/// that exists in more than one file system, the file in the top-most file +/// system overrides the other(s). +class OverlayFileSystem : public FileSystem { + typedef SmallVector<IntrusiveRefCntPtr<FileSystem>, 1> FileSystemList; + typedef FileSystemList::reverse_iterator iterator; + + /// \brief The stack of file systems, implemented as a list in order of + /// their addition. + FileSystemList FSList; + + /// \brief Get an iterator pointing to the most recently added file system. + iterator overlays_begin() { return FSList.rbegin(); } + + /// \brief Get an iterator pointing one-past the least recently added file + /// system. + iterator overlays_end() { return FSList.rend(); } + +public: + OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> Base); + /// \brief Pushes a file system on top of the stack. + void pushOverlay(IntrusiveRefCntPtr<FileSystem> FS); + + llvm::ErrorOr<Status> status(const Twine &Path) LLVM_OVERRIDE; + llvm::error_code openFileForRead(const Twine &Path, + OwningPtr<File> &Result) LLVM_OVERRIDE; +}; + +} // end namespace vfs +} // end namespace clang +#endif // LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index fa20ae48e4f..be1e1eaf3b2 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -75,6 +75,9 @@ class CompilerInstance : public ModuleLoader { /// The target being compiled for. IntrusiveRefCntPtr<TargetInfo> Target; + /// The virtual file system. + IntrusiveRefCntPtr<vfs::FileSystem> VirtualFileSystem; + /// The file manager. IntrusiveRefCntPtr<FileManager> FileMgr; @@ -314,6 +317,26 @@ public: void setTarget(TargetInfo *Value); /// } + /// @name Virtual File System + /// { + + bool hasVirtualFileSystem() const { return VirtualFileSystem != 0; } + + vfs::FileSystem &getVirtualFileSystem() const { + assert(hasVirtualFileSystem() && + "Compiler instance has no virtual file system"); + return *VirtualFileSystem; + } + + /// \brief Replace the current virtual file system. + /// + /// \note Most clients should use setFileManager, which will implicitly reset + /// the virtual file system to the one contained in the file manager. + void setVirtualFileSystem(IntrusiveRefCntPtr<vfs::FileSystem> FS) { + VirtualFileSystem = FS; + } + + /// } /// @name File Manager /// { @@ -330,7 +353,7 @@ public: FileMgr.resetWithoutRelease(); } - /// setFileManager - Replace the current file manager. + /// \brief Replace the current file manager and virtual file system. void setFileManager(FileManager *Value); /// } |