diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp | 363 |
1 files changed, 302 insertions, 61 deletions
diff --git a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp index 6977f40..8ace2b3 100644 --- a/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp +++ b/contrib/llvm/tools/clang/lib/Basic/VirtualFileSystem.cpp @@ -16,13 +16,16 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" #include "llvm/Support/YAMLParser.h" -#include "llvm/Config/llvm-config.h" #include <atomic> #include <memory> +#include <utility> // For chdir. #ifdef LLVM_ON_WIN32 @@ -99,6 +102,9 @@ 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(); + auto WorkingDir = getCurrentWorkingDirectory(); if (!WorkingDir) return WorkingDir.getError(); @@ -111,6 +117,20 @@ bool FileSystem::exists(const Twine &Path) { return Status && Status->exists(); } +#ifndef NDEBUG +static bool isTraversalComponent(StringRef Component) { + return Component.equals("..") || Component.equals("."); +} + +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; + return false; +} +#endif + //===-----------------------------------------------------------------------===/ // RealFileSystem implementation //===-----------------------------------------------------------------------===/ @@ -120,16 +140,19 @@ namespace { class RealFile : public File { int FD; Status S; + std::string RealName; friend class RealFileSystem; - RealFile(int FD, StringRef NewName) + RealFile(int FD, StringRef NewName, StringRef NewRealPathName) : FD(FD), S(NewName, {}, {}, {}, {}, {}, - llvm::sys::fs::file_type::status_error, {}) { + llvm::sys::fs::file_type::status_error, {}), + RealName(NewRealPathName.str()) { assert(FD >= 0 && "Invalid or inactive file descriptor"); } public: ~RealFile() override; ErrorOr<Status> status() override; + ErrorOr<std::string> getName() override; ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, @@ -150,6 +173,10 @@ ErrorOr<Status> RealFile::status() { return S; } +ErrorOr<std::string> RealFile::getName() { + return RealName.empty() ? S.getName().str() : RealName; +} + ErrorOr<std::unique_ptr<MemoryBuffer>> RealFile::getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator, bool IsVolatile) { @@ -158,21 +185,10 @@ RealFile::getBuffer(const Twine &Name, int64_t FileSize, IsVolatile); } -// FIXME: This is terrible, we need this for ::close. -#if !defined(_MSC_VER) && !defined(__MINGW32__) -#include <unistd.h> -#include <sys/uio.h> -#else -#include <io.h> -#ifndef S_ISFIFO -#define S_ISFIFO(x) (0) -#endif -#endif std::error_code RealFile::close() { - if (::close(FD)) - return std::error_code(errno, std::generic_category()); + std::error_code EC = sys::Process::SafelyCloseFileDescriptor(FD); FD = -1; - return std::error_code(); + return EC; } namespace { @@ -198,9 +214,10 @@ ErrorOr<Status> RealFileSystem::status(const Twine &Path) { ErrorOr<std::unique_ptr<File>> RealFileSystem::openFileForRead(const Twine &Name) { int FD; - if (std::error_code EC = sys::fs::openFileForRead(Name, FD)) + SmallString<256> RealName; + if (std::error_code EC = sys::fs::openFileForRead(Name, FD, &RealName)) return EC; - return std::unique_ptr<File>(new RealFile(FD, Name.str())); + return std::unique_ptr<File>(new RealFile(FD, Name.str(), RealName.str())); } llvm::ErrorOr<std::string> RealFileSystem::getCurrentWorkingDirectory() const { @@ -271,7 +288,7 @@ directory_iterator RealFileSystem::dir_begin(const Twine &Dir, // OverlayFileSystem implementation //===-----------------------------------------------------------------------===/ OverlayFileSystem::OverlayFileSystem(IntrusiveRefCntPtr<FileSystem> BaseFS) { - FSList.push_back(BaseFS); + FSList.push_back(std::move(BaseFS)); } void OverlayFileSystem::pushOverlay(IntrusiveRefCntPtr<FileSystem> FS) { @@ -711,7 +728,13 @@ public: 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<Entry> Content) { + Contents.push_back(std::move(Content)); + } + Entry *getLastContent() const { return Contents.back().get(); } typedef decltype(Contents)::iterator iterator; iterator contents_begin() { return Contents.begin(); } iterator contents_end() { return Contents.end(); } @@ -739,6 +762,7 @@ public: return UseName == NK_NotSet ? GlobalUseExternalName : (UseName == NK_External); } + NameKind getUseName() const { return UseName; } static bool classof(const Entry *E) { return E->getKind() == EK_File; } }; @@ -776,6 +800,7 @@ public: /// All configuration options are optional. /// 'case-sensitive': <boolean, default=true> /// 'use-external-names': <boolean, default=true> +/// 'overlay-relative': <boolean, default=false> /// /// Virtual directories are represented as /// \verbatim @@ -815,6 +840,10 @@ class RedirectingFileSystem : public vfs::FileSystem { std::vector<std::unique_ptr<Entry>> Roots; /// \brief 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. + std::string ExternalContentsPrefixDir; /// @name Configuration /// @{ @@ -822,18 +851,32 @@ class RedirectingFileSystem : public vfs::FileSystem { /// \brief Whether to perform case-sensitive comparisons. /// /// Currently, case-insensitive matching only works correctly with ASCII. - bool CaseSensitive; + bool CaseSensitive = true; + + /// IsRelativeOverlay marks whether a IsExternalContentsPrefixDir path must + /// 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 /// names of files. This global value is overridable on a per-file basis. - bool UseExternalNames; + bool UseExternalNames = 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 LLVM_ON_WIN32 + false; +#else + true; +#endif + friend class RedirectingFileSystemParser; private: RedirectingFileSystem(IntrusiveRefCntPtr<FileSystem> ExternalFS) - : ExternalFS(ExternalFS), CaseSensitive(true), UseExternalNames(true) {} + : ExternalFS(std::move(ExternalFS)) {} /// \brief Looks up \p Path in \c Roots. ErrorOr<Entry *> lookupPath(const Twine &Path); @@ -851,8 +894,8 @@ public: /// returns a virtual file system representing its contents. static RedirectingFileSystem * create(std::unique_ptr<MemoryBuffer> Buffer, - SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext, - IntrusiveRefCntPtr<FileSystem> ExternalFS); + SourceMgr::DiagHandlerTy DiagHandler, StringRef YAMLFilePath, + void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS); ErrorOr<Status> status(const Twine &Path) override; ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override; @@ -885,6 +928,38 @@ public: return directory_iterator(std::make_shared<VFSFromYamlDirIterImpl>(Dir, *this, D->contents_begin(), D->contents_end(), EC)); } + + void setExternalContentsPrefixDir(StringRef PrefixDir) { + ExternalContentsPrefixDir = PrefixDir.str(); + } + + StringRef getExternalContentsPrefixDir() const { + return ExternalContentsPrefixDir; + } + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) +LLVM_DUMP_METHOD void dump() const { + for (const std::unique_ptr<Entry> &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<RedirectingDirectoryEntry>(E); + assert(DE && "Should be a directory"); + + for (std::unique_ptr<Entry> &SubEntry : + llvm::make_range(DE->contents_begin(), DE->contents_end())) + dumpEntry(SubEntry.get(), NumSpaces+2); + } + } +#endif + }; /// \brief A helper class to hold the common YAML parsing state. @@ -964,7 +1039,71 @@ class RedirectingFileSystemParser { return true; } - std::unique_ptr<Entry> parseEntry(yaml::Node *N) { + 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) { + if (Name.equals(Root->getName())) { + ParentEntry = Root.get(); + return ParentEntry; + } + } + } else { // Advance to the next component + auto *DE = dyn_cast<RedirectingDirectoryEntry>(ParentEntry); + for (std::unique_ptr<Entry> &Content : + llvm::make_range(DE->contents_begin(), DE->contents_end())) { + auto *DirContent = dyn_cast<RedirectingDirectoryEntry>(Content.get()); + if (DirContent && Name.equals(Content->getName())) + return DirContent; + } + } + + // ... or create a new one + std::unique_ptr<Entry> E = llvm::make_unique<RedirectingDirectoryEntry>( + Name, Status("", getNextVirtualUniqueID(), sys::TimeValue::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)); + ParentEntry = FS->Roots.back().get(); + return ParentEntry; + } + + auto *DE = dyn_cast<RedirectingDirectoryEntry>(ParentEntry); + DE->addContent(std::move(E)); + return DE->getLastContent(); + } + + void uniqueOverlayTree(RedirectingFileSystem *FS, Entry *SrcE, + Entry *NewParentE = nullptr) { + StringRef Name = SrcE->getName(); + switch (SrcE->getKind()) { + case EK_Directory: { + auto *DE = dyn_cast<RedirectingDirectoryEntry>(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<Entry> &SubEntry : + llvm::make_range(DE->contents_begin(), DE->contents_end())) + uniqueOverlayTree(FS, SubEntry.get(), NewParentE); + break; + } + case EK_File: { + auto *FE = dyn_cast<RedirectingFileEntry>(SrcE); + assert(FE && "Must be a file"); + assert(NewParentE && "Parent entry must exist"); + auto *DE = dyn_cast<RedirectingDirectoryEntry>(NewParentE); + DE->addContent(llvm::make_unique<RedirectingFileEntry>( + Name, FE->getExternalContentsPath(), FE->getUseName())); + break; + } + } + } + + std::unique_ptr<Entry> parseEntry(yaml::Node *N, RedirectingFileSystem *FS) { yaml::MappingNode *M = dyn_cast<yaml::MappingNode>(N); if (!M) { error(N, "expected mapping node for file or directory entry"); @@ -1004,7 +1143,17 @@ class RedirectingFileSystemParser { if (Key == "name") { if (!parseScalarString(I->getValue(), Value, Buffer)) return nullptr; - Name = Value; + + if (FS->UseCanonicalizedPaths) { + SmallString<256> Path(Value); + // Guarantee that old YAML files containing paths with ".." and "." + // are properly canonicalized before read into the VFS. + Path = sys::path::remove_leading_dotslash(Path); + sys::path::remove_dots(Path, /*remove_dot_dot=*/true); + Name = Path.str(); + } else { + Name = Value; + } } else if (Key == "type") { if (!parseScalarString(I->getValue(), Value, Buffer)) return nullptr; @@ -1034,7 +1183,7 @@ class RedirectingFileSystemParser { for (yaml::SequenceNode::iterator I = Contents->begin(), E = Contents->end(); I != E; ++I) { - if (std::unique_ptr<Entry> E = parseEntry(&*I)) + if (std::unique_ptr<Entry> E = parseEntry(&*I, FS)) EntryArrayContents.push_back(std::move(E)); else return nullptr; @@ -1048,7 +1197,24 @@ class RedirectingFileSystemParser { HasContents = true; if (!parseScalarString(I->getValue(), Value, Buffer)) return nullptr; - ExternalContentsPath = Value; + + SmallString<256> FullPath; + if (FS->IsRelativeOverlay) { + FullPath = FS->getExternalContentsPrefixDir(); + assert(!FullPath.empty() && + "External contents prefix directory must exist"); + llvm::sys::path::append(FullPath, Value); + } else { + FullPath = Value; + } + + if (FS->UseCanonicalizedPaths) { + // Guarantee that old YAML files containing paths with ".." and "." + // are properly canonicalized before read into the VFS. + FullPath = sys::path::remove_leading_dotslash(FullPath); + sys::path::remove_dots(FullPath, /*remove_dot_dot=*/true); + } + ExternalContentsPath = FullPath.str(); } else if (Key == "use-external-name") { bool Val; if (!parseScalarBool(I->getValue(), Val)) @@ -1134,10 +1300,12 @@ public: KeyStatusPair("version", true), KeyStatusPair("case-sensitive", false), KeyStatusPair("use-external-names", false), + KeyStatusPair("overlay-relative", false), KeyStatusPair("roots", true), }; DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields)); + std::vector<std::unique_ptr<Entry>> RootEntries; // Parse configuration and 'roots' for (yaml::MappingNode::iterator I = Top->begin(), E = Top->end(); I != E; @@ -1159,8 +1327,8 @@ public: for (yaml::SequenceNode::iterator I = Roots->begin(), E = Roots->end(); I != E; ++I) { - if (std::unique_ptr<Entry> E = parseEntry(&*I)) - FS->Roots.push_back(std::move(E)); + if (std::unique_ptr<Entry> E = parseEntry(&*I, FS)) + RootEntries.push_back(std::move(E)); else return false; } @@ -1185,6 +1353,9 @@ public: } else if (Key == "case-sensitive") { if (!parseScalarBool(I->getValue(), FS->CaseSensitive)) return false; + } else if (Key == "overlay-relative") { + if (!parseScalarBool(I->getValue(), FS->IsRelativeOverlay)) + return false; } else if (Key == "use-external-names") { if (!parseScalarBool(I->getValue(), FS->UseExternalNames)) return false; @@ -1198,6 +1369,13 @@ public: if (!checkMissingKeys(Top, Keys)) return false; + + // 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) + uniqueOverlayTree(FS, E.get()); + return true; } }; @@ -1205,9 +1383,11 @@ public: Entry::~Entry() = default; -RedirectingFileSystem *RedirectingFileSystem::create( - std::unique_ptr<MemoryBuffer> Buffer, SourceMgr::DiagHandlerTy DiagHandler, - void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS) { +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); @@ -1223,7 +1403,24 @@ RedirectingFileSystem *RedirectingFileSystem::create( RedirectingFileSystemParser P(Stream); std::unique_ptr<RedirectingFileSystem> FS( - new RedirectingFileSystem(ExternalFS)); + new RedirectingFileSystem(std::move(ExternalFS))); + + if (!YAMLFilePath.empty()) { + // Use the YAML path from -ivfsoverlay to compute the dir to be prefixed + // to each 'external-contents' path. + // + // Example: + // -ivfsoverlay dummy.cache/vfs/vfs.yaml + // yields: + // FS->ExternalContentsPrefixDir => /<absolute_path_to>/dummy.cache/vfs + // + SmallString<256> OverlayAbsDir = sys::path::parent_path(YAMLFilePath); + std::error_code EC = llvm::sys::fs::make_absolute(OverlayAbsDir); + assert(!EC && "Overlay dir final path must be absolute"); + (void)EC; + FS->setExternalContentsPrefixDir(OverlayAbsDir); + } + if (!P.parse(Root, FS.get())) return nullptr; @@ -1238,6 +1435,14 @@ ErrorOr<Entry *> RedirectingFileSystem::lookupPath(const Twine &Path_) { if (std::error_code EC = makeAbsolute(Path)) return EC; + // Canonicalize path by removing ".", "..", "./", etc components. This is + // a VFS request, do bot bother about symlinks in the path components + // but canonicalize in order to perform the correct entry search. + if (UseCanonicalizedPaths) { + Path = sys::path::remove_leading_dotslash(Path); + sys::path::remove_dots(Path, /*remove_dot_dot=*/true); + } + if (Path.empty()) return make_error_code(llvm::errc::invalid_argument); @@ -1254,20 +1459,32 @@ 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 + assert(!isTraversalComponent(*Start) && + !isTraversalComponent(From->getName()) && + "Paths should not contain traversal components"); +#else + // FIXME: this is here to support windows, remove it once canonicalized + // paths become globally default. if (Start->equals(".")) ++Start; +#endif - // FIXME: handle .. - if (CaseSensitive ? !Start->equals(From->getName()) - : !Start->equals_lower(From->getName())) - // failure to match - return make_error_code(llvm::errc::no_such_file_or_directory); + StringRef FromName = From->getName(); - ++Start; + // Forward the search to the next component in case this is an empty one. + if (!FromName.empty()) { + if (CaseSensitive ? !Start->equals(FromName) + : !Start->equals_lower(FromName)) + // failure to match + return make_error_code(llvm::errc::no_such_file_or_directory); - if (Start == End) { - // Match! - return From; + ++Start; + + if (Start == End) { + // Match! + return From; + } } auto *DE = dyn_cast<RedirectingDirectoryEntry>(From); @@ -1322,7 +1539,7 @@ class FileWithFixedStatus : public File { public: FileWithFixedStatus(std::unique_ptr<File> InnerFile, Status S) - : InnerFile(std::move(InnerFile)), S(S) {} + : InnerFile(std::move(InnerFile)), S(std::move(S)) {} ErrorOr<Status> status() override { return S; } ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> @@ -1362,10 +1579,13 @@ RedirectingFileSystem::openFileForRead(const Twine &Path) { IntrusiveRefCntPtr<FileSystem> vfs::getVFSFromYAML(std::unique_ptr<MemoryBuffer> Buffer, - SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext, + SourceMgr::DiagHandlerTy DiagHandler, + StringRef YAMLFilePath, + void *DiagContext, IntrusiveRefCntPtr<FileSystem> ExternalFS) { return RedirectingFileSystem::create(std::move(Buffer), DiagHandler, - DiagContext, ExternalFS); + YAMLFilePath, DiagContext, + std::move(ExternalFS)); } UniqueID vfs::getNextVirtualUniqueID() { @@ -1376,16 +1596,6 @@ UniqueID vfs::getNextVirtualUniqueID() { return UniqueID(std::numeric_limits<uint64_t>::max(), ID); } -#ifndef NDEBUG -static bool pathHasTraversal(StringRef Path) { - using namespace llvm::sys; - for (StringRef Comp : llvm::make_range(path::begin(Path), path::end(Path))) - if (Comp == "." || Comp == "..") - return true; - return false; -} -#endif - void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) { assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute"); assert(sys::path::is_absolute(RealPath) && "real path not absolute"); @@ -1407,7 +1617,9 @@ class JSONWriter { public: JSONWriter(llvm::raw_ostream &OS) : OS(OS) {} - void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> IsCaseSensitive); + void write(ArrayRef<YAMLVFSEntry> Entries, Optional<bool> UseExternalNames, + Optional<bool> IsCaseSensitive, Optional<bool> IsOverlayRelative, + StringRef OverlayDir); }; } @@ -1460,7 +1672,10 @@ void JSONWriter::writeEntry(StringRef VPath, StringRef RPath) { } void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries, - Optional<bool> IsCaseSensitive) { + Optional<bool> UseExternalNames, + Optional<bool> IsCaseSensitive, + Optional<bool> IsOverlayRelative, + StringRef OverlayDir) { using namespace llvm::sys; OS << "{\n" @@ -1468,12 +1683,30 @@ void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries, if (IsCaseSensitive.hasValue()) OS << " 'case-sensitive': '" << (IsCaseSensitive.getValue() ? "true" : "false") << "',\n"; + if (UseExternalNames.hasValue()) + OS << " 'use-external-names': '" + << (UseExternalNames.getValue() ? "true" : "false") << "',\n"; + bool UseOverlayRelative = false; + if (IsOverlayRelative.hasValue()) { + UseOverlayRelative = IsOverlayRelative.getValue(); + OS << " 'overlay-relative': '" + << (UseOverlayRelative ? "true" : "false") << "',\n"; + } OS << " 'roots': [\n"; if (!Entries.empty()) { const YAMLVFSEntry &Entry = Entries.front(); startDirectory(path::parent_path(Entry.VPath)); - writeEntry(path::filename(Entry.VPath), Entry.RPath); + + StringRef RPath = Entry.RPath; + if (UseOverlayRelative) { + unsigned OverlayDirLen = OverlayDir.size(); + assert(RPath.substr(0, OverlayDirLen) == OverlayDir && + "Overlay dir must be contained in RPath"); + RPath = RPath.slice(OverlayDirLen, RPath.size()); + } + + writeEntry(path::filename(Entry.VPath), RPath); for (const auto &Entry : Entries.slice(1)) { StringRef Dir = path::parent_path(Entry.VPath); @@ -1487,7 +1720,14 @@ void JSONWriter::write(ArrayRef<YAMLVFSEntry> Entries, OS << ",\n"; startDirectory(Dir); } - writeEntry(path::filename(Entry.VPath), Entry.RPath); + StringRef RPath = Entry.RPath; + if (UseOverlayRelative) { + unsigned OverlayDirLen = OverlayDir.size(); + assert(RPath.substr(0, OverlayDirLen) == OverlayDir && + "Overlay dir must be contained in RPath"); + RPath = RPath.slice(OverlayDirLen, RPath.size()); + } + writeEntry(path::filename(Entry.VPath), RPath); } while (!DirStack.empty()) { @@ -1507,7 +1747,8 @@ void YAMLVFSWriter::write(llvm::raw_ostream &OS) { return LHS.VPath < RHS.VPath; }); - JSONWriter(OS).write(Mappings, IsCaseSensitive); + JSONWriter(OS).write(Mappings, UseExternalNames, IsCaseSensitive, + IsOverlayRelative, OverlayDir); } VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl( |