diff --git a/clang/test/VFS/Inputs/vfsoverlay-root-relative.yaml b/clang/test/VFS/Inputs/vfsoverlay-root-relative.yaml new file mode 100644 index 00000000000000..9ed7ec59d11e6c --- /dev/null +++ b/clang/test/VFS/Inputs/vfsoverlay-root-relative.yaml @@ -0,0 +1,17 @@ +{ + 'version': 0, + 'fallthrough': true, + 'overlay-relative': true, + 'roots': [ + { 'name': 'virtual', + 'type': 'directory', + 'contents': [ + { + 'external-contents': 'actual_header.h', + 'type': 'file', + 'name': 'virtual_header.h', + } + ] + } + ] +} diff --git a/clang/test/VFS/vfsoverlay-relative-root.c b/clang/test/VFS/vfsoverlay-relative-root.c new file mode 100644 index 00000000000000..30a7a79eceaecd --- /dev/null +++ b/clang/test/VFS/vfsoverlay-relative-root.c @@ -0,0 +1,3 @@ +// RUN: %clang_cc1 -Werror -ivfsoverlay %S/Inputs/vfsoverlay-root-relative.yaml -I virtual -fsyntax-only %s + +#include "virtual_header.h" diff --git a/llvm/include/llvm/Support/VirtualFileSystem.h b/llvm/include/llvm/Support/VirtualFileSystem.h index 78bcdbf3e93283..9b5ff8f20ae2db 100644 --- a/llvm/include/llvm/Support/VirtualFileSystem.h +++ b/llvm/include/llvm/Support/VirtualFileSystem.h @@ -547,6 +547,9 @@ class RedirectingFileSystemParser; /// } /// \endverbatim /// +/// The roots may be absolute or relative. If relative they will be made +/// absolute against the current working directory. +/// /// All configuration options are optional. /// 'case-sensitive': /// 'use-external-names': diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp index bec4e8dbe06c64..7b752b557f8e65 100644 --- a/llvm/lib/Support/VirtualFileSystem.cpp +++ b/llvm/lib/Support/VirtualFileSystem.cpp @@ -1649,10 +1649,19 @@ class llvm::vfs::RedirectingFileSystemParser { sys::path::Style::windows_backslash)) { path_style = sys::path::Style::windows_backslash; } else { - assert(NameValueNode && "Name presence should be checked earlier"); - error(NameValueNode, + // Relative VFS root entries are made absolute to the current working + // directory, then we can determine the path style from that. + auto EC = sys::fs::make_absolute(Name); + if (EC) { + assert(NameValueNode && "Name presence should be checked earlier"); + error( + NameValueNode, "entry with relative path at the root level is not discoverable"); - return nullptr; + return nullptr; + } + path_style = sys::path::is_absolute(Name, sys::path::Style::posix) + ? sys::path::Style::posix + : sys::path::Style::windows_backslash; } } diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp index be32971908ea36..caae58f74f6362 100644 --- a/llvm/unittests/Support/VirtualFileSystemTest.cpp +++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp @@ -2164,6 +2164,11 @@ TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) { TEST_F(VFSFromYAMLTest, RelativePaths) { IntrusiveRefCntPtr Lower(new DummyFileSystem()); + std::error_code EC; + SmallString<128> CWD; + EC = llvm::sys::fs::current_path(CWD); + ASSERT_FALSE(EC); + // Filename at root level without a parent directory. IntrusiveRefCntPtr FS = getFromYAMLString( "{ 'roots': [\n" @@ -2172,16 +2177,26 @@ TEST_F(VFSFromYAMLTest, RelativePaths) { " }\n" "] }", Lower); - EXPECT_EQ(nullptr, FS.get()); + ASSERT_TRUE(FS.get() != nullptr); + SmallString<128> ExpectedPathNotInDir("file-not-in-directory.h"); + llvm::sys::fs::make_absolute(ExpectedPathNotInDir); + checkContents(FS->dir_begin(CWD, EC), {ExpectedPathNotInDir}); // Relative file path. FS = getFromYAMLString("{ 'roots': [\n" - " { 'type': 'file', 'name': 'relative/file/path.h',\n" + " { 'type': 'file', 'name': 'relative/path.h',\n" " 'external-contents': '//root/external/file'\n" " }\n" "] }", Lower); - EXPECT_EQ(nullptr, FS.get()); + ASSERT_TRUE(FS.get() != nullptr); + SmallString<128> Parent("relative"); + llvm::sys::fs::make_absolute(Parent); + auto I = FS->dir_begin(Parent, EC); + ASSERT_FALSE(EC); + // Convert to POSIX path for comparison of windows paths + ASSERT_EQ("relative/path.h", + getPosixPath(std::string(I->path().substr(CWD.size() + 1)))); // Relative directory path. FS = getFromYAMLString( @@ -2191,9 +2206,14 @@ TEST_F(VFSFromYAMLTest, RelativePaths) { " }\n" "] }", Lower); - EXPECT_EQ(nullptr, FS.get()); + ASSERT_TRUE(FS.get() != nullptr); + SmallString<128> Root("relative/directory"); + llvm::sys::fs::make_absolute(Root); + I = FS->dir_begin(Root, EC); + ASSERT_FALSE(EC); + ASSERT_EQ("path.h", std::string(I->path().substr(Root.size() + 1))); - EXPECT_EQ(3, NumDiagnostics); + EXPECT_EQ(0, NumDiagnostics); } TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {