Index: llvm/trunk/include/llvm/Support/VirtualFileSystem.h =================================================================== --- llvm/trunk/include/llvm/Support/VirtualFileSystem.h +++ llvm/trunk/include/llvm/Support/VirtualFileSystem.h @@ -24,6 +24,7 @@ #include "llvm/Support/Chrono.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/SourceMgr.h" #include #include @@ -495,6 +496,230 @@ std::string RPath; }; +class VFSFromYamlDirIterImpl; +class RedirectingFileSystemParser; + +/// 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. +/// +/// The basic structure of the parsed file is: +/// \verbatim +/// { +/// 'version': , +/// +/// 'roots': [ +/// +/// ] +/// } +/// \endverbatim +/// +/// All configuration options are optional. +/// 'case-sensitive': +/// 'use-external-names': +/// 'overlay-relative': +/// 'fallthrough': +/// +/// Virtual directories are represented as +/// \verbatim +/// { +/// 'type': 'directory', +/// 'name': , +/// 'contents': [ ] +/// } +/// \endverbatim +/// +/// The default attributes for virtual directories are: +/// \verbatim +/// MTime = now() when created +/// Perms = 0777 +/// User = Group = 0 +/// Size = 0 +/// UniqueID = unspecified unique value +/// \endverbatim +/// +/// Re-mapped files are represented as +/// \verbatim +/// { +/// 'type': 'file', +/// 'name': , +/// 'use-external-name': # Optional +/// 'external-contents': +/// } +/// \endverbatim +/// +/// and inherit their attributes from the external contents. +/// +/// In both cases, the 'name' field may contain multiple path components (e.g. +/// /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 { +public: + enum EntryKind { EK_Directory, EK_File }; + + /// A single file or directory in the VFS. + class Entry { + EntryKind Kind; + std::string Name; + + public: + Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {} + virtual ~Entry() = default; + + StringRef getName() const { return Name; } + EntryKind getKind() const { return Kind; } + }; + + class RedirectingDirectoryEntry : public Entry { + std::vector> Contents; + Status S; + + public: + RedirectingDirectoryEntry(StringRef Name, + std::vector> Contents, + Status S) + : Entry(EK_Directory, Name), Contents(std::move(Contents)), + 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 Content) { + Contents.push_back(std::move(Content)); + } + + Entry *getLastContent() const { return Contents.back().get(); } + + 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; } + }; + + class RedirectingFileEntry : public Entry { + public: + enum NameKind { NK_NotSet, 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; } + + /// 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; } + }; + +private: + friend class VFSFromYamlDirIterImpl; + friend class RedirectingFileSystemParser; + + /// The root(s) of the virtual file system. + std::vector> Roots; + + /// The file system to use for external references. + IntrusiveRefCntPtr ExternalFS; + + /// If IsRelativeOverlay is set, this represents the directory + /// path that should be prefixed to each 'external-contents' entry + /// when reading from YAML files. + std::string ExternalContentsPrefixDir; + + /// @name Configuration + /// @{ + + /// Whether to perform case-sensitive comparisons. + /// + /// Currently, case-insensitive matching only works correctly with ASCII. + bool CaseSensitive = true; + + /// IsRelativeOverlay marks whether a ExternalContentsPrefixDir path must + /// be prefixed in every 'external-contents' when reading from YAML files. + bool IsRelativeOverlay = false; + + /// 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; + + /// Whether to attempt a file lookup in external file system after it wasn't + /// found in VFS. + bool IsFallthrough = true; + /// @} + + /// Virtual file paths and external files could be canonicalized without "..", + /// "." and "./" in their paths. FIXME: some unittests currently fail on + /// win32 when using remove_dots and remove_leading_dotslash on paths. + bool UseCanonicalizedPaths = +#ifdef _WIN32 + false; +#else + true; +#endif + + RedirectingFileSystem(IntrusiveRefCntPtr ExternalFS) + : ExternalFS(std::move(ExternalFS)) {} + + /// Looks up the path [Start, End) in \p From, possibly + /// recursing into the contents of \p From if it is a directory. + ErrorOr lookupPath(llvm::sys::path::const_iterator Start, + llvm::sys::path::const_iterator End, + Entry *From) const; + + /// Get the status of a given an \c Entry. + ErrorOr status(const Twine &Path, Entry *E); + +public: + /// Looks up \p Path in \c Roots. + ErrorOr lookupPath(const Twine &Path) const; + + /// 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 Buffer, + SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, + void *DiagContext, IntrusiveRefCntPtr ExternalFS); + + ErrorOr status(const Twine &Path) override; + ErrorOr> openFileForRead(const Twine &Path) override; + + std::error_code getRealPath(const Twine &Path, + SmallVectorImpl &Output) const override; + + llvm::ErrorOr getCurrentWorkingDirectory() const override; + + std::error_code setCurrentWorkingDirectory(const Twine &Path) override; + + std::error_code isLocal(const Twine &Path, bool &Result) override; + + directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override; + + void setExternalContentsPrefixDir(StringRef PrefixDir); + + StringRef getExternalContentsPrefixDir() const; + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const; + LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const; +#endif +}; + /// Collect all pairs of entries from the /// \p YAMLFilePath. This is used by the module dependency collector to forward /// the entries into the reproducer output VFS YAML file. Index: llvm/trunk/lib/Support/VirtualFileSystem.cpp =================================================================== --- llvm/trunk/lib/Support/VirtualFileSystem.cpp +++ llvm/trunk/lib/Support/VirtualFileSystem.cpp @@ -943,84 +943,12 @@ // RedirectingFileSystem implementation //===-----------------------------------------------------------------------===/ -namespace { - -enum EntryKind { EK_Directory, EK_File }; - -/// A single file or directory in the VFS. -class Entry { - EntryKind Kind; - std::string Name; - -public: - Entry(EntryKind K, StringRef Name) : Kind(K), Name(Name) {} - virtual ~Entry() = default; - - StringRef getName() const { return Name; } - EntryKind getKind() const { return Kind; } -}; - -class RedirectingDirectoryEntry : public Entry { - std::vector> Contents; - Status S; - -public: - RedirectingDirectoryEntry(StringRef Name, - std::vector> Contents, - Status S) - : Entry(EK_Directory, Name), Contents(std::move(Contents)), - 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 Content) { - Contents.push_back(std::move(Content)); - } - - Entry *getLastContent() const { return Contents.back().get(); } - - 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; } -}; - -class RedirectingFileEntry : public Entry { -public: - enum NameKind { NK_NotSet, 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; } - - /// 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; } -}; - // FIXME: reuse implementation common with OverlayFSDirIterImpl as these // iterators are conceptually similar. -class VFSFromYamlDirIterImpl : public llvm::vfs::detail::DirIterImpl { +class llvm::vfs::VFSFromYamlDirIterImpl + : public llvm::vfs::detail::DirIterImpl { std::string Dir; - RedirectingDirectoryEntry::iterator Current, End; + RedirectingFileSystem::RedirectingDirectoryEntry::iterator Current, End; // To handle 'fallthrough' mode we need to iterate at first through // RedirectingDirectoryEntry and then through ExternalFS. These operations are @@ -1050,216 +978,92 @@ /// @} public: - VFSFromYamlDirIterImpl(const Twine &Path, - RedirectingDirectoryEntry::iterator Begin, - RedirectingDirectoryEntry::iterator End, - bool IterateExternalFS, FileSystem &ExternalFS, - std::error_code &EC); + VFSFromYamlDirIterImpl( + const Twine &Path, + RedirectingFileSystem::RedirectingDirectoryEntry::iterator Begin, + RedirectingFileSystem::RedirectingDirectoryEntry::iterator End, + bool IterateExternalFS, FileSystem &ExternalFS, std::error_code &EC); std::error_code increment() override; }; -/// 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. -/// -/// The basic structure of the parsed file is: -/// \verbatim -/// { -/// 'version': , -/// -/// 'roots': [ -/// -/// ] -/// } -/// \endverbatim -/// -/// All configuration options are optional. -/// 'case-sensitive': -/// 'use-external-names': -/// 'overlay-relative': -/// 'fallthrough': -/// -/// Virtual directories are represented as -/// \verbatim -/// { -/// 'type': 'directory', -/// 'name': , -/// 'contents': [ ] -/// } -/// \endverbatim -/// -/// The default attributes for virtual directories are: -/// \verbatim -/// MTime = now() when created -/// Perms = 0777 -/// User = Group = 0 -/// Size = 0 -/// UniqueID = unspecified unique value -/// \endverbatim -/// -/// Re-mapped files are represented as -/// \verbatim -/// { -/// 'type': 'file', -/// 'name': , -/// 'use-external-name': # Optional -/// 'external-contents': -/// } -/// \endverbatim -/// -/// and inherit their attributes from the external contents. -/// -/// In both cases, the 'name' field may contain multiple path components (e.g. -/// /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> Roots; - - /// The file system to use for external references. - IntrusiveRefCntPtr ExternalFS; - - /// If IsRelativeOverlay is set, this represents the directory - /// path that should be prefixed to each 'external-contents' entry - /// when reading from YAML files. - std::string ExternalContentsPrefixDir; - - /// @name Configuration - /// @{ - - /// Whether to perform case-sensitive comparisons. - /// - /// Currently, case-insensitive matching only works correctly with ASCII. - bool CaseSensitive = true; - - /// IsRelativeOverlay marks whether a ExternalContentsPrefixDir path must - /// be prefixed in every 'external-contents' when reading from YAML files. - bool IsRelativeOverlay = false; - - /// 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; - - /// Whether to attempt a file lookup in external file system after it wasn't - /// found in VFS. - bool IsFallthrough = true; - /// @} - - /// Virtual file paths and external files could be canonicalized without "..", - /// "." and "./" in their paths. FIXME: some unittests currently fail on - /// win32 when using remove_dots and remove_leading_dotslash on paths. - bool UseCanonicalizedPaths = -#ifdef _WIN32 - false; -#else - true; -#endif - -private: - RedirectingFileSystem(IntrusiveRefCntPtr ExternalFS) - : ExternalFS(std::move(ExternalFS)) {} - - /// Looks up the path [Start, End) in \p From, possibly - /// recursing into the contents of \p From if it is a directory. - ErrorOr lookupPath(sys::path::const_iterator Start, - sys::path::const_iterator End, Entry *From) const; - - /// Get the status of a given an \c Entry. - ErrorOr status(const Twine &Path, Entry *E); - -public: - /// Looks up \p Path in \c Roots. - ErrorOr lookupPath(const Twine &Path) const; - - /// 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 Buffer, - SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, - void *DiagContext, IntrusiveRefCntPtr ExternalFS); +llvm::ErrorOr +RedirectingFileSystem::getCurrentWorkingDirectory() const { + return ExternalFS->getCurrentWorkingDirectory(); +} - ErrorOr status(const Twine &Path) override; - ErrorOr> openFileForRead(const Twine &Path) override; +std::error_code +RedirectingFileSystem::setCurrentWorkingDirectory(const Twine &Path) { + return ExternalFS->setCurrentWorkingDirectory(Path); +} - std::error_code getRealPath(const Twine &Path, - SmallVectorImpl &Output) const override; +std::error_code RedirectingFileSystem::isLocal(const Twine &Path, + bool &Result) { + return ExternalFS->isLocal(Path, Result); +} - llvm::ErrorOr getCurrentWorkingDirectory() const override { - return ExternalFS->getCurrentWorkingDirectory(); +directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir, + std::error_code &EC) { + ErrorOr E = lookupPath(Dir); + if (!E) { + EC = E.getError(); + if (IsFallthrough && EC == errc::no_such_file_or_directory) + return ExternalFS->dir_begin(Dir, EC); + return {}; } - - std::error_code setCurrentWorkingDirectory(const Twine &Path) override { - return ExternalFS->setCurrentWorkingDirectory(Path); + ErrorOr S = status(Dir, *E); + if (!S) { + EC = S.getError(); + return {}; } - - std::error_code isLocal(const Twine &Path, bool &Result) override { - return ExternalFS->isLocal(Path, Result); + if (!S->isDirectory()) { + EC = std::error_code(static_cast(errc::not_a_directory), + std::system_category()); + return {}; } - directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override { - ErrorOr E = lookupPath(Dir); - if (!E) { - EC = E.getError(); - if (IsFallthrough && EC == errc::no_such_file_or_directory) - return ExternalFS->dir_begin(Dir, EC); - return {}; - } - ErrorOr S = status(Dir, *E); - if (!S) { - EC = S.getError(); - return {}; - } - if (!S->isDirectory()) { - EC = std::error_code(static_cast(errc::not_a_directory), - std::system_category()); - return {}; - } - - auto *D = cast(*E); - return directory_iterator(std::make_shared( - Dir, D->contents_begin(), D->contents_end(), - /*IterateExternalFS=*/IsFallthrough, *ExternalFS, EC)); - } + auto *D = cast(*E); + return directory_iterator(std::make_shared( + Dir, D->contents_begin(), D->contents_end(), + /*IterateExternalFS=*/IsFallthrough, *ExternalFS, EC)); +} - void setExternalContentsPrefixDir(StringRef PrefixDir) { - ExternalContentsPrefixDir = PrefixDir.str(); - } +void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) { + ExternalContentsPrefixDir = PrefixDir.str(); +} - StringRef getExternalContentsPrefixDir() const { - return ExternalContentsPrefixDir; - } +StringRef RedirectingFileSystem::getExternalContentsPrefixDir() const { + return ExternalContentsPrefixDir; +} #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) - LLVM_DUMP_METHOD void dump() const { - for (const auto &Root : Roots) - dumpEntry(Root.get()); - } - - LLVM_DUMP_METHOD void dumpEntry(Entry *E, int NumSpaces = 0) const { - StringRef Name = E->getName(); - for (int i = 0, e = NumSpaces; i < e; ++i) - dbgs() << " "; - dbgs() << "'" << Name.str().c_str() << "'" - << "\n"; - - if (E->getKind() == EK_Directory) { - auto *DE = dyn_cast(E); - assert(DE && "Should be a directory"); +LLVM_DUMP_METHOD void RedirectingFileSystem::dump() const { + for (const auto &Root : Roots) + dumpEntry(Root.get()); +} + +LLVM_DUMP_METHOD void +RedirectingFileSystem::dumpEntry(RedirectingFileSystem::Entry *E, + int NumSpaces) const { + StringRef Name = E->getName(); + for (int i = 0, e = NumSpaces; i < e; ++i) + dbgs() << " "; + dbgs() << "'" << Name.str().c_str() << "'" + << "\n"; + + if (E->getKind() == RedirectingFileSystem::EK_Directory) { + auto *DE = dyn_cast(E); + assert(DE && "Should be a directory"); - for (std::unique_ptr &SubEntry : - llvm::make_range(DE->contents_begin(), DE->contents_end())) - dumpEntry(SubEntry.get(), NumSpaces + 2); - } + for (std::unique_ptr &SubEntry : + llvm::make_range(DE->contents_begin(), DE->contents_end())) + dumpEntry(SubEntry.get(), NumSpaces + 2); } +} #endif -}; /// A helper class to hold the common YAML parsing state. -class RedirectingFileSystemParser { +class llvm::vfs::RedirectingFileSystemParser { yaml::Stream &Stream; void error(yaml::Node *N, const Twine &Msg) { Stream.printError(N, Msg); } @@ -1334,8 +1138,9 @@ return true; } - Entry *lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, - Entry *ParentEntry = nullptr) { + RedirectingFileSystem::Entry * + lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name, + RedirectingFileSystem::Entry *ParentEntry = nullptr) { if (!ParentEntry) { // Look for a existent root for (const auto &Root : FS->Roots) { if (Name.equals(Root->getName())) { @@ -1344,20 +1149,24 @@ } } } else { // Advance to the next component - auto *DE = dyn_cast(ParentEntry); - for (std::unique_ptr &Content : + auto *DE = dyn_cast( + ParentEntry); + for (std::unique_ptr &Content : llvm::make_range(DE->contents_begin(), DE->contents_end())) { - auto *DirContent = dyn_cast(Content.get()); + auto *DirContent = + dyn_cast( + Content.get()); if (DirContent && Name.equals(Content->getName())) return DirContent; } } // ... or create a new one - std::unique_ptr E = llvm::make_unique( - Name, - Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(), - 0, 0, 0, file_type::directory_file, sys::fs::all_all)); + std::unique_ptr E = + llvm::make_unique( + Name, Status("", getNextVirtualUniqueID(), + std::chrono::system_clock::now(), 0, 0, 0, + file_type::directory_file, sys::fs::all_all)); if (!ParentEntry) { // Add a new root to the overlay FS->Roots.push_back(std::move(E)); @@ -1365,42 +1174,47 @@ return ParentEntry; } - auto *DE = dyn_cast(ParentEntry); + auto *DE = + dyn_cast(ParentEntry); DE->addContent(std::move(E)); return DE->getLastContent(); } - void uniqueOverlayTree(RedirectingFileSystem *FS, Entry *SrcE, - Entry *NewParentE = nullptr) { + void uniqueOverlayTree(RedirectingFileSystem *FS, + RedirectingFileSystem::Entry *SrcE, + RedirectingFileSystem::Entry *NewParentE = nullptr) { StringRef Name = SrcE->getName(); switch (SrcE->getKind()) { - case EK_Directory: { - auto *DE = dyn_cast(SrcE); + case RedirectingFileSystem::EK_Directory: { + auto *DE = + dyn_cast(SrcE); assert(DE && "Must be a directory"); // Empty directories could be present in the YAML as a way to // describe a file for a current directory after some of its subdir // is parsed. This only leads to redundant walks, ignore it. if (!Name.empty()) NewParentE = lookupOrCreateEntry(FS, Name, NewParentE); - for (std::unique_ptr &SubEntry : + for (std::unique_ptr &SubEntry : llvm::make_range(DE->contents_begin(), DE->contents_end())) uniqueOverlayTree(FS, SubEntry.get(), NewParentE); break; } - case EK_File: { - auto *FE = dyn_cast(SrcE); + case RedirectingFileSystem::EK_File: { + auto *FE = dyn_cast(SrcE); assert(FE && "Must be a file"); assert(NewParentE && "Parent entry must exist"); - auto *DE = dyn_cast(NewParentE); - DE->addContent(llvm::make_unique( - Name, FE->getExternalContentsPath(), FE->getUseName())); + auto *DE = dyn_cast( + NewParentE); + DE->addContent( + llvm::make_unique( + Name, FE->getExternalContentsPath(), FE->getUseName())); break; } } } - std::unique_ptr parseEntry(yaml::Node *N, RedirectingFileSystem *FS, - bool IsRootEntry) { + std::unique_ptr + parseEntry(yaml::Node *N, RedirectingFileSystem *FS, bool IsRootEntry) { auto *M = dyn_cast(N); if (!M) { error(N, "expected mapping node for file or directory entry"); @@ -1418,12 +1232,14 @@ DenseMap Keys(std::begin(Fields), std::end(Fields)); bool HasContents = false; // external or otherwise - std::vector> EntryArrayContents; + std::vector> + EntryArrayContents; std::string ExternalContentsPath; std::string Name; yaml::Node *NameValueNode; - auto UseExternalName = RedirectingFileEntry::NK_NotSet; - EntryKind Kind; + auto UseExternalName = + RedirectingFileSystem::RedirectingFileEntry::NK_NotSet; + RedirectingFileSystem::EntryKind Kind; for (auto &I : *M) { StringRef Key; @@ -1456,9 +1272,9 @@ if (!parseScalarString(I.getValue(), Value, Buffer)) return nullptr; if (Value == "file") - Kind = EK_File; + Kind = RedirectingFileSystem::EK_File; else if (Value == "directory") - Kind = EK_Directory; + Kind = RedirectingFileSystem::EK_Directory; else { error(I.getValue(), "unknown value for 'type'"); return nullptr; @@ -1478,7 +1294,7 @@ } for (auto &I : *Contents) { - if (std::unique_ptr E = + if (std::unique_ptr E = parseEntry(&I, FS, /*IsRootEntry*/ false)) EntryArrayContents.push_back(std::move(E)); else @@ -1515,8 +1331,9 @@ bool Val; if (!parseScalarBool(I.getValue(), Val)) return nullptr; - UseExternalName = Val ? RedirectingFileEntry::NK_External - : RedirectingFileEntry::NK_Virtual; + UseExternalName = + Val ? RedirectingFileSystem::RedirectingFileEntry::NK_External + : RedirectingFileSystem::RedirectingFileEntry::NK_Virtual; } else { llvm_unreachable("key missing from Keys"); } @@ -1534,8 +1351,9 @@ return nullptr; // check invalid configuration - if (Kind == EK_Directory && - UseExternalName != RedirectingFileEntry::NK_NotSet) { + if (Kind == RedirectingFileSystem::EK_Directory && + UseExternalName != + RedirectingFileSystem::RedirectingFileEntry::NK_NotSet) { error(N, "'use-external-name' is not supported for directories"); return nullptr; } @@ -1556,17 +1374,19 @@ // Get the last component StringRef LastComponent = sys::path::filename(Trimmed); - std::unique_ptr Result; + std::unique_ptr Result; switch (Kind) { - case EK_File: - Result = llvm::make_unique( + case RedirectingFileSystem::EK_File: + Result = llvm::make_unique( LastComponent, std::move(ExternalContentsPath), UseExternalName); break; - case EK_Directory: - Result = llvm::make_unique( - LastComponent, std::move(EntryArrayContents), - Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(), - 0, 0, 0, file_type::directory_file, sys::fs::all_all)); + case RedirectingFileSystem::EK_Directory: + Result = + llvm::make_unique( + LastComponent, std::move(EntryArrayContents), + Status("", getNextVirtualUniqueID(), + std::chrono::system_clock::now(), 0, 0, 0, + file_type::directory_file, sys::fs::all_all)); break; } @@ -1578,12 +1398,14 @@ for (sys::path::reverse_iterator I = sys::path::rbegin(Parent), E = sys::path::rend(Parent); I != E; ++I) { - std::vector> Entries; + std::vector> Entries; Entries.push_back(std::move(Result)); - Result = llvm::make_unique( - *I, std::move(Entries), - Status("", getNextVirtualUniqueID(), std::chrono::system_clock::now(), - 0, 0, 0, file_type::directory_file, sys::fs::all_all)); + Result = + llvm::make_unique( + *I, std::move(Entries), + Status("", getNextVirtualUniqueID(), + std::chrono::system_clock::now(), 0, 0, 0, + file_type::directory_file, sys::fs::all_all)); } return Result; } @@ -1609,7 +1431,7 @@ }; DenseMap Keys(std::begin(Fields), std::end(Fields)); - std::vector> RootEntries; + std::vector> RootEntries; // Parse configuration and 'roots' for (auto &I : *Top) { @@ -1629,7 +1451,7 @@ } for (auto &I : *Roots) { - if (std::unique_ptr E = + if (std::unique_ptr E = parseEntry(&I, FS, /*IsRootEntry*/ true)) RootEntries.push_back(std::move(E)); else @@ -1686,8 +1508,6 @@ } }; -} // namespace - RedirectingFileSystem * RedirectingFileSystem::create(std::unique_ptr Buffer, SourceMgr::DiagHandlerTy DiagHandler, @@ -1731,7 +1551,8 @@ return FS.release(); } -ErrorOr RedirectingFileSystem::lookupPath(const Twine &Path_) const { +ErrorOr +RedirectingFileSystem::lookupPath(const Twine &Path_) const { SmallString<256> Path; Path_.toVector(Path); @@ -1753,17 +1574,18 @@ sys::path::const_iterator Start = sys::path::begin(Path); sys::path::const_iterator End = sys::path::end(Path); for (const auto &Root : Roots) { - ErrorOr Result = lookupPath(Start, End, Root.get()); + ErrorOr Result = + lookupPath(Start, End, Root.get()); if (Result || Result.getError() != llvm::errc::no_such_file_or_directory) return Result; } return make_error_code(llvm::errc::no_such_file_or_directory); } -ErrorOr +ErrorOr RedirectingFileSystem::lookupPath(sys::path::const_iterator Start, sys::path::const_iterator End, - Entry *From) const { + RedirectingFileSystem::Entry *From) const { #ifndef _WIN32 assert(!isTraversalComponent(*Start) && !isTraversalComponent(From->getName()) && @@ -1792,13 +1614,14 @@ } } - auto *DE = dyn_cast(From); + auto *DE = dyn_cast(From); if (!DE) return make_error_code(llvm::errc::not_a_directory); - for (const std::unique_ptr &DirEntry : + for (const std::unique_ptr &DirEntry : llvm::make_range(DE->contents_begin(), DE->contents_end())) { - ErrorOr Result = lookupPath(Start, End, DirEntry.get()); + ErrorOr Result = + lookupPath(Start, End, DirEntry.get()); if (Result || Result.getError() != llvm::errc::no_such_file_or_directory) return Result; } @@ -1814,9 +1637,10 @@ return S; } -ErrorOr RedirectingFileSystem::status(const Twine &Path, Entry *E) { +ErrorOr RedirectingFileSystem::status(const Twine &Path, + RedirectingFileSystem::Entry *E) { assert(E != nullptr); - if (auto *F = dyn_cast(E)) { + if (auto *F = dyn_cast(E)) { ErrorOr S = ExternalFS->status(F->getExternalContentsPath()); assert(!S || S->getName() == F->getExternalContentsPath()); if (S) @@ -1824,13 +1648,13 @@ *S); return S; } else { // directory - auto *DE = cast(E); + auto *DE = cast(E); return Status::copyWithNewName(DE->getStatus(), Path.str()); } } ErrorOr RedirectingFileSystem::status(const Twine &Path) { - ErrorOr Result = lookupPath(Path); + ErrorOr Result = lookupPath(Path); if (!Result) { if (IsFallthrough && Result.getError() == llvm::errc::no_such_file_or_directory) { @@ -1868,7 +1692,7 @@ ErrorOr> RedirectingFileSystem::openFileForRead(const Twine &Path) { - ErrorOr E = lookupPath(Path); + ErrorOr E = lookupPath(Path); if (!E) { if (IsFallthrough && E.getError() == llvm::errc::no_such_file_or_directory) { @@ -1877,7 +1701,7 @@ return E.getError(); } - auto *F = dyn_cast(*E); + auto *F = dyn_cast(*E); if (!F) // FIXME: errc::not_a_file? return make_error_code(llvm::errc::invalid_argument); @@ -1899,7 +1723,7 @@ std::error_code RedirectingFileSystem::getRealPath(const Twine &Path, SmallVectorImpl &Output) const { - ErrorOr Result = lookupPath(Path); + ErrorOr Result = lookupPath(Path); if (!Result) { if (IsFallthrough && Result.getError() == llvm::errc::no_such_file_or_directory) { @@ -1908,7 +1732,8 @@ return Result.getError(); } - if (auto *F = dyn_cast(*Result)) { + if (auto *F = + dyn_cast(*Result)) { return ExternalFS->getRealPath(F->getExternalContentsPath(), Output); } // Even if there is a directory entry, fall back to ExternalFS if allowed, @@ -1927,13 +1752,14 @@ std::move(ExternalFS)); } -static void getVFSEntries(Entry *SrcE, SmallVectorImpl &Path, +static void getVFSEntries(RedirectingFileSystem::Entry *SrcE, + SmallVectorImpl &Path, SmallVectorImpl &Entries) { auto Kind = SrcE->getKind(); - if (Kind == EK_Directory) { - auto *DE = dyn_cast(SrcE); + if (Kind == RedirectingFileSystem::EK_Directory) { + auto *DE = dyn_cast(SrcE); assert(DE && "Must be a directory"); - for (std::unique_ptr &SubEntry : + for (std::unique_ptr &SubEntry : llvm::make_range(DE->contents_begin(), DE->contents_end())) { Path.push_back(SubEntry->getName()); getVFSEntries(SubEntry.get(), Path, Entries); @@ -1942,8 +1768,8 @@ return; } - assert(Kind == EK_File && "Must be a EK_File"); - auto *FE = dyn_cast(SrcE); + assert(Kind == RedirectingFileSystem::EK_File && "Must be a EK_File"); + auto *FE = dyn_cast(SrcE); assert(FE && "Must be a file"); SmallString<128> VPath; for (auto &Comp : Path) @@ -1960,7 +1786,7 @@ RedirectingFileSystem *VFS = RedirectingFileSystem::create( std::move(Buffer), DiagHandler, YAMLFilePath, DiagContext, std::move(ExternalFS)); - ErrorOr RootE = VFS->lookupPath("/"); + ErrorOr RootE = VFS->lookupPath("/"); if (!RootE) return; SmallVector Components; @@ -2136,9 +1962,10 @@ } VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl( - const Twine &_Path, RedirectingDirectoryEntry::iterator Begin, - RedirectingDirectoryEntry::iterator End, bool IterateExternalFS, - FileSystem &ExternalFS, std::error_code &EC) + const Twine &_Path, + RedirectingFileSystem::RedirectingDirectoryEntry::iterator Begin, + RedirectingFileSystem::RedirectingDirectoryEntry::iterator End, + bool IterateExternalFS, FileSystem &ExternalFS, std::error_code &EC) : Dir(_Path.str()), Current(Begin), End(End), IterateExternalFS(IterateExternalFS), ExternalFS(ExternalFS) { EC = incrementImpl(/*IsFirstTime=*/true); @@ -2178,10 +2005,10 @@ llvm::sys::path::append(PathStr, (*Current)->getName()); sys::fs::file_type Type; switch ((*Current)->getKind()) { - case EK_Directory: + case RedirectingFileSystem::EK_Directory: Type = sys::fs::file_type::directory_file; break; - case EK_File: + case RedirectingFileSystem::EK_File: Type = sys::fs::file_type::regular_file; break; }