bnbarham updated this revision to Diff 415615.
bnbarham edited the summary of this revision.
bnbarham added a comment.
Herald added subscribers: cfe-commits, lldb-commits, carlosgalvezp.
Herald added projects: clang, LLDB, clang-tools-extra.
Re-order to be before D121424 <https://reviews.llvm.org/D121424> and merge with
D121426 <https://reviews.llvm.org/D121426>
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D121425/new/
https://reviews.llvm.org/D121425
Files:
clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/test/VFS/Inputs/vfsroot.yaml
clang/test/VFS/directory.c
clang/test/VFS/multiple-overlays.c
clang/test/VFS/vfsroot-with-overlay.c
lldb/source/Commands/CommandObjectReproducer.cpp
llvm/include/llvm/Support/VirtualFileSystem.h
llvm/lib/Support/VirtualFileSystem.cpp
llvm/tools/dsymutil/Reproducer.cpp
llvm/tools/dsymutil/Reproducer.h
llvm/unittests/Support/VirtualFileSystemTest.cpp
Index: llvm/unittests/Support/VirtualFileSystemTest.cpp
===================================================================
--- llvm/unittests/Support/VirtualFileSystemTest.cpp
+++ llvm/unittests/Support/VirtualFileSystemTest.cpp
@@ -14,6 +14,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Testing/Support/Error.h"
#include "llvm/Testing/Support/SupportHelpers.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -2571,7 +2572,7 @@
}
TEST_F(VFSFromYAMLTest, WorkingDirectory) {
- IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
+ IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
Lower->addDirectory("//root/");
Lower->addDirectory("//root/foo");
Lower->addRegularFile("//root/foo/a");
@@ -2593,6 +2594,7 @@
"}",
Lower);
ASSERT_NE(FS.get(), nullptr);
+
std::error_code EC = FS->setCurrentWorkingDirectory("//root/bar");
ASSERT_FALSE(EC);
@@ -2621,6 +2623,14 @@
ASSERT_TRUE(WorkingDir);
EXPECT_EQ(*WorkingDir, "//root/");
+ Status = FS->status("bar/a");
+ ASSERT_FALSE(Status.getError());
+ EXPECT_TRUE(Status->exists());
+
+ Status = FS->status("foo/a");
+ ASSERT_FALSE(Status.getError());
+ EXPECT_TRUE(Status->exists());
+
EC = FS->setCurrentWorkingDirectory("bar");
ASSERT_FALSE(EC);
WorkingDir = FS->getCurrentWorkingDirectory();
@@ -2710,43 +2720,6 @@
EXPECT_TRUE(Status->exists());
}
-TEST_F(VFSFromYAMLTest, WorkingDirectoryFallthroughInvalid) {
- IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
- Lower->addDirectory("//root/");
- Lower->addDirectory("//root/foo");
- Lower->addRegularFile("//root/foo/a");
- Lower->addRegularFile("//root/foo/b");
- Lower->addRegularFile("//root/c");
- IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
- "{ 'use-external-names': false,\n"
- " 'roots': [\n"
- "{\n"
- " 'type': 'directory',\n"
- " 'name': '//root/bar',\n"
- " 'contents': [ {\n"
- " 'type': 'file',\n"
- " 'name': 'a',\n"
- " 'external-contents': '//root/foo/a'\n"
- " }\n"
- " ]\n"
- "}\n"
- "]\n"
- "}",
- Lower);
- ASSERT_NE(FS.get(), nullptr);
- std::error_code EC = FS->setCurrentWorkingDirectory("//root/");
- ASSERT_FALSE(EC);
- ASSERT_NE(FS.get(), nullptr);
-
- llvm::ErrorOr<vfs::Status> Status = FS->status("bar/a");
- ASSERT_FALSE(Status.getError());
- EXPECT_TRUE(Status->exists());
-
- Status = FS->status("foo/a");
- ASSERT_FALSE(Status.getError());
- EXPECT_TRUE(Status->exists());
-}
-
TEST_F(VFSFromYAMLTest, VirtualWorkingDirectory) {
IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
Lower->addDirectory("//root/");
@@ -3207,3 +3180,168 @@
" DummyFileSystem (RecursiveContents)\n",
Output);
}
+
+static std::unique_ptr<vfs::OverlayFileSystem>
+getVFSOrNull(ArrayRef<std::string> YAMLOverlays,
+ IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
+ SmallVector<MemoryBufferRef> OverlayRefs;
+ for (const auto &Overlay : YAMLOverlays) {
+ OverlayRefs.emplace_back(Overlay, "");
+ }
+
+ auto ExpectedFS = vfs::getVFSFromYAMLs(OverlayRefs, ExternalFS);
+ if (auto Err = ExpectedFS.takeError()) {
+ consumeError(std::move(Err));
+ return nullptr;
+ }
+ return std::move(*ExpectedFS);
+}
+
+static std::string createSimpleOverlay(StringRef RedirectKind, StringRef From,
+ StringRef To) {
+ return ("{\n"
+ " 'version': 0,\n"
+ " 'redirecting-with': '" +
+ RedirectKind +
+ "'\n"
+ " 'roots': [\n"
+ " {\n"
+ " 'type': 'directory-remap',\n"
+ " 'name': '" +
+ From +
+ "',\n"
+ " 'external-contents': '" +
+ To +
+ "',\n"
+ " }]\n"
+ " }"
+ " ]")
+ .str();
+}
+
+// Make sure that overlays are not transitive. Given A -> B and B -> C, if a
+// file in A is requested, it should not end up mapping to C.
+TEST(VFSFromYAMLsTest, NotTransitive) {
+ auto C = makeIntrusiveRefCnt<DummyFileSystem>();
+ C->addDirectory("/real/c");
+ C->addRegularFile("/real/c/f");
+
+ SmallVector<std::string> Overlays;
+ Overlays.push_back(createSimpleOverlay("fallthrough", "/b", "/real/c"));
+ Overlays.push_back(createSimpleOverlay("fallthrough", "/a", "/b"));
+ auto FS = getVFSOrNull(Overlays, C);
+ ASSERT_TRUE(FS);
+
+ EXPECT_PATHS(*FS, "/b/f", "/real/c/f", "/real/c/f");
+ auto S = FS->status("/b/f");
+ ASSERT_FALSE(S.getError());
+ EXPECT_EQ("/real/c/f", S->getName());
+
+ EXPECT_TRUE(FS->status("/a/f").getError());
+}
+
+// When fallback is the first overlay, the external FS should be checked before
+// it. Given B -> A, A should only be used if the file does not exist in B.
+TEST(VFSFromYAMLsTest, FallbackChecksExternalFirst) {
+ auto AOnly = makeIntrusiveRefCnt<DummyFileSystem>();
+ AOnly->addDirectory("/a");
+ AOnly->addRegularFile("/a/f");
+
+ auto BOnly = makeIntrusiveRefCnt<DummyFileSystem>();
+ BOnly->addDirectory("/b");
+ BOnly->addRegularFile("/b/f");
+
+ auto Both = makeIntrusiveRefCnt<DummyFileSystem>();
+ Both->addDirectory("/a");
+ Both->addRegularFile("/a/f");
+ Both->addDirectory("/b");
+ Both->addRegularFile("/b/f");
+
+ auto FallbackOverlay = createSimpleOverlay("fallback", "/b", "/a");
+
+ auto FS = getVFSOrNull(FallbackOverlay, AOnly);
+ ASSERT_TRUE(FS);
+ EXPECT_PATHS(*FS, "/b/f", "/a/f", "/a/f");
+
+ FS = getVFSOrNull(FallbackOverlay, BOnly);
+ ASSERT_TRUE(FS);
+ EXPECT_PATHS(*FS, "/b/f", "/b/f", "/b/f");
+
+ FS = getVFSOrNull(FallbackOverlay, Both);
+ ASSERT_TRUE(FS);
+ EXPECT_PATHS(*FS, "/b/f", "/b/f", "/b/f");
+}
+
+// Ensure the last overlay with redirect-only specified is the final FS
+TEST(VFSFromYAMLsTest, RedirectOnlyIsFinalFS) {
+ auto Real = makeIntrusiveRefCnt<DummyFileSystem>();
+ Real->addDirectory("/real");
+ Real->addRegularFile("/real/f");
+ Real->setCurrentWorkingDirectory("/real");
+
+ SmallVector<std::string> Overlays;
+ Overlays.push_back(createSimpleOverlay("redirect-only", "/ro1", "/real"));
+ Overlays.push_back(createSimpleOverlay("fallthrough", "/ft1", "/real"));
+ Overlays.push_back(createSimpleOverlay("redirect-only", "/ro2", "/real"));
+ Overlays.push_back(createSimpleOverlay("fallback", "/fb", "/real"));
+ Overlays.push_back(createSimpleOverlay("fallthrough", "/ft2", "/real"));
+ auto FS = getVFSOrNull(Overlays, Real);
+ ASSERT_TRUE(FS);
+
+ // Should have the same CWD as the external FS we passed down, even if that
+ // FS isn't actually being used in the overlay any more.
+ auto CWD = FS->getCurrentWorkingDirectory();
+ ASSERT_FALSE(CWD.getError());
+ EXPECT_EQ(*CWD, "/real");
+
+ // Only //ft2/f and //ro2/f should be valid:
+ // - //ro1 and //ft1 are specified before //ro2 so never run
+ // - //fb is specified after, but it's set to fallback and hence //ro2
+ // should run first (and not continue)
+
+ EXPECT_TRUE(FS->status("/ro1/f").getError());
+ EXPECT_TRUE(FS->status("/ft1/f").getError());
+ EXPECT_TRUE(FS->status("/fb/f").getError());
+
+ EXPECT_PATHS(*FS, "/ro2/f", "/real/f", "/real/f");
+ EXPECT_PATHS(*FS, "/ft2/f", "/real/f", "/real/f");
+}
+
+// Ensure overlays are read from the OverlayFS built so far
+TEST(VFSFromYAMLsTest, OverlayFromVFS) {
+ std::string FT1 = createSimpleOverlay("fallthrough", "/vfs1", "/a");
+ std::string FT2 = createSimpleOverlay("fallthrough", "/vfs2", "/b");
+ std::string FT3 = createSimpleOverlay("fallthrough", "/vfs3", "/c");
+ std::string RO = createSimpleOverlay("redirect-only", "/vfs", "/a");
+
+ auto Real = makeIntrusiveRefCnt<vfs::InMemoryFileSystem>();
+ Real->addFile("/ft1.yaml", 0, MemoryBuffer::getMemBuffer(FT1));
+ Real->addFile("/ft2.yaml", 0, MemoryBuffer::getMemBuffer(FT2));
+ Real->addFile("/a/ft3.yaml", 0, MemoryBuffer::getMemBuffer(FT3));
+ Real->addFile("/ro.yaml", 0, MemoryBuffer::getMemBuffer(RO));
+ Real->addFile("/a/f", 0, MemoryBuffer::getMemBuffer("a"));
+ Real->addFile("/b/f", 0, MemoryBuffer::getMemBuffer("b"));
+ Real->addFile("/c/f", 0, MemoryBuffer::getMemBuffer("c"));
+ Real->setCurrentWorkingDirectory("/");
+
+ // 3 to check we're not just using the last overlay
+ auto ExpectedFS =
+ vfs::getVFSFromYAMLs({"/ft1.yaml", "/ft2.yaml", "/vfs1/ft3.yaml"}, Real);
+ ASSERT_THAT_EXPECTED(ExpectedFS, Succeeded());
+ auto FS = std::move(*ExpectedFS);
+ FS->print(llvm::errs(), vfs::FileSystem::PrintType::RecursiveContents);
+ ASSERT_TRUE(FS);
+ EXPECT_PATHS(*FS, "/vfs1/f", "/a/f", "/a/f");
+ EXPECT_PATHS(*FS, "/vfs2/f", "/b/f", "/b/f");
+ EXPECT_PATHS(*FS, "/vfs3/f", "/c/f", "/c/f");
+
+ // If redirect-only is given, any further overlays *must* be specified by it
+ ExpectedFS = vfs::getVFSFromYAMLs({"/ro.yaml", "/a/ft3.yaml"}, Real);
+ EXPECT_THAT_EXPECTED(ExpectedFS, Failed());
+
+ ExpectedFS = vfs::getVFSFromYAMLs({"/ro.yaml", "/vfs/ft3.yaml"}, Real);
+ ASSERT_THAT_EXPECTED(ExpectedFS, Succeeded());
+ FS = std::move(*ExpectedFS);
+ ASSERT_TRUE(FS);
+ EXPECT_PATHS(*FS, "/vfs/f", "/a/f", "/a/f");
+}
Index: llvm/tools/dsymutil/Reproducer.h
===================================================================
--- llvm/tools/dsymutil/Reproducer.h
+++ llvm/tools/dsymutil/Reproducer.h
@@ -59,8 +59,7 @@
};
/// Reproducer instance used to use an existing reproducer. The VFS returned by
-/// this instance is a RedirectingFileSystem that remaps paths to their
-/// counterpart in the reproducer.
+/// this instance remaps paths to their counterpart in the reproducer.
class ReproducerUse : public Reproducer {
public:
ReproducerUse(StringRef Root, std::error_code &EC);
Index: llvm/tools/dsymutil/Reproducer.cpp
===================================================================
--- llvm/tools/dsymutil/Reproducer.cpp
+++ llvm/tools/dsymutil/Reproducer.cpp
@@ -48,15 +48,15 @@
ReproducerUse::ReproducerUse(StringRef Root, std::error_code &EC) {
SmallString<128> Mapping(Root);
sys::path::append(Mapping, "mapping.yaml");
- ErrorOr<std::unique_ptr<MemoryBuffer>> Buffer =
- vfs::getRealFileSystem()->getBufferForFile(Mapping.str());
- if (!Buffer) {
- EC = Buffer.getError();
+ auto OverlayFS = llvm::vfs::getVFSFromYAMLs(Mapping.str());
+ if (auto Err = OverlayFS.takeError()) {
+ llvm::handleAllErrors(std::move(Err), [&](const llvm::ErrorInfoBase &E) {
+ EC = E.convertToErrorCode();
+ });
return;
}
-
- VFS = llvm::vfs::getVFSFromYAML(std::move(Buffer.get()), nullptr, Mapping);
+ VFS = std::move(*OverlayFS);
}
llvm::Expected<std::unique_ptr<Reproducer>>
Index: llvm/lib/Support/VirtualFileSystem.cpp
===================================================================
--- llvm/lib/Support/VirtualFileSystem.cpp
+++ llvm/lib/Support/VirtualFileSystem.cpp
@@ -1461,14 +1461,6 @@
return Combined;
}
-void RedirectingFileSystem::setExternalContentsPrefixDir(StringRef PrefixDir) {
- ExternalContentsPrefixDir = PrefixDir.str();
-}
-
-StringRef RedirectingFileSystem::getExternalContentsPrefixDir() const {
- return ExternalContentsPrefixDir;
-}
-
void RedirectingFileSystem::setFallthrough(bool Fallthrough) {
if (Fallthrough) {
Redirection = RedirectingFileSystem::RedirectKind::Fallthrough;
@@ -1546,6 +1538,41 @@
void RedirectingFileSystem::dump() const { print(dbgs()); }
#endif
+namespace {
+
+struct YAMLParseResult {
+ /// The way in which this VFS should be added to an overlay. Note that the
+ /// order is right to left - given [A, B, C], any FS operations run on C
+ /// *first* and if failing, B, followed by A.
+ enum class RedirectKind {
+ /// Allow "falling through" to the next (ie. to the left) VFS.
+ Fallthrough,
+ /// Run any operations on the next VFS *first*, using this VFS as a
+ /// "fallback".
+ Fallback,
+ /// Do not perform any more operations on further VFS.
+ RedirectOnly
+ };
+
+ std::unique_ptr<RedirectingFileSystem> FS;
+ RedirectKind Redirection;
+
+ // TODO: Remove after simplifying RedirectingFileSystem
+ static RedirectingFileSystem::RedirectKind
+ toRFSKind(RedirectKind Redirection) {
+ switch (Redirection) {
+ case RedirectKind::Fallthrough:
+ return RedirectingFileSystem::RedirectKind::Fallthrough;
+ case RedirectKind::Fallback:
+ return RedirectingFileSystem::RedirectKind::Fallback;
+ case RedirectKind::RedirectOnly:
+ return RedirectingFileSystem::RedirectKind::RedirectOnly;
+ }
+ }
+};
+
+} // namespace
+
/// A helper class to hold the common YAML parsing state.
class llvm::vfs::RedirectingFileSystemParser {
yaml::Stream &Stream;
@@ -1587,19 +1614,18 @@
return false;
}
- Optional<RedirectingFileSystem::RedirectKind>
- parseRedirectKind(yaml::Node *N) {
+ Optional<YAMLParseResult::RedirectKind> parseRedirectKind(yaml::Node *N) {
SmallString<12> Storage;
StringRef Value;
if (!parseScalarString(N, Value, Storage))
return None;
if (Value.equals_insensitive("fallthrough")) {
- return RedirectingFileSystem::RedirectKind::Fallthrough;
+ return YAMLParseResult::RedirectKind::Fallthrough;
} else if (Value.equals_insensitive("fallback")) {
- return RedirectingFileSystem::RedirectKind::Fallback;
+ return YAMLParseResult::RedirectKind::Fallback;
} else if (Value.equals_insensitive("redirect-only")) {
- return RedirectingFileSystem::RedirectKind::RedirectOnly;
+ return YAMLParseResult::RedirectKind::RedirectOnly;
}
return None;
}
@@ -1642,10 +1668,10 @@
public:
static RedirectingFileSystem::Entry *
- lookupOrCreateEntry(RedirectingFileSystem *FS, StringRef Name,
+ lookupOrCreateEntry(RedirectingFileSystem &FS, StringRef Name,
RedirectingFileSystem::Entry *ParentEntry = nullptr) {
if (!ParentEntry) { // Look for a existent root
- for (const auto &Root : FS->Roots) {
+ for (const auto &Root : FS.Roots) {
if (Name.equals(Root->getName())) {
ParentEntry = Root.get();
return ParentEntry;
@@ -1670,8 +1696,8 @@
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();
+ FS.Roots.push_back(std::move(E));
+ ParentEntry = FS.Roots.back().get();
return ParentEntry;
}
@@ -1681,7 +1707,7 @@
}
private:
- void uniqueOverlayTree(RedirectingFileSystem *FS,
+ void uniqueOverlayTree(RedirectingFileSystem &FS,
RedirectingFileSystem::Entry *SrcE,
RedirectingFileSystem::Entry *NewParentE = nullptr) {
StringRef Name = SrcE->getName();
@@ -1719,7 +1745,8 @@
}
std::unique_ptr<RedirectingFileSystem::Entry>
- parseEntry(yaml::Node *N, RedirectingFileSystem *FS, bool IsRootEntry) {
+ parseEntry(yaml::Node *N, bool IsRelativeOverlay,
+ StringRef ExternalContentsPrefixDir, bool IsRootEntry) {
auto *M = dyn_cast<yaml::MappingNode>(N);
if (!M) {
error(N, "expected mapping node for file or directory entry");
@@ -1794,7 +1821,8 @@
for (auto &I : *Contents) {
if (std::unique_ptr<RedirectingFileSystem::Entry> E =
- parseEntry(&I, FS, /*IsRootEntry*/ false))
+ parseEntry(&I, IsRelativeOverlay, ExternalContentsPrefixDir,
+ /*IsRootEntry=*/false))
EntryArrayContents.push_back(std::move(E));
else
return nullptr;
@@ -1810,8 +1838,8 @@
return nullptr;
SmallString<256> FullPath;
- if (FS->IsRelativeOverlay) {
- FullPath = FS->getExternalContentsPrefixDir();
+ if (IsRelativeOverlay) {
+ FullPath.append(ExternalContentsPrefixDir);
assert(!FullPath.empty() &&
"External contents prefix directory must exist");
llvm::sys::path::append(FullPath, Value);
@@ -1933,12 +1961,45 @@
public:
RedirectingFileSystemParser(yaml::Stream &S) : Stream(S) {}
- // false on error
- bool parse(yaml::Node *Root, RedirectingFileSystem *FS) {
+ static Optional<YAMLParseResult>
+ parse(MemoryBufferRef Buffer, SourceMgr &SM,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS) {
+ yaml::Stream Stream(Buffer, SM);
+ yaml::document_iterator DI = Stream.begin();
+ yaml::Node *Root = DI->getRoot();
+ if (DI == Stream.end() || !Root) {
+ SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
+ return None;
+ }
+
+ SmallString<256> ExternalContentsPrefixDir;
+ if (!Buffer.getBufferIdentifier().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
+ //
+ ExternalContentsPrefixDir =
+ sys::path::parent_path(Buffer.getBufferIdentifier());
+ std::error_code EC = ExternalFS->makeAbsolute(ExternalContentsPrefixDir);
+ assert(!EC && "Overlay dir final path must be absolute");
+ (void)EC;
+ }
+
+ RedirectingFileSystemParser P(Stream);
+ return P.parse(Root, ExternalContentsPrefixDir, std::move(ExternalFS));
+ }
+
+ Optional<YAMLParseResult> parse(yaml::Node *Root,
+ StringRef ExternalContentsPrefixDir,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS) {
auto *Top = dyn_cast<yaml::MappingNode>(Root);
if (!Top) {
error(Root, "expected mapping node");
- return false;
+ return None;
}
KeyStatusPair Fields[] = {
@@ -1954,85 +2015,101 @@
DenseMap<StringRef, KeyStatus> Keys(std::begin(Fields), std::end(Fields));
std::vector<std::unique_ptr<RedirectingFileSystem::Entry>> RootEntries;
+ bool IsRelativeOverlay = false;
+ YAMLParseResult Result{std::unique_ptr<RedirectingFileSystem>(
+ new RedirectingFileSystem(ExternalFS)),
+ YAMLParseResult::RedirectKind::Fallthrough};
+ if (auto CWD = ExternalFS->getCurrentWorkingDirectory())
+ Result.FS->setCurrentWorkingDirectory(*CWD);
+
// Parse configuration and 'roots'
for (auto &I : *Top) {
SmallString<10> KeyBuffer;
StringRef Key;
if (!parseScalarString(I.getKey(), Key, KeyBuffer))
- return false;
+ return None;
if (!checkDuplicateOrUnknownKey(I.getKey(), Key, Keys))
- return false;
+ return None;
if (Key == "roots") {
auto *Roots = dyn_cast<yaml::SequenceNode>(I.getValue());
if (!Roots) {
error(I.getValue(), "expected array");
- return false;
+ return None;
}
for (auto &I : *Roots) {
if (std::unique_ptr<RedirectingFileSystem::Entry> E =
- parseEntry(&I, FS, /*IsRootEntry*/ true))
+ parseEntry(&I, IsRelativeOverlay, ExternalContentsPrefixDir,
+ /*IsRootEntry=*/true))
RootEntries.push_back(std::move(E));
else
- return false;
+ return None;
}
} else if (Key == "version") {
StringRef VersionString;
SmallString<4> Storage;
if (!parseScalarString(I.getValue(), VersionString, Storage))
- return false;
+ return None;
int Version;
if (VersionString.getAsInteger<int>(10, Version)) {
error(I.getValue(), "expected integer");
- return false;
+ return None;
}
if (Version < 0) {
error(I.getValue(), "invalid version number");
- return false;
+ return None;
}
if (Version != 0) {
error(I.getValue(), "version mismatch, expected 0");
- return false;
+ return None;
}
} else if (Key == "case-sensitive") {
- if (!parseScalarBool(I.getValue(), FS->CaseSensitive))
- return false;
+ if (!parseScalarBool(I.getValue(), Result.FS->CaseSensitive))
+ return None;
} else if (Key == "overlay-relative") {
- if (!parseScalarBool(I.getValue(), FS->IsRelativeOverlay))
- return false;
+ if (!parseScalarBool(I.getValue(), IsRelativeOverlay))
+ return None;
} else if (Key == "use-external-names") {
- if (!parseScalarBool(I.getValue(), FS->UseExternalNames))
- return false;
+ if (!parseScalarBool(I.getValue(), Result.FS->UseExternalNames))
+ return None;
} else if (Key == "fallthrough") {
if (Keys["redirecting-with"].Seen) {
error(I.getValue(),
"'fallthrough' and 'redirecting-with' are mutually exclusive");
- return false;
+ return None;
}
bool ShouldFallthrough = false;
if (!parseScalarBool(I.getValue(), ShouldFallthrough))
- return false;
+ return None;
if (ShouldFallthrough) {
- FS->Redirection = RedirectingFileSystem::RedirectKind::Fallthrough;
+ Result.Redirection = YAMLParseResult::RedirectKind::Fallthrough;
+ // TODO: Remove after simplifying RedirectingFileSystem
+ Result.FS->Redirection =
+ RedirectingFileSystem::RedirectKind::Fallthrough;
} else {
- FS->Redirection = RedirectingFileSystem::RedirectKind::RedirectOnly;
+ Result.Redirection = YAMLParseResult::RedirectKind::RedirectOnly;
+ // TODO: Remove after simplifying RedirectingFileSystem
+ Result.FS->Redirection =
+ RedirectingFileSystem::RedirectKind::RedirectOnly;
}
} else if (Key == "redirecting-with") {
if (Keys["fallthrough"].Seen) {
error(I.getValue(),
"'fallthrough' and 'redirecting-with' are mutually exclusive");
- return false;
+ return None;
}
if (auto Kind = parseRedirectKind(I.getValue())) {
- FS->Redirection = *Kind;
+ Result.Redirection = *Kind;
+ // TODO: Remove after simplifying RedirectingFileSystem
+ Result.FS->Redirection = YAMLParseResult::toRFSKind(*Kind);
} else {
error(I.getValue(), "expected valid redirect kind");
- return false;
+ return None;
}
} else {
llvm_unreachable("key missing from Keys");
@@ -2040,18 +2117,18 @@
}
if (Stream.failed())
- return false;
+ return None;
if (!checkMissingKeys(Top, Keys))
- return false;
+ return None;
// 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 (auto &E : RootEntries)
- uniqueOverlayTree(FS, E.get());
+ uniqueOverlayTree(*Result.FS, E.get());
- return true;
+ return Result;
}
};
@@ -2061,41 +2138,12 @@
StringRef YAMLFilePath, void *DiagContext,
IntrusiveRefCntPtr<FileSystem> ExternalFS) {
SourceMgr SM;
- yaml::Stream Stream(Buffer->getMemBufferRef(), SM);
-
SM.setDiagHandler(DiagHandler, DiagContext);
- yaml::document_iterator DI = Stream.begin();
- yaml::Node *Root = DI->getRoot();
- if (DI == Stream.end() || !Root) {
- SM.PrintMessage(SMLoc(), SourceMgr::DK_Error, "expected root node");
- return nullptr;
- }
-
- RedirectingFileSystemParser P(Stream);
-
- std::unique_ptr<RedirectingFileSystem> FS(
- new RedirectingFileSystem(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;
- return FS;
+ if (Optional<YAMLParseResult> Result = RedirectingFileSystemParser::parse(
+ Buffer->getMemBufferRef(), SM, std::move(ExternalFS)))
+ return std::move(Result->FS);
+ return nullptr;
}
std::unique_ptr<RedirectingFileSystem> RedirectingFileSystem::create(
@@ -2128,8 +2176,8 @@
for (auto I = llvm::sys::path::begin(FromDirectory),
E = llvm::sys::path::end(FromDirectory);
I != E; ++I) {
- Parent = RedirectingFileSystemParser::lookupOrCreateEntry(FS.get(), *I,
- Parent);
+ Parent =
+ RedirectingFileSystemParser::lookupOrCreateEntry(*FS, *I, Parent);
}
assert(Parent && "File without a directory?");
{
@@ -2325,8 +2373,8 @@
: InnerFile(std::move(InnerFile)), S(std::move(S)) {}
ErrorOr<Status> status() override { return S; }
- ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
+ ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
bool IsVolatile) override {
return InnerFile->getBuffer(Name, FileSize, RequiresNullTerminator,
@@ -2471,9 +2519,135 @@
SourceMgr::DiagHandlerTy DiagHandler,
StringRef YAMLFilePath, void *DiagContext,
IntrusiveRefCntPtr<FileSystem> ExternalFS) {
- return RedirectingFileSystem::create(std::move(Buffer), DiagHandler,
- YAMLFilePath, DiagContext,
- std::move(ExternalFS));
+ MemoryBufferRef BufferRef{Buffer->getBuffer(), YAMLFilePath};
+ auto FS = getVFSFromYAMLs(BufferRef, ExternalFS, DiagHandler, DiagContext);
+ if (auto Err = FS.takeError()) {
+ consumeError(std::move(Err));
+ return nullptr;
+ }
+ return std::move(*FS);
+}
+
+namespace {
+
+struct VFSResult {
+ IntrusiveRefCntPtr<FileSystem> FS;
+ YAMLParseResult::RedirectKind Redirection;
+
+ VFSResult(IntrusiveRefCntPtr<FileSystem> FS,
+ YAMLParseResult::RedirectKind Redirection)
+ : FS(std::move(FS)), Redirection(Redirection) {}
+
+ VFSResult(YAMLParseResult &Result)
+ : FS(std::move(Result.FS)), Redirection(Result.Redirection) {}
+};
+
+} // namespace
+
+static std::unique_ptr<OverlayFileSystem>
+createOverlay(ArrayRef<VFSResult> VFSResults) {
+ if (VFSResults.empty())
+ return nullptr;
+
+ auto OverlayFS = std::make_unique<OverlayFileSystem>(VFSResults.front().FS);
+ for (const auto &Result : VFSResults.drop_front()) {
+ OverlayFS->pushOverlay(Result.FS);
+ }
+ return OverlayFS;
+}
+
+Expected<std::unique_ptr<OverlayFileSystem>>
+vfs::getVFSFromYAMLs(ArrayRef<StringRef> YAMLOverlayPaths,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS,
+ SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext) {
+ SmallVector<MemoryBufferRef, 2> BufferRefs;
+ for (StringRef Path : YAMLOverlayPaths) {
+ BufferRefs.emplace_back(StringRef(), Path);
+ }
+ return getVFSFromYAMLs(BufferRefs, std::move(ExternalFS), DiagHandler,
+ DiagContext);
+}
+
+Expected<std::unique_ptr<OverlayFileSystem>>
+vfs::getVFSFromYAMLs(ArrayRef<MemoryBufferRef> YAMLOverlays,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS,
+ SourceMgr::DiagHandlerTy DiagHandler, void *DiagContext) {
+ if (YAMLOverlays.empty())
+ return std::make_unique<OverlayFileSystem>(std::move(ExternalFS));
+
+ SourceMgr SM;
+ SM.setDiagHandler(DiagHandler, DiagContext);
+
+ SmallVector<VFSResult, 2> Overlays;
+ Overlays.emplace_back(ExternalFS, YAMLParseResult::RedirectKind::Fallthrough);
+ std::unique_ptr<OverlayFileSystem> OverlayFS = createOverlay(Overlays);
+
+ for (MemoryBufferRef Buffer : YAMLOverlays) {
+ // Bit of a hack. If the buffer's data is a nullptr (not just empty),
+ // attempt to read the the file from the current FS. This is to
+ // differentiate between an actual buffer and one that was made from just
+ // a path. The paths cannot be read all up front in order to support
+ // overlay files being defined in a VFS.
+ std::unique_ptr<MemoryBuffer> TempBuffer;
+ if (Buffer.getBuffer().data() == nullptr) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> NewBufferOrError =
+ OverlayFS->getBufferForFile(Buffer.getBufferIdentifier());
+ if (!NewBufferOrError)
+ return createFileError(Buffer.getBufferIdentifier(),
+ NewBufferOrError.getError());
+ TempBuffer = std::move(*NewBufferOrError);
+ Buffer = MemoryBufferRef(TempBuffer->getBuffer(),
+ Buffer.getBufferIdentifier());
+ }
+
+ Optional<YAMLParseResult> Result =
+ RedirectingFileSystemParser::parse(Buffer, SM, ExternalFS);
+ if (!Result)
+ return createFileError(Buffer.getBufferIdentifier(),
+ llvm::errc::invalid_argument);
+
+ // TODO: Remove after simplifying RedirectingFileSystem
+ Result->FS->setRedirection(
+ RedirectingFileSystem::RedirectKind::RedirectOnly);
+ switch (Result->Redirection) {
+ case YAMLParseResult::RedirectKind::Fallthrough:
+ // Simple case - add on the FS
+ Overlays.emplace_back(*Result);
+ OverlayFS->pushOverlay(Overlays.back().FS);
+ break;
+ case YAMLParseResult::RedirectKind::Fallback:
+ // Fallback implies that the previously added FS should run operations
+ // before hitting this FS. This doesn't make a whole lot of sense for any
+ // position other than the beginning where we want the external FS to run
+ // first. For other positions the overlays could just be specified in the
+ // opposite order.
+ //
+ // This is fallout from the history of \c RedirectingFileSystem. Ideally
+ // we would just depend on order and have some way to specify the real
+ // filesystem.
+
+ if (Overlays.back().Redirection !=
+ YAMLParseResult::RedirectKind::RedirectOnly) {
+ // If the previously inserted overlay is redirect only, don't bother
+ // adding this one - it would never run anyway (since redirect only
+ // is necessarily the last FS).
+
+ // Note: Overlays is never empty, it always has at least the
+ // \c ExternalFS
+ Overlays.insert(Overlays.end() - 1, VFSResult(*Result));
+ OverlayFS = createOverlay(Overlays);
+ }
+ break;
+ case YAMLParseResult::RedirectKind::RedirectOnly:
+ // This is now the last FS, clear the rest if there were any
+ Overlays.clear();
+ Overlays.emplace_back(*Result);
+ OverlayFS = createOverlay(Overlays);
+ break;
+ }
+ }
+
+ return OverlayFS;
}
static void getVFSEntries(RedirectingFileSystem::Entry *SrcE,
Index: llvm/include/llvm/Support/VirtualFileSystem.h
===================================================================
--- llvm/include/llvm/Support/VirtualFileSystem.h
+++ llvm/include/llvm/Support/VirtualFileSystem.h
@@ -570,14 +570,62 @@
/// Get a globally unique ID for a virtual file or directory.
llvm::sys::fs::UniqueID getNextVirtualUniqueID();
-/// Gets a \p FileSystem for a virtual file system described in YAML
-/// format.
+/// \see getVFSFromYAMLs
+///
+/// Returns nullptr if \p Buffer could not be parsed as a YAML containing
+/// overlay mappings.
std::unique_ptr<FileSystem>
getVFSFromYAML(std::unique_ptr<llvm::MemoryBuffer> Buffer,
llvm::SourceMgr::DiagHandlerTy DiagHandler,
StringRef YAMLFilePath, void *DiagContext = nullptr,
IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem());
+/// Convenience function to read each file from \p ExternalFS and pass their
+/// buffers along to the next overload. Returns a \c FileError if any file
+/// could not be read.
+Expected<std::unique_ptr<OverlayFileSystem>>
+getVFSFromYAMLs(ArrayRef<StringRef> YAMLOverlayPaths,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem(),
+ SourceMgr::DiagHandlerTy DiagHandler = nullptr,
+ void *DiagContext = nullptr);
+
+/// Gets a \c FileSystem that runs operations on the virtual filesystems
+/// described by each buffer in \p Buffers and then the \p ExternalFS if those
+/// all fail (dependent on the options below). The order that each is run is
+/// the reverse of the list, ie. the last buffer creates the first used
+/// \c FileSystem.
+///
+/// Returns a \c FileError if any of the buffers are invalid and an
+/// \c OverlayFileSystem with just the \p ExternalFS if no buffers were
+/// provided.
+///
+/// Two extra root configuration options are handled by this method when
+/// parsing the YAML of each filesystem:
+/// 'fallthrough': <boolean, default=true, deprecated - use 'redirecting-with'
+/// instead>
+/// 'redirecting-with': <string, one of 'fallthrough', 'fallback', or
+/// 'redirect-only', default='fallthrough'>
+///
+/// These specify the order each filesystem is added to an \c OverlayFileSystem
+/// and whether they're added at all -
+/// - 'fallthrough': allow "falling through" to the next filesystem
+/// - 'fallback': run opertions on the next filesystem before this one.
+/// Most useful when specified on the first overlay, which
+/// causes the \p ExternalFS to run before it (ie. "fallback"
+/// to using the mapped paths only when original fails)
+/// - 'redirect-only': skip running operations on any further filesystems,
+/// ie. this is the last used filesystem. As with
+/// 'fallback', this is more useful when specified on the
+/// first overlay to avoid also checking the \p ExternalFS.
+///
+/// \see OverlayFileSystem
+/// \see RedirectingFileSystem
+Expected<std::unique_ptr<OverlayFileSystem>>
+getVFSFromYAMLs(ArrayRef<MemoryBufferRef> YAMLOverlays,
+ IntrusiveRefCntPtr<FileSystem> ExternalFS = getRealFileSystem(),
+ SourceMgr::DiagHandlerTy DiagHandler = nullptr,
+ void *DiagContext = nullptr);
+
struct YAMLVFSEntry {
template <typename T1, typename T2>
YAMLVFSEntry(T1 &&VPath, T2 &&RPath, bool IsDirectory = false)
@@ -616,10 +664,6 @@
/// 'case-sensitive': <boolean, default=(true for Posix, false for Windows)>
/// 'use-external-names': <boolean, default=true>
/// 'overlay-relative': <boolean, default=false>
-/// 'fallthrough': <boolean, default=true, deprecated - use 'redirecting-with'
-/// instead>
-/// 'redirecting-with': <string, one of 'fallthrough', 'fallback', or
-/// 'redirect-only', default='fallthrough'>
///
/// Virtual directories that list their contents are represented as
/// \verbatim
@@ -690,6 +734,11 @@
enum EntryKind { EK_Directory, EK_DirectoryRemap, EK_File };
enum NameKind { NK_NotSet, NK_External, NK_Virtual };
+ // TODO: Simplify RedirectingFileSystem to remove redirection completely.
+ // Remove RedirectKind, Redirection, and all non-redirect-only paths. Require
+ // any old uses to move to using OverlayFileSystem instead (see the new
+ // getVFSFromYAMLs API).
+
/// The type of redirection to perform.
enum class RedirectKind {
/// Lookup the redirected path first (ie. the one specified in
@@ -733,7 +782,7 @@
DirectoryEntry(StringRef Name, Status S)
: Entry(EK_Directory, Name), S(std::move(S)) {}
- Status getStatus() { return S; }
+ Status getStatus() const { return S; }
void addContent(std::unique_ptr<Entry> Content) {
Contents.push_back(std::move(Content));
@@ -869,11 +918,6 @@
/// 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
/// @{
@@ -882,10 +926,6 @@
/// Currently, case-insensitive matching only works correctly with ASCII.
bool CaseSensitive = is_style_posix(sys::path::Style::native);
- /// 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;
@@ -928,6 +968,7 @@
bool UseExternalNames, FileSystem &ExternalFS);
ErrorOr<Status> status(const Twine &Path) override;
+
ErrorOr<std::unique_ptr<File>> openFileForRead(const Twine &Path) override;
std::error_code getRealPath(const Twine &Path,
@@ -943,10 +984,6 @@
directory_iterator dir_begin(const Twine &Dir, std::error_code &EC) override;
- void setExternalContentsPrefixDir(StringRef PrefixDir);
-
- StringRef getExternalContentsPrefixDir() const;
-
/// Sets the redirection kind to \c Fallthrough if true or \c RedirectOnly
/// otherwise. Will removed in the future, use \c setRedirection instead.
void setFallthrough(bool Fallthrough);
Index: lldb/source/Commands/CommandObjectReproducer.cpp
===================================================================
--- lldb/source/Commands/CommandObjectReproducer.cpp
+++ lldb/source/Commands/CommandObjectReproducer.cpp
@@ -409,23 +409,19 @@
switch (m_options.provider) {
case eReproducerProviderFiles: {
FileSpec vfs_mapping = loader->GetFile<FileProvider::Info>();
+ std::string overlay_path = vfs_mapping.GetPath();
- // Read the VFS mapping.
- ErrorOr<std::unique_ptr<MemoryBuffer>> buffer =
- vfs::getRealFileSystem()->getBufferForFile(vfs_mapping.GetPath());
- if (!buffer) {
- SetError(result, errorCodeToError(buffer.getError()));
+ Expected<IntrusiveRefCntPtr<vfs::FileSystem>> vfs =
+ vfs::getVFSFromYAMLs(StringRef(overlay_path));
+ if (auto err = vfs.takeError()) {
+ SetError(result, std::move(err));
return false;
}
- // Initialize a VFS from the given mapping.
- IntrusiveRefCntPtr<vfs::FileSystem> vfs = vfs::getVFSFromYAML(
- std::move(buffer.get()), nullptr, vfs_mapping.GetPath());
-
// Dump the VFS to a buffer.
std::string str;
raw_string_ostream os(str);
- static_cast<vfs::RedirectingFileSystem &>(*vfs).print(os);
+ (*vfs)->print(os);
os.flush();
// Return the string.
Index: clang/test/VFS/vfsroot-with-overlay.c
===================================================================
--- clang/test/VFS/vfsroot-with-overlay.c
+++ clang/test/VFS/vfsroot-with-overlay.c
@@ -1,7 +1,7 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t
// RUN: sed -e "s@TEST_DIR@%{/S:regex_replacement}@g" -e "s@OUT_DIR@%{/t:regex_replacement}@g" %S/Inputs/vfsroot.yaml > %t.yaml
-// RUN: sed -e "s@INPUT_DIR@/indirect-vfs-root-files@g" -e "s@OUT_DIR@/overlay-dir@g" %S/Inputs/vfsoverlay.yaml > %t/vfsoverlay.yaml
+// RUN: sed -e "s@INPUT_DIR@%{/S:regex_replacement}/Inputs@g" -e "s@OUT_DIR@/overlay-dir@g" %S/Inputs/vfsoverlay.yaml > %t/vfsoverlay.yaml
// RUN: %clang_cc1 -Werror -ivfsoverlay %t.yaml -ivfsoverlay /direct-vfs-root-files/vfsoverlay.yaml -I /overlay-dir -fsyntax-only /tests/vfsroot-with-overlay.c
#include "not_real.h"
Index: clang/test/VFS/multiple-overlays.c
===================================================================
--- /dev/null
+++ clang/test/VFS/multiple-overlays.c
@@ -0,0 +1,39 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: sed -e "s@EXTERNAL_DIR@%{/t:regex_replacement}/B@g" -e "s@NAME_DIR@%{/t:regex_replacement}/A@g" %t/vfs/base.yaml > %t/vfs/a-b.yaml
+// RUN: sed -e "s@EXTERNAL_DIR@%{/t:regex_replacement}/C@g" -e "s@NAME_DIR@%{/t:regex_replacement}/B@g" %t/vfs/base.yaml > %t/vfs/b-c.yaml
+
+// Overlays should not be transitive, ie. given overlays of A -> B and B -> C, A should not remap to
+// C.
+
+// RUN: %clang_cc1 -Werror -I %t/A -ivfsoverlay %t/vfs/b-c.yaml -ivfsoverlay %t/vfs/a-b.yaml -fsyntax-only -E -C %t/main.c 2>&1 | FileCheck --check-prefix=FROM_B %s
+// FROM_B: # 1 "{{.*(/|\\\\)B(/|\\\\)}}Header.h"
+// FROM_B: // Header.h in B
+
+// RUN: %clang_cc1 -Werror -I %t/B -ivfsoverlay %t/vfs/b-c.yaml -ivfsoverlay %t/vfs/a-b.yaml -fsyntax-only -E -C %t/main.c 2>&1 | FileCheck --check-prefix=FROM_C %s
+// FROM_C: # 1 "{{.*(/|\\\\)C(/|\\\\)}}Header.h"
+// FROM_C: // Header.h in C
+
+//--- main.c
+#include "Header.h"
+
+//--- A/Header.h
+// Header.h in A
+
+//--- B/Header.h
+// Header.h in B
+
+//--- C/Header.h
+// Header.h in C
+
+//--- vfs/base.yaml
+{
+ 'version': 0,
+ 'redirecting-with': 'fallthrough',
+ 'roots': [
+ { 'name': 'NAME_DIR',
+ 'type': 'directory-remap',
+ 'external-contents': 'EXTERNAL_DIR'
+ }
+ ]
+}
Index: clang/test/VFS/directory.c
===================================================================
--- clang/test/VFS/directory.c
+++ clang/test/VFS/directory.c
@@ -1,13 +1,11 @@
// RUN: rm -rf %t
// RUN: mkdir -p %t/Underlying
// RUN: mkdir -p %t/Overlay
-// RUN: mkdir -p %t/Middle
// RUN: echo '// B.h in Underlying' > %t/Underlying/B.h
// RUN: echo '#ifdef NESTED' >> %t/Underlying/B.h
// RUN: echo '#include "C.h"' >> %t/Underlying/B.h
// RUN: echo '#endif' >> %t/Underlying/B.h
// RUN: echo '// C.h in Underlying' > %t/Underlying/C.h
-// RUN: echo '// C.h in Middle' > %t/Middle/C.h
// RUN: echo '// C.h in Overlay' > %t/Overlay/C.h
// 1) Underlying -> Overlay (C.h found, B.h falling back to Underlying)
@@ -17,31 +15,11 @@
// RUN: sed -e "s@INPUT_DIR@Overlay@g" -e "s@OUT_DIR@%{/t:regex_replacement}/Underlying@g" %S/Inputs/vfsoverlay-directory-relative.yaml > %t/vfs-relative.yaml
// RUN: %clang_cc1 -Werror -I %t/Underlying -ivfsoverlay %t/vfs-relative.yaml -fsyntax-only -E -C %s 2>&1 | FileCheck --check-prefix=DIRECT %s
+// DIRECT: # 1 "{{.*(/|\\\\)Underlying(/|\\\\)}}B.h"
// DIRECT: {{^}}// B.h in Underlying
+// DIRECT: # 1 "{{.*(/|\\\\)Overlay(/|\\\\)}}C.h"
// DIRECT: {{^}}// C.h in Overlay
-// 2) Underlying -> Middle -> Overlay (C.h found, B.h falling back to Underlying)
-// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}/Overlay@g" -e "s@OUT_DIR@%{/t:regex_replacement}/Middle@g" %S/Inputs/vfsoverlay-directory.yaml > %t/vfs.yaml
-// RUN: sed -e "s@INPUT_DIR@%{/t:regex_replacement}/Middle@g" -e "s@OUT_DIR@%{/t:regex_replacement}/Underlying@g" %S/Inputs/vfsoverlay-directory.yaml > %t/vfs2.yaml
-// RUN: %clang_cc1 -Werror -I %t/Underlying -ivfsoverlay %t/vfs.yaml -ivfsoverlay %t/vfs2.yaml -fsyntax-only -E -C %s 2>&1 | FileCheck --check-prefix=DIRECT %s
-// RUN: %clang_cc1 -Werror -I %t/Underlying -ivfsoverlay %t/vfs.yaml -ivfsoverlay %t/vfs2.yaml -DNESTED -fsyntax-only -E -C %s 2>&1 | FileCheck --check-prefix=DIRECT %s
-
-// Same as direct above
-
-// 3) Underlying -> Middle -> Overlay (C.h falling back to Middle, B.h falling back to Underlying)
-// RUN: rm -f %t/Overlay/C.h
-// RUN: %clang_cc1 -Werror -I %t/Underlying -ivfsoverlay %t/vfs.yaml -ivfsoverlay %t/vfs2.yaml -fsyntax-only -E -C %s 2>&1 | FileCheck --check-prefix=FALLBACK %s
-
-// FALLBACK: {{^}}// B.h in Underlying
-// FALLBACK: {{^}}// C.h in Middle
-
-// 3) Underlying -> Middle -> Overlay (C.h falling back to Underlying, B.h falling back to Underlying)
-// RUN: rm -f %t/Middle/C.h
-// RUN: %clang_cc1 -Werror -I %t/Underlying -ivfsoverlay %t/vfs.yaml -ivfsoverlay %t/vfs2.yaml -fsyntax-only -E -C %s 2>&1 | FileCheck --check-prefix=FALLBACK2 %s
-
-// FALLBACK2: {{^}}// B.h in Underlying
-// FALLBACK2: {{^}}// C.h in Underlying
-
#include "B.h"
#ifndef NESTED
#include "C.h"
Index: clang/test/VFS/Inputs/vfsroot.yaml
===================================================================
--- clang/test/VFS/Inputs/vfsroot.yaml
+++ clang/test/VFS/Inputs/vfsroot.yaml
@@ -26,13 +26,6 @@
}
]
},
- { 'name': '/indirect-vfs-root-files', 'type': 'directory',
- 'contents': [
- { 'name': 'actual_header.h', 'type': 'file',
- 'external-contents': 'TEST_DIR/Inputs/actual_header.h'
- }
- ]
- },
{ 'name': 'TEST_DIR/Inputs/Broken.framework', 'type': 'directory',
'contents': [
{ 'name': 'Headers/A.h', 'type': 'file',
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -4693,28 +4693,22 @@
clang::createVFSFromCompilerInvocation(
const CompilerInvocation &CI, DiagnosticsEngine &Diags,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS) {
- if (CI.getHeaderSearchOpts().VFSOverlayFiles.empty())
+ ArrayRef<std::string> OptFiles = CI.getHeaderSearchOpts().VFSOverlayFiles;
+ if (OptFiles.empty())
return BaseFS;
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> Result = BaseFS;
- // earlier vfs files are on the bottom
- for (const auto &File : CI.getHeaderSearchOpts().VFSOverlayFiles) {
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
- Result->getBufferForFile(File);
- if (!Buffer) {
- Diags.Report(diag::err_missing_vfs_overlay_file) << File;
- continue;
- }
-
- IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = llvm::vfs::getVFSFromYAML(
- std::move(Buffer.get()), /*DiagHandler*/ nullptr, File,
- /*DiagContext*/ nullptr, Result);
- if (!FS) {
- Diags.Report(diag::err_invalid_vfs_overlay) << File;
- continue;
- }
-
- Result = FS;
+ SmallVector<StringRef> Files(OptFiles.begin(), OptFiles.end());
+ Expected<IntrusiveRefCntPtr<llvm::vfs::FileSystem>> OverlayFS =
+ llvm::vfs::getVFSFromYAMLs(Files, BaseFS);
+ if (auto Err = OverlayFS.takeError()) {
+ llvm::handleAllErrors(std::move(Err), [&](const llvm::FileError &FE) {
+ if (FE.convertToErrorCode() == std::errc::no_such_file_or_directory) {
+ Diags.Report(diag::err_missing_vfs_overlay_file) << FE.getFileName();
+ } else {
+ Diags.Report(diag::err_invalid_vfs_overlay) << FE.getFileName();
+ }
+ });
+ return BaseFS;
}
- return Result;
+ return *OverlayFS;
}
Index: clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
===================================================================
--- clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
+++ clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp
@@ -363,26 +363,26 @@
std::move(OverrideOptions), std::move(FS));
}
-llvm::IntrusiveRefCntPtr<vfs::FileSystem>
-getVfsFromFile(const std::string &OverlayFile,
- llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS) {
- llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Buffer =
- BaseFS->getBufferForFile(OverlayFile);
- if (!Buffer) {
- llvm::errs() << "Can't load virtual filesystem overlay file '"
- << OverlayFile << "': " << Buffer.getError().message()
- << ".\n";
- return nullptr;
- }
-
- IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getVFSFromYAML(
- std::move(Buffer.get()), /*DiagHandler*/ nullptr, OverlayFile);
- if (!FS) {
- llvm::errs() << "Error: invalid virtual filesystem overlay file '"
- << OverlayFile << "'.\n";
+static IntrusiveRefCntPtr<vfs::OverlayFileSystem>
+getVFSFromFile(StringRef OverlayFile) {
+ if (OverlayFile.empty())
+ return makeIntrusiveRefCnt<vfs::OverlayFileSystem>(
+ vfs::getRealFileSystem());
+
+ auto OverlayFS = vfs::getVFSFromYAMLs(OverlayFile, vfs::getRealFileSystem());
+ if (auto Err = OverlayFS.takeError()) {
+ handleAllErrors(std::move(Err), [](const FileError &FE) {
+ if (FE.convertToErrorCode() == std::errc::no_such_file_or_directory) {
+ errs() << "Can't load virtual filesystem overlay file '"
+ << FE.getFileName() << "': " << FE.message() << ".\n";
+ } else {
+ errs() << "Error: invalid virtual filesystem overlay file '"
+ << FE.getFileName() << "'.\n";
+ }
+ });
return nullptr;
}
- return FS;
+ return std::move(*OverlayFS);
}
int clangTidyMain(int argc, const char **argv) {
@@ -400,16 +400,10 @@
return 1;
}
- llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> BaseFS(
- new vfs::OverlayFileSystem(vfs::getRealFileSystem()));
-
- if (!VfsOverlay.empty()) {
- IntrusiveRefCntPtr<vfs::FileSystem> VfsFromFile =
- getVfsFromFile(VfsOverlay, BaseFS);
- if (!VfsFromFile)
- return 1;
- BaseFS->pushOverlay(std::move(VfsFromFile));
- }
+ llvm::IntrusiveRefCntPtr<vfs::OverlayFileSystem> BaseFS =
+ getVFSFromFile(VfsOverlay);
+ if (!BaseFS)
+ return 1;
auto OwningOptionsProvider = createOptionsProvider(BaseFS);
auto *OptionsProvider = OwningOptionsProvider.get();
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits