diff options
Diffstat (limited to 'lib/Basic/VirtualFileSystem.cpp')
-rw-r--r-- | lib/Basic/VirtualFileSystem.cpp | 363 |
1 files changed, 242 insertions, 121 deletions
diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp index 9d44597dc3fb..bcfcbdbb9014 100644 --- a/lib/Basic/VirtualFileSystem.cpp +++ b/lib/Basic/VirtualFileSystem.cpp @@ -1,4 +1,4 @@ -//===- VirtualFileSystem.cpp - Virtual File System Layer --------*- C++ -*-===// +//===- VirtualFileSystem.cpp - Virtual File System Layer ------------------===// // // The LLVM Compiler Infrastructure // @@ -6,30 +6,57 @@ // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// +// // This file implements the VirtualFileSystem interface. +// //===----------------------------------------------------------------------===// #include "clang/Basic/VirtualFileSystem.h" -#include "clang/Basic/FileManager.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Config/llvm-config.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Chrono.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLParser.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> #include <atomic> +#include <cassert> +#include <cstdint> +#include <iterator> +#include <limits> +#include <map> #include <memory> +#include <string> +#include <system_error> #include <utility> +#include <vector> using namespace clang; -using namespace clang::vfs; +using namespace vfs; using namespace llvm; + using llvm::sys::fs::file_status; using llvm::sys::fs::file_type; using llvm::sys::fs::perms; @@ -38,13 +65,13 @@ using llvm::sys::fs::UniqueID; Status::Status(const file_status &Status) : UID(Status.getUniqueID()), MTime(Status.getLastModificationTime()), User(Status.getUser()), Group(Status.getGroup()), Size(Status.getSize()), - Type(Status.type()), Perms(Status.permissions()), IsVFSMapped(false) {} + Type(Status.type()), Perms(Status.permissions()) {} Status::Status(StringRef Name, UniqueID UID, sys::TimePoint<> MTime, uint32_t User, uint32_t Group, uint64_t Size, file_type Type, perms Perms) : Name(Name), UID(UID), MTime(MTime), User(User), Group(Group), Size(Size), - Type(Type), Perms(Perms), IsVFSMapped(false) {} + Type(Type), Perms(Perms) {} Status Status::copyWithNewName(const Status &In, StringRef NewName) { return Status(NewName, In.getUniqueID(), In.getLastModificationTime(), @@ -62,28 +89,34 @@ bool Status::equivalent(const Status &Other) const { assert(isStatusKnown() && Other.isStatusKnown()); return getUniqueID() == Other.getUniqueID(); } + bool Status::isDirectory() const { return Type == file_type::directory_file; } + bool Status::isRegularFile() const { return Type == file_type::regular_file; } + bool Status::isOther() const { return exists() && !isRegularFile() && !isDirectory() && !isSymlink(); } + bool Status::isSymlink() const { return Type == file_type::symlink_file; } + bool Status::isStatusKnown() const { return Type != file_type::status_error; } + bool Status::exists() const { return isStatusKnown() && Type != file_type::file_not_found; } -File::~File() {} +File::~File() = default; -FileSystem::~FileSystem() {} +FileSystem::~FileSystem() = default; ErrorOr<std::unique_ptr<MemoryBuffer>> FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize, @@ -97,7 +130,7 @@ FileSystem::getBufferForFile(const llvm::Twine &Name, int64_t FileSize, std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const { if (llvm::sys::path::is_absolute(Path)) - return std::error_code(); + return {}; auto WorkingDir = getCurrentWorkingDirectory(); if (!WorkingDir) @@ -106,6 +139,11 @@ std::error_code FileSystem::makeAbsolute(SmallVectorImpl<char> &Path) const { return llvm::sys::fs::make_absolute(WorkingDir.get(), Path); } +std::error_code FileSystem::getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const { + return errc::operation_not_permitted; +} + bool FileSystem::exists(const Twine &Path) { auto Status = status(Path); return Status && Status->exists(); @@ -118,6 +156,7 @@ static bool isTraversalComponent(StringRef Component) { static bool pathHasTraversal(StringRef Path) { using namespace llvm::sys; + for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path))) if (isTraversalComponent(Comp)) return true; @@ -130,12 +169,15 @@ static bool pathHasTraversal(StringRef Path) { //===-----------------------------------------------------------------------===/ namespace { -/// \brief Wrapper around a raw file descriptor. + +/// Wrapper around a raw file descriptor. class RealFile : public File { + friend class RealFileSystem; + int FD; Status S; std::string RealName; - friend class RealFileSystem; + RealFile(int FD, StringRef NewName, StringRef NewRealPathName) : FD(FD), S(NewName, {}, {}, {}, {}, {}, llvm::sys::fs::file_type::status_error, {}), @@ -145,6 +187,7 @@ class RealFile : public File { public: ~RealFile() override; + ErrorOr<Status> status() override; ErrorOr<std::string> getName() override; ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name, @@ -153,7 +196,9 @@ public: bool IsVolatile) override; std::error_code close() override; }; -} // end anonymous namespace + +} // namespace + RealFile::~RealFile() { close(); } ErrorOr<Status> RealFile::status() { @@ -186,7 +231,8 @@ std::error_code RealFile::close() { } namespace { -/// \brief The file system according to your operating system. + +/// The file system according to your operating system. class RealFileSystem : public FileSystem { public: ErrorOr<Status> status(const Twine &Path) override; @@ -195,8 +241,11 @@ public: llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override; std::error_code setCurrentWorkingDirectory(const Twine &Path) override; + std::error_code getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const override; }; -} // end anonymous namespace + +} // namespace ErrorOr<Status> RealFileSystem::status(const Twine &Path) { sys::fs::file_status RealStatus; @@ -209,7 +258,8 @@ ErrorOr<std::unique_ptr<File>> RealFileSystem::openFileForRead(const Twine &Name) { int FD; SmallString<256> RealName; - if (std::error_code EC = sys::fs::openFileForRead(Name, FD, &RealName)) + if (std::error_code EC = + sys::fs::openFileForRead(Name, FD, sys::fs::OF_None, &RealName)) return EC; return std::unique_ptr<File>(new RealFile(FD, Name.str(), RealName.str())); } @@ -232,39 +282,50 @@ std::error_code RealFileSystem::setCurrentWorkingDirectory(const Twine &Path) { return llvm::sys::fs::set_current_path(Path); } +std::error_code +RealFileSystem::getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const { + return llvm::sys::fs::real_path(Path, Output); +} + IntrusiveRefCntPtr<FileSystem> vfs::getRealFileSystem() { static IntrusiveRefCntPtr<FileSystem> FS = new RealFileSystem(); return FS; } namespace { + class RealFSDirIter : public clang::vfs::detail::DirIterImpl { llvm::sys::fs::directory_iterator Iter; + public: RealFSDirIter(const Twine &Path, std::error_code &EC) : Iter(Path, EC) { - if (!EC && Iter != llvm::sys::fs::directory_iterator()) { + if (Iter != llvm::sys::fs::directory_iterator()) { llvm::sys::fs::file_status S; - EC = llvm::sys::fs::status(Iter->path(), S, true); + std::error_code ErrorCode = llvm::sys::fs::status(Iter->path(), S, true); CurrentEntry = Status::copyWithNewName(S, Iter->path()); + if (!EC) + EC = ErrorCode; } } std::error_code increment() override { std::error_code EC; Iter.increment(EC); - if (EC) { - return EC; - } else if (Iter == llvm::sys::fs::directory_iterator()) { + if (Iter == llvm::sys::fs::directory_iterator()) { CurrentEntry = Status(); } else { llvm::sys::fs::file_status S; - EC = llvm::sys::fs::status(Iter->path(), S, true); + std::error_code ErrorCode = llvm::sys::fs::status(Iter->path(), S, true); CurrentEntry = Status::copyWithNewName(S, Iter->path()); + if (!EC) + EC = ErrorCode; } return EC; } }; -} + +} // namespace directory_iterator RealFileSystem::dir_begin(const Twine &Dir, std::error_code &EC) { @@ -274,6 +335,7 @@ directory_iterator RealFileSystem::dir_begin(const Twine &Dir, //===-----------------------------------------------------------------------===/ // OverlayFileSystem implementation //===-----------------------------------------------------------------------===/ + OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) { FSList.push_back(std::move(BaseFS)); } @@ -311,17 +373,28 @@ OverlayFileSystem::getCurrentWorkingDirectory() const { // All file systems are synchronized, just take the first working directory. return FSList.front()->getCurrentWorkingDirectory(); } + std::error_code OverlayFileSystem::setCurrentWorkingDirectory(const Twine &Path) { for (auto &FS : FSList) if (std::error_code EC = FS->setCurrentWorkingDirectory(Path)) return EC; - return std::error_code(); + return {}; +} + +std::error_code +OverlayFileSystem::getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const { + for (auto &FS : FSList) + if (FS->exists(Path)) + return FS->getRealPath(Path, Output); + return errc::no_such_file_or_directory; } -clang::vfs::detail::DirIterImpl::~DirIterImpl() { } +clang::vfs::detail::DirIterImpl::~DirIterImpl() = default; namespace { + class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl { OverlayFileSystem &Overlays; std::string Path; @@ -340,7 +413,7 @@ class OverlayFSDirIterImpl : public clang::vfs::detail::DirIterImpl { if (CurrentDirIter != directory_iterator()) break; // found } - return std::error_code(); + return {}; } std::error_code incrementDirIter(bool IsFirstTime) { @@ -379,7 +452,8 @@ public: std::error_code increment() override { return incrementImpl(false); } }; -} // end anonymous namespace + +} // namespace directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir, std::error_code &EC) { @@ -389,6 +463,7 @@ directory_iterator OverlayFileSystem::dir_begin(const Twine &Dir, namespace clang { namespace vfs { + namespace detail { enum InMemoryNodeKind { IME_File, IME_Directory }; @@ -402,13 +477,15 @@ class InMemoryNode { public: InMemoryNode(Status Stat, InMemoryNodeKind Kind) : Stat(std::move(Stat)), Kind(Kind) {} - virtual ~InMemoryNode() {} + virtual ~InMemoryNode() = default; + const Status &getStatus() const { return Stat; } InMemoryNodeKind getKind() const { return Kind; } virtual std::string toString(unsigned Indent) const = 0; }; namespace { + class InMemoryFile : public InMemoryNode { std::unique_ptr<llvm::MemoryBuffer> Buffer; @@ -417,9 +494,11 @@ public: : InMemoryNode(std::move(Stat), IME_File), Buffer(std::move(Buffer)) {} llvm::MemoryBuffer *getBuffer() { return Buffer.get(); } + std::string toString(unsigned Indent) const override { return (std::string(Indent, ' ') + getStatus().getName() + "\n").str(); } + static bool classof(const InMemoryNode *N) { return N->getKind() == IME_File; } @@ -433,6 +512,7 @@ public: explicit InMemoryFileAdaptor(InMemoryFile &Node) : Node(Node) {} llvm::ErrorOr<Status> status() override { return Node.getStatus(); } + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, bool IsVolatile) override { @@ -440,9 +520,11 @@ public: return llvm::MemoryBuffer::getMemBuffer( Buf->getBuffer(), Buf->getBufferIdentifier(), RequiresNullTerminator); } - std::error_code close() override { return std::error_code(); } + + std::error_code close() override { return {}; } }; -} // end anonymous namespace + +} // namespace class InMemoryDirectory : public InMemoryNode { std::map<std::string, std::unique_ptr<InMemoryNode>> Entries; @@ -450,34 +532,38 @@ class InMemoryDirectory : public InMemoryNode { public: InMemoryDirectory(Status Stat) : InMemoryNode(std::move(Stat), IME_Directory) {} + InMemoryNode *getChild(StringRef Name) { auto I = Entries.find(Name); if (I != Entries.end()) return I->second.get(); return nullptr; } + InMemoryNode *addChild(StringRef Name, std::unique_ptr<InMemoryNode> Child) { return Entries.insert(make_pair(Name, std::move(Child))) .first->second.get(); } - typedef decltype(Entries)::const_iterator const_iterator; + using const_iterator = decltype(Entries)::const_iterator; + const_iterator begin() const { return Entries.begin(); } const_iterator end() const { return Entries.end(); } std::string toString(unsigned Indent) const override { std::string Result = (std::string(Indent, ' ') + getStatus().getName() + "\n").str(); - for (const auto &Entry : Entries) { + for (const auto &Entry : Entries) Result += Entry.second->toString(Indent + 2); - } return Result; } + static bool classof(const InMemoryNode *N) { return N->getKind() == IME_Directory; } }; -} + +} // namespace detail InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths) : Root(new detail::InMemoryDirectory( @@ -486,7 +572,7 @@ InMemoryFileSystem::InMemoryFileSystem(bool UseNormalizedPaths) llvm::sys::fs::perms::all_all))), UseNormalizedPaths(UseNormalizedPaths) {} -InMemoryFileSystem::~InMemoryFileSystem() {} +InMemoryFileSystem::~InMemoryFileSystem() = default; std::string InMemoryFileSystem::toString() const { return Root->toString(/*Indent=*/0); @@ -645,13 +731,15 @@ InMemoryFileSystem::openFileForRead(const Twine &Path) { } namespace { + /// Adaptor from InMemoryDir::iterator to directory_iterator. class InMemoryDirIterator : public clang::vfs::detail::DirIterImpl { detail::InMemoryDirectory::const_iterator I; detail::InMemoryDirectory::const_iterator E; public: - InMemoryDirIterator() {} + InMemoryDirIterator() = default; + explicit InMemoryDirIterator(detail::InMemoryDirectory &Dir) : I(Dir.begin()), E(Dir.end()) { if (I != E) @@ -663,10 +751,11 @@ public: // When we're at the end, make CurrentEntry invalid and DirIterImpl will do // the rest. CurrentEntry = I != E ? I->second->getStatus() : Status(); - return std::error_code(); + return {}; } }; -} // end anonymous namespace + +} // namespace directory_iterator InMemoryFileSystem::dir_begin(const Twine &Dir, std::error_code &EC) { @@ -697,11 +786,25 @@ std::error_code InMemoryFileSystem::setCurrentWorkingDirectory(const Twine &P) { if (!Path.empty()) WorkingDirectory = Path.str(); - return std::error_code(); -} + return {}; } + +std::error_code +InMemoryFileSystem::getRealPath(const Twine &Path, + SmallVectorImpl<char> &Output) const { + auto CWD = getCurrentWorkingDirectory(); + if (!CWD || CWD->empty()) + return errc::operation_not_permitted; + Path.toVector(Output); + if (auto EC = makeAbsolute(Output)) + return EC; + llvm::sys::path::remove_dots(Output, /*remove_dot_dot=*/true); + return {}; } +} // namespace vfs +} // namespace clang + //===-----------------------------------------------------------------------===/ // RedirectingFileSystem implementation //===-----------------------------------------------------------------------===/ @@ -713,14 +816,15 @@ enum EntryKind { EK_File }; -/// \brief A single file or directory in the VFS. +/// A single file or directory in the VFS. class Entry { EntryKind Kind; std::string Name; public: - virtual ~Entry(); Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {} + virtual ~Entry() = default; + StringRef getName() const { return Name; } EntryKind getKind() const { return Kind; } }; @@ -737,14 +841,20 @@ public: S(std::move(S)) {} RedirectingDirectoryEntry(StringRef Name, Status S) : Entry(EK_Directory, Name), S(std::move(S)) {} + Status getStatus() { return S; } + void addContent(std::unique_ptr<Entry> Content) { Contents.push_back(std::move(Content)); } + Entry *getLastContent() const { return Contents.back().get(); } - typedef decltype(Contents)::iterator iterator; + + using iterator = decltype(Contents)::iterator; + iterator contents_begin() { return Contents.begin(); } iterator contents_end() { return Contents.end(); } + static bool classof(const Entry *E) { return E->getKind() == EK_Directory; } }; @@ -755,21 +865,27 @@ public: NK_External, NK_Virtual }; + private: std::string ExternalContentsPath; NameKind UseName; + public: RedirectingFileEntry(StringRef Name, StringRef ExternalContentsPath, NameKind UseName) : Entry(EK_File, Name), ExternalContentsPath(ExternalContentsPath), UseName(UseName) {} + StringRef getExternalContentsPath() const { return ExternalContentsPath; } - /// \brief whether to use the external path as the name for this file. + + /// whether to use the external path as the name for this file. bool useExternalName(bool GlobalUseExternalName) const { return UseName == NK_NotSet ? GlobalUseExternalName : (UseName == NK_External); } + NameKind getUseName() const { return UseName; } + static bool classof(const Entry *E) { return E->getKind() == EK_File; } }; @@ -785,10 +901,11 @@ public: RedirectingDirectoryEntry::iterator Begin, RedirectingDirectoryEntry::iterator End, std::error_code &EC); + std::error_code increment() override; }; -/// \brief A virtual file system parsed from a YAML file. +/// A virtual file system parsed from a YAML file. /// /// Currently, this class allows creating virtual directories and mapping /// virtual file paths to existing external files, available in \c ExternalFS. @@ -844,10 +961,14 @@ public: /// /path/to/file). However, any directory that contains more than one child /// must be uniquely represented by a directory entry. class RedirectingFileSystem : public vfs::FileSystem { + friend class RedirectingFileSystemParser; + /// The root(s) of the virtual file system. std::vector<std::unique_ptr<Entry>> Roots; - /// \brief The file system to use for external references. + + /// The file system to use for external references. IntrusiveRefCntPtr<FileSystem> ExternalFS; + /// If IsRelativeOverlay is set, this represents the directory /// path that should be prefixed to each 'external-contents' entry /// when reading from YAML files. @@ -856,7 +977,7 @@ class RedirectingFileSystem : public vfs::FileSystem { /// @name Configuration /// @{ - /// \brief Whether to perform case-sensitive comparisons. + /// Whether to perform case-sensitive comparisons. /// /// Currently, case-insensitive matching only works correctly with ASCII. bool CaseSensitive = true; @@ -865,11 +986,11 @@ class RedirectingFileSystem : public vfs::FileSystem { /// be prefixed in every 'external-contents' when reading from YAML files. bool IsRelativeOverlay = false; - /// \brief Whether to use to use the value of 'external-contents' for the + /// Whether to use to use the value of 'external-contents' for the /// names of files. This global value is overridable on a per-file basis. bool UseExternalNames = true; - /// \brief Whether an invalid path obtained via 'external-contents' should + /// Whether an invalid path obtained via 'external-contents' should /// cause iteration on the VFS to stop. If 'true', the VFS should ignore /// the entry and continue with the next. Allows YAML files to be shared /// across multiple compiler invocations regardless of prior existent @@ -882,31 +1003,29 @@ class RedirectingFileSystem : public vfs::FileSystem { /// "." and "./" in their paths. FIXME: some unittests currently fail on /// win32 when using remove_dots and remove_leading_dotslash on paths. bool UseCanonicalizedPaths = -#ifdef LLVM_ON_WIN32 +#ifdef _WIN32 false; #else true; #endif - friend class RedirectingFileSystemParser; - private: RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS) : ExternalFS(std::move(ExternalFS)) {} - /// \brief Looks up the path <tt>[Start, End)</tt> in \p From, possibly + /// Looks up the path <tt>[Start, End)</tt> in \p From, possibly /// recursing into the contents of \p From if it is a directory. ErrorOr<Entry *> lookupPath(sys::path::const_iterator Start, sys::path::const_iterator End, Entry *From); - /// \brief Get the status of a given an \c Entry. + /// Get the status of a given an \c Entry. ErrorOr<Status> status(const Twine &Path, Entry *E); public: - /// \brief Looks up \p Path in \c Roots. + /// Looks up \p Path in \c Roots. ErrorOr<Entry *> lookupPath(const Twine &Path); - /// \brief Parses \p Buffer, which is expected to be in YAML format and + /// Parses \p Buffer, which is expected to be in YAML format and /// returns a virtual file system representing its contents. static RedirectingFileSystem * create(std::unique_ptr<MemoryBuffer> Buffer, @@ -919,6 +1038,7 @@ public: llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override { return ExternalFS->getCurrentWorkingDirectory(); } + std::error_code setCurrentWorkingDirectory(const Twine &Path) override { return ExternalFS->setCurrentWorkingDirectory(Path); } @@ -927,17 +1047,17 @@ public: ErrorOr<Entry *> E = lookupPath(Dir); if (!E) { EC = E.getError(); - return directory_iterator(); + return {}; } ErrorOr<Status> S = status(Dir, *E); if (!S) { EC = S.getError(); - return directory_iterator(); + return {}; } if (!S->isDirectory()) { EC = std::error_code(static_cast<int>(errc::not_a_directory), std::system_category()); - return directory_iterator(); + return {}; } auto *D = cast<RedirectingDirectoryEntry>(*E); @@ -959,7 +1079,7 @@ public: #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void dump() const { - for (const std::unique_ptr<Entry> &Root : Roots) + for (const auto &Root : Roots) dumpEntry(Root.get()); } @@ -979,10 +1099,9 @@ LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const { } } #endif - }; -/// \brief A helper class to hold the common YAML parsing state. +/// A helper class to hold the common YAML parsing state. class RedirectingFileSystemParser { yaml::Stream &Stream; @@ -993,7 +1112,8 @@ class RedirectingFileSystemParser { // false on error bool parseScalarString(yaml::Node *N, StringRef &Result, SmallVectorImpl<char> &Storage) { - yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N); + const auto *S = dyn_cast<yaml::ScalarNode>(N); + if (!S) { error(N, "expected string"); return false; @@ -1024,11 +1144,13 @@ class RedirectingFileSystemParser { } struct KeyStatus { - KeyStatus(bool Required=false) : Required(Required), Seen(false) {} bool Required; - bool Seen; + bool Seen = false; + + KeyStatus(bool Required = false) : Required(Required) {} }; - typedef std::pair<StringRef, KeyStatus> KeyStatusPair; + + using KeyStatusPair = std::pair<StringRef, KeyStatus>; // false on error bool checkDuplicateOrUnknownKey(yaml::Node *KeyNode, StringRef Key, @@ -1048,11 +1170,9 @@ class RedirectingFileSystemParser { // false on error bool checkMissingKeys(yaml::Node *Obj, DenseMap<StringRef, KeyStatus> &Keys) { - for (DenseMap<StringRef, KeyStatus>::iterator I = Keys.begin(), - E = Keys.end(); - I != E; ++I) { - if (I->second.Required && !I->second.Seen) { - error(Obj, Twine("missing key '") + I->first + "'"); + for (const auto &I : Keys) { + if (I.second.Required && !I.second.Seen) { + error(Obj, Twine("missing key '") + I.first + "'"); return false; } } @@ -1062,7 +1182,7 @@ class RedirectingFileSystemParser { Entry *lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, Entry *ParentEntry = nullptr) { if (!ParentEntry) { // Look for a existent root - for (const std::unique_ptr<Entry> &Root : FS->Roots) { + for (const auto &Root : FS->Roots) { if (Name.equals(Root->getName())) { ParentEntry = Root.get(); return ParentEntry; @@ -1125,7 +1245,7 @@ class RedirectingFileSystemParser { } std::unique_ptr<Entry> parseEntry(yaml::Node *N, RedirectingFileSystem *FS) { - yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N); + auto *M = dyn_cast<yaml::MappingNode>(N); if (!M) { error(N, "expected mapping node for file or directory entry"); return nullptr; @@ -1148,21 +1268,20 @@ class RedirectingFileSystemParser { auto UseExternalName = RedirectingFileEntry::NK_NotSet; EntryKind Kind; - for (yaml::MappingNode::iterator I = M->begin(), E = M->end(); I != E; - ++I) { + for (auto &I : *M) { StringRef Key; // Reuse the buffer for key and value, since we don't look at key after // parsing value. SmallString<256> Buffer; - if (!parseScalarString(I->getKey(), Key, Buffer)) + if (!parseScalarString(I.getKey(), Key, Buffer)) return nullptr; - if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys)) + if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys)) return nullptr; StringRef Value; if (Key == "name") { - if (!parseScalarString(I->getValue(), Value, Buffer)) + if (!parseScalarString(I.getValue(), Value, Buffer)) return nullptr; if (FS->UseCanonicalizedPaths) { @@ -1176,47 +1295,44 @@ class RedirectingFileSystemParser { Name = Value; } } else if (Key == "type") { - if (!parseScalarString(I->getValue(), Value, Buffer)) + if (!parseScalarString(I.getValue(), Value, Buffer)) return nullptr; if (Value == "file") Kind = EK_File; else if (Value == "directory") Kind = EK_Directory; else { - error(I->getValue(), "unknown value for 'type'"); + error(I.getValue(), "unknown value for 'type'"); return nullptr; } } else if (Key == "contents") { if (HasContents) { - error(I->getKey(), + error(I.getKey(), "entry already has 'contents' or 'external-contents'"); return nullptr; } HasContents = true; - yaml::SequenceNode *Contents = - dyn_cast<yaml::SequenceNode>(I->getValue()); + auto *Contents = dyn_cast<yaml::SequenceNode>(I.getValue()); if (!Contents) { // FIXME: this is only for directories, what about files? - error(I->getValue(), "expected array"); + error(I.getValue(), "expected array"); return nullptr; } - for (yaml::SequenceNode::iterator I = Contents->begin(), - E = Contents->end(); - I != E; ++I) { - if (std::unique_ptr<Entry> E = parseEntry(&*I, FS)) + for (auto &I : *Contents) { + if (std::unique_ptr<Entry> E = parseEntry(&I, FS)) EntryArrayContents.push_back(std::move(E)); else return nullptr; } } else if (Key == "external-contents") { if (HasContents) { - error(I->getKey(), + error(I.getKey(), "entry already has 'contents' or 'external-contents'"); return nullptr; } HasContents = true; - if (!parseScalarString(I->getValue(), Value, Buffer)) + if (!parseScalarString(I.getValue(), Value, Buffer)) return nullptr; SmallString<256> FullPath; @@ -1238,7 +1354,7 @@ class RedirectingFileSystemParser { ExternalContentsPath = FullPath.str(); } else if (Key == "use-external-name") { bool Val; - if (!parseScalarBool(I->getValue(), Val)) + if (!parseScalarBool(I.getValue(), Val)) return nullptr; UseExternalName = Val ? RedirectingFileEntry::NK_External : RedirectingFileEntry::NK_Virtual; @@ -1311,7 +1427,7 @@ public: // false on error bool parse(yaml::Node *Root, RedirectingFileSystem *FS) { - yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root); + auto *Top = dyn_cast<yaml::MappingNode>(Root); if (!Top) { error(Root, "expected mapping node"); return false; @@ -1330,26 +1446,24 @@ public: std::vector<std::unique_ptr<Entry>> RootEntries; // Parse configuration and 'roots' - for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E; - ++I) { + for (auto &I : *Top) { SmallString<10> KeyBuffer; StringRef Key; - if (!parseScalarString(I->getKey(), Key, KeyBuffer)) + if (!parseScalarString(I.getKey(), Key, KeyBuffer)) return false; - if (!checkDuplicateOrUnknownKey(I->getKey(), Key, Keys)) + if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys)) return false; if (Key == "roots") { - yaml::SequenceNode *Roots = dyn_cast<yaml::SequenceNode>(I->getValue()); + auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue()); if (!Roots) { - error(I->getValue(), "expected array"); + error(I.getValue(), "expected array"); return false; } - for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end(); - I != E; ++I) { - if (std::unique_ptr<Entry> E = parseEntry(&*I, FS)) + for (auto &I : *Roots) { + if (std::unique_ptr<Entry> E = parseEntry(&I, FS)) RootEntries.push_back(std::move(E)); else return false; @@ -1357,32 +1471,32 @@ public: } else if (Key == "version") { StringRef VersionString; SmallString<4> Storage; - if (!parseScalarString(I->getValue(), VersionString, Storage)) + if (!parseScalarString(I.getValue(), VersionString, Storage)) return false; int Version; if (VersionString.getAsInteger<int>(10, Version)) { - error(I->getValue(), "expected integer"); + error(I.getValue(), "expected integer"); return false; } if (Version < 0) { - error(I->getValue(), "invalid version number"); + error(I.getValue(), "invalid version number"); return false; } if (Version != 0) { - error(I->getValue(), "version mismatch, expected 0"); + error(I.getValue(), "version mismatch, expected 0"); return false; } } else if (Key == "case-sensitive") { - if (!parseScalarBool(I->getValue(), FS->CaseSensitive)) + if (!parseScalarBool(I.getValue(), FS->CaseSensitive)) return false; } else if (Key == "overlay-relative") { - if (!parseScalarBool(I->getValue(), FS->IsRelativeOverlay)) + if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay)) return false; } else if (Key == "use-external-names") { - if (!parseScalarBool(I->getValue(), FS->UseExternalNames)) + if (!parseScalarBool(I.getValue(), FS->UseExternalNames)) return false; } else if (Key == "ignore-non-existent-contents") { - if (!parseScalarBool(I->getValue(), FS->IgnoreNonExistentContents)) + if (!parseScalarBool(I.getValue(), FS->IgnoreNonExistentContents)) return false; } else { llvm_unreachable("key missing from Keys"); @@ -1398,22 +1512,20 @@ public: // Now that we sucessefully parsed the YAML file, canonicalize the internal // representation to a proper directory tree so that we can search faster // inside the VFS. - for (std::unique_ptr<Entry> &E : RootEntries) + for (auto &E : RootEntries) uniqueOverlayTree(FS, E.get()); return true; } }; -} // end of anonymous namespace -Entry::~Entry() = default; +} // namespace RedirectingFileSystem * RedirectingFileSystem::create(std::unique_ptr<MemoryBuffer> Buffer, SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS) { - SourceMgr SM; yaml::Stream Stream(Buffer->getMemBufferRef(), SM); @@ -1473,7 +1585,7 @@ ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) { sys::path::const_iterator Start = sys::path::begin(Path); sys::path::const_iterator End = sys::path::end(Path); - for (const std::unique_ptr<Entry> &Root : Roots) { + for (const auto &Root : Roots) { ErrorOr<Entry *> Result = lookupPath(Start, End, Root.get()); if (Result || Result.getError() != llvm::errc::no_such_file_or_directory) return Result; @@ -1484,7 +1596,7 @@ ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) { ErrorOr<Entry *> RedirectingFileSystem::lookupPath(sys::path::const_iterator Start, sys::path::const_iterator End, Entry *From) { -#ifndef LLVM_ON_WIN32 +#ifndef _WIN32 assert(!isTraversalComponent(*Start) && !isTraversalComponent(From->getName()) && "Paths should not contain traversal components"); @@ -1557,6 +1669,7 @@ ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path) { } namespace { + /// Provide a file wrapper with an overriden status. class FileWithFixedStatus : public File { std::unique_ptr<File> InnerFile; @@ -1568,14 +1681,17 @@ public: ErrorOr<Status> status() override { return S; } ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> + getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, bool IsVolatile) override { return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator, IsVolatile); } + std::error_code close() override { return InnerFile->close(); } }; -} // end anonymous namespace + +} // namespace ErrorOr<std::unique_ptr<File>> RedirectingFileSystem::openFileForRead(const Twine &Path) { @@ -1670,11 +1786,13 @@ void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) { } namespace { + class JSONWriter { llvm::raw_ostream &OS; SmallVector<StringRef, 16> DirStack; - inline unsigned getDirIndent() { return 4 * DirStack.size(); } - inline unsigned getFileIndent() { return 4 * (DirStack.size() + 1); } + + unsigned getDirIndent() { return 4 * DirStack.size(); } + unsigned getFileIndent() { return 4 * (DirStack.size() + 1); } bool containedIn(StringRef Parent, StringRef Path); StringRef containedPart(StringRef Parent, StringRef Path); void startDirectory(StringRef Path); @@ -1683,14 +1801,17 @@ class JSONWriter { public: JSONWriter(llvm::raw_ostream &OS) : OS(OS) {} + void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames, Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative, Optional<bool> IgnoreNonExistentContents, StringRef OverlayDir); }; -} + +} // namespace bool JSONWriter::containedIn(StringRef Parent, StringRef Path) { using namespace llvm::sys; + // Compare each path component. auto IParent = path::begin(Parent), EParent = path::end(Parent); for (auto IChild = path::begin(Path), EChild = path::end(Path); @@ -1812,8 +1933,8 @@ void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries, } void YAMLVFSWriter::write(llvm::raw_ostream &OS) { - std::sort(Mappings.begin(), Mappings.end(), - [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) { + llvm::sort(Mappings.begin(), Mappings.end(), + [](const YAMLVFSEntry &LHS, const YAMLVFSEntry &RHS) { return LHS.VPath < RHS.VPath; }); @@ -1868,7 +1989,7 @@ std::error_code VFSFromYamlDirIterImpl::increment() { if (Current == End) CurrentEntry = Status(); - return std::error_code(); + return {}; } vfs::recursive_directory_iterator::recursive_directory_iterator(FileSystem &FS_, |