summaryrefslogtreecommitdiff
path: root/include/clang/Basic/VirtualFileSystem.h
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2014-11-24 09:15:30 +0000
committerDimitry Andric <dim@FreeBSD.org>2014-11-24 09:15:30 +0000
commit9f4dbff6669c8037f3b036bcf580d14f1a4f12a5 (patch)
tree47df2c12b57214af6c31e47404b005675b8b7ffc /include/clang/Basic/VirtualFileSystem.h
parentf73d5f23a889b93d89ddef61ac0995df40286bb8 (diff)
Notes
Diffstat (limited to 'include/clang/Basic/VirtualFileSystem.h')
-rw-r--r--include/clang/Basic/VirtualFileSystem.h283
1 files changed, 283 insertions, 0 deletions
diff --git a/include/clang/Basic/VirtualFileSystem.h b/include/clang/Basic/VirtualFileSystem.h
new file mode 100644
index 000000000000..36f78fd8725f
--- /dev/null
+++ b/include/clang/Basic/VirtualFileSystem.h
@@ -0,0 +1,283 @@
+//===- 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/ADT/Optional.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/SourceMgr.h"
+
+namespace llvm {
+class MemoryBuffer;
+}
+
+namespace clang {
+namespace vfs {
+
+/// \brief The result of a \p status operation.
+class Status {
+ std::string Name;
+ 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:
+ bool IsVFSMapped; // FIXME: remove when files support multiple names
+
+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 that should be used for this file or directory.
+ StringRef getName() const { return Name; }
+ void setName(StringRef N) { Name = 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 std::error_code getBuffer(const Twine &Name,
+ std::unique_ptr<llvm::MemoryBuffer> &Result,
+ int64_t FileSize = -1,
+ bool RequiresNullTerminator = true,
+ bool IsVolatile = false) = 0;
+ /// \brief Closes the file.
+ virtual std::error_code close() = 0;
+ /// \brief Sets the name to use for this file.
+ virtual void setName(StringRef Name) = 0;
+};
+
+namespace detail {
+/// \brief An interface for virtual file systems to provide an iterator over the
+/// (non-recursive) contents of a directory.
+struct DirIterImpl {
+ virtual ~DirIterImpl();
+ /// \brief Sets \c CurrentEntry to the next entry in the directory on success,
+ /// or returns a system-defined \c error_code.
+ virtual std::error_code increment() = 0;
+ Status CurrentEntry;
+};
+} // end namespace detail
+
+/// \brief An input iterator over the entries in a virtual path, similar to
+/// llvm::sys::fs::directory_iterator.
+class directory_iterator {
+ std::shared_ptr<detail::DirIterImpl> Impl; // Input iterator semantics on copy
+
+public:
+ directory_iterator(std::shared_ptr<detail::DirIterImpl> I) : Impl(I) {
+ assert(Impl.get() != nullptr && "requires non-null implementation");
+ if (!Impl->CurrentEntry.isStatusKnown())
+ Impl.reset(); // Normalize the end iterator to Impl == nullptr.
+ }
+
+ /// \brief Construct an 'end' iterator.
+ directory_iterator() { }
+
+ /// \brief Equivalent to operator++, with an error code.
+ directory_iterator &increment(std::error_code &EC) {
+ assert(Impl && "attempting to increment past end");
+ EC = Impl->increment();
+ if (EC || !Impl->CurrentEntry.isStatusKnown())
+ Impl.reset(); // Normalize the end iterator to Impl == nullptr.
+ return *this;
+ }
+
+ const Status &operator*() const { return Impl->CurrentEntry; }
+ const Status *operator->() const { return &Impl->CurrentEntry; }
+
+ bool operator==(const directory_iterator &RHS) const {
+ if (Impl && RHS.Impl)
+ return Impl->CurrentEntry.equivalent(RHS.Impl->CurrentEntry);
+ return !Impl && !RHS.Impl;
+ }
+ bool operator!=(const directory_iterator &RHS) const {
+ return !(*this == RHS);
+ }
+};
+
+class FileSystem;
+
+/// \brief An input iterator over the recursive contents of a virtual path,
+/// similar to llvm::sys::fs::recursive_directory_iterator.
+class recursive_directory_iterator {
+ typedef std::stack<directory_iterator, std::vector<directory_iterator>>
+ IterState;
+
+ FileSystem *FS;
+ std::shared_ptr<IterState> State; // Input iterator semantics on copy.
+
+public:
+ recursive_directory_iterator(FileSystem &FS, const Twine &Path,
+ std::error_code &EC);
+ /// \brief Construct an 'end' iterator.
+ recursive_directory_iterator() { }
+
+ /// \brief Equivalent to operator++, with an error code.
+ recursive_directory_iterator &increment(std::error_code &EC);
+
+ const Status &operator*() const { return *State->top(); }
+ const Status *operator->() const { return &*State->top(); }
+
+ bool operator==(const recursive_directory_iterator &Other) const {
+ return State == Other.State; // identity
+ }
+ bool operator!=(const recursive_directory_iterator &RHS) const {
+ return !(*this == RHS);
+ }
+};
+
+/// \brief The virtual file system interface.
+class FileSystem : public llvm::ThreadSafeRefCountedBase<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 std::error_code openFileForRead(const Twine &Path,
+ std::unique_ptr<File> &Result) = 0;
+
+ /// This is a convenience method that opens a file, gets its content and then
+ /// closes the file.
+ std::error_code getBufferForFile(const Twine &Name,
+ std::unique_ptr<llvm::MemoryBuffer> &Result,
+ int64_t FileSize = -1,
+ bool RequiresNullTerminator = true,
+ bool IsVolatile = false);
+
+ /// \brief Get a directory_iterator for \p Dir.
+ /// \note The 'end' iterator is directory_iterator().
+ virtual directory_iterator dir_begin(const Twine &Dir,
+ std::error_code &EC) = 0;
+};
+
+/// \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 FileSystem 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;
+ /// \brief The stack of file systems, implemented as a list in order of
+ /// their addition.
+ FileSystemList FSList;
+
+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) override;
+ std::error_code openFileForRead(const Twine &Path,
+ std::unique_ptr<File> &Result) override;
+ directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
+
+ typedef FileSystemList::reverse_iterator iterator;
+
+ /// \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(); }
+};
+
+/// \brief Get a globally unique ID for a virtual file or directory.
+llvm::sys::fs::UniqueID getNextVirtualUniqueID();
+
+/// \brief Gets a \p FileSystem for a virtual file system described in YAML
+/// format.
+///
+/// Takes ownership of \p Buffer.
+IntrusiveRefCntPtr<FileSystem>
+getVFSFromYAML(llvm::MemoryBuffer *Buffer,
+ llvm::SourceMgr::DiagHandlerTy DiagHandler,
+ void *DiagContext = nullptr,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem());
+
+struct YAMLVFSEntry {
+ template <typename T1, typename T2> YAMLVFSEntry(T1 &&VPath, T2 &&RPath)
+ : VPath(std::forward<T1>(VPath)), RPath(std::forward<T2>(RPath)) {}
+ std::string VPath;
+ std::string RPath;
+};
+
+class YAMLVFSWriter {
+ std::vector<YAMLVFSEntry> Mappings;
+ Optional<bool> IsCaseSensitive;
+
+public:
+ YAMLVFSWriter() {}
+ void addFileMapping(StringRef VirtualPath, StringRef RealPath);
+ void setCaseSensitivity(bool CaseSensitive) {
+ IsCaseSensitive = CaseSensitive;
+ }
+ void write(llvm::raw_ostream &OS);
+};
+
+} // end namespace vfs
+} // end namespace clang
+#endif // LLVM_CLANG_BASIC_VIRTUAL_FILE_SYSTEM_H