summaryrefslogtreecommitdiffstats
path: root/clang/include/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang/include/clang')
-rw-r--r--clang/include/clang/Basic/FileManager.h38
-rw-r--r--clang/include/clang/Basic/FileSystemStatCache.h23
-rw-r--r--clang/include/clang/Basic/VirtualFileSystem.h162
-rw-r--r--clang/include/clang/Frontend/CompilerInstance.h25
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);
/// }
OpenPOWER on IntegriCloud