diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -506,10 +506,12 @@ struct YAMLVFSEntry { template - YAMLVFSEntry(T1 &&VPath, T2 &&RPath) - : VPath(std::forward(VPath)), RPath(std::forward(RPath)) {} + YAMLVFSEntry(T1 &&VPath, T2 &&RPath, bool IsDirectory = false) + : VPath(std::forward(VPath)), RPath(std::forward(RPath)), + IsDirectory(IsDirectory) {} std::string VPath; std::string RPath; + bool IsDirectory = false; }; class VFSFromYamlDirIterImpl; @@ -771,10 +773,13 @@ Optional UseExternalNames; std::string OverlayDir; + void addEntry(StringRef VirtualPath, StringRef RealPath, bool IsDirectory); + public: YAMLVFSWriter() = default; void addFileMapping(StringRef VirtualPath, StringRef RealPath); + void addDirectoryMapping(StringRef VirtualPath, StringRef RealPath); void setCaseSensitivity(bool CaseSensitive) { IsCaseSensitive = CaseSensitive; diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -1912,11 +1912,21 @@ return UniqueID(std::numeric_limits::max(), ID); } -void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) { +void YAMLVFSWriter::addEntry(StringRef VirtualPath, StringRef RealPath, + bool IsDirectory) { assert(sys::path::is_absolute(VirtualPath) && "virtual path not absolute"); assert(sys::path::is_absolute(RealPath) && "real path not absolute"); assert(!pathHasTraversal(VirtualPath) && "path traversal is not supported"); - Mappings.emplace_back(VirtualPath, RealPath); + Mappings.emplace_back(VirtualPath, RealPath, IsDirectory); +} + +void YAMLVFSWriter::addFileMapping(StringRef VirtualPath, StringRef RealPath) { + addEntry(VirtualPath, RealPath, /*IsDirectory=*/false); +} + +void YAMLVFSWriter::addDirectoryMapping(StringRef VirtualPath, + StringRef RealPath) { + addEntry(VirtualPath, RealPath, /*IsDirectory=*/true); } namespace { @@ -2017,7 +2027,10 @@ if (!Entries.empty()) { const YAMLVFSEntry &Entry = Entries.front(); - startDirectory(path::parent_path(Entry.VPath)); + bool first_entry_is_directory = Entry.IsDirectory; + StringRef Dir = + first_entry_is_directory ? Entry.VPath : path::parent_path(Entry.VPath); + startDirectory(Dir); StringRef RPath = Entry.RPath; if (UseOverlayRelative) { @@ -2027,13 +2040,18 @@ RPath = RPath.slice(OverlayDirLen, RPath.size()); } - writeEntry(path::filename(Entry.VPath), RPath); + if (!first_entry_is_directory) + writeEntry(path::filename(Entry.VPath), RPath); for (const auto &Entry : Entries.slice(1)) { - StringRef Dir = path::parent_path(Entry.VPath); - if (Dir == DirStack.back()) - OS << ",\n"; - else { + StringRef Dir = + Entry.IsDirectory ? Entry.VPath : path::parent_path(Entry.VPath); + if (Dir == DirStack.back()) { + if (!first_entry_is_directory) { + OS << ",\n"; + first_entry_is_directory = false; + } + } else { while (!DirStack.empty() && !containedIn(DirStack.back(), Dir)) { OS << "\n"; endDirectory(); diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -2200,20 +2200,14 @@ ScopedDir _g(TestDirectory + "/g"); ScopedFile _h(TestDirectory + "/h", ""); - // This test exposes a bug/shortcoming in the YAMLVFSWriter. Below we call - // addFileMapping for _a and _e, which causes _ab and _ef not to exists in - // the deserialized file system, because _a and _e got emitted as regular - // files. The counter example is _c, if we only call addFileMapping for _cd, - // things work as expected. - vfs::YAMLVFSWriter VFSWriter; - VFSWriter.addFileMapping(_a.Path, "//root/a"); + VFSWriter.addDirectoryMapping(_a.Path, "//root/a"); VFSWriter.addFileMapping(_ab.Path, "//root/a/b"); VFSWriter.addFileMapping(_cd.Path, "//root/c/d"); - VFSWriter.addFileMapping(_e.Path, "//root/e"); - VFSWriter.addFileMapping(_ef.Path, "//root/e/f"); + VFSWriter.addDirectoryMapping(_e.Path, "//root/e"); + VFSWriter.addDirectoryMapping(_ef.Path, "//root/e/f"); VFSWriter.addFileMapping(_g.Path, "//root/g"); - VFSWriter.addFileMapping(_h.Path, "//root/h"); + VFSWriter.addDirectoryMapping(_h.Path, "//root/h"); std::string Buffer; raw_string_ostream OS(Buffer); @@ -2236,11 +2230,11 @@ ASSERT_TRUE(FS.get() != nullptr); EXPECT_TRUE(FS->exists(_a.Path)); - EXPECT_FALSE(FS->exists(_ab.Path)); // FIXME: See explanation above. + EXPECT_TRUE(FS->exists(_ab.Path)); EXPECT_TRUE(FS->exists(_c.Path)); EXPECT_TRUE(FS->exists(_cd.Path)); EXPECT_TRUE(FS->exists(_e.Path)); - EXPECT_FALSE(FS->exists(_ef.Path)); // FIXME: See explanation above. + EXPECT_TRUE(FS->exists(_ef.Path)); EXPECT_TRUE(FS->exists(_g.Path)); EXPECT_TRUE(FS->exists(_h.Path)); }