Skip to content

Commit 86e2af8

Browse files
committed
reland: [VFS] Use original path when falling back to external FS
This reverts commit f0cf544. Just a small change to fix: ``` /home/buildbot/as-builder-4/llvm-clang-x86_64-expensive-checks-ubuntu/llvm-project/llvm/lib/Support/VirtualFileSystem.cpp: In static member function ‘static llvm::ErrorOr<std::unique_ptr<llvm::vfs::File> > llvm::vfs::File::getWithPath(llvm::ErrorOr<std::unique_ptr<llvm::vfs::File> >, const llvm::Twine&)’: /home/buildbot/as-builder-4/llvm-clang-x86_64-expensive-checks-ubuntu/llvm-project/llvm/lib/Support/VirtualFileSystem.cpp:2084:10: error: could not convert ‘F’ from ‘std::unique_ptr<llvm::vfs::File>’ to ‘llvm::ErrorOr<std::unique_ptr<llvm::vfs::File> >’ return F; ^ ``` Differential Revision: https://reviews.llvm.org/D113832
1 parent e96214d commit 86e2af8

File tree

4 files changed

+215
-28
lines changed

4 files changed

+215
-28
lines changed

clang/test/VFS/relative-path-errors.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: mkdir -p %t
2+
// RUN: cd %t
3+
// RUN: cp %s main.c
4+
// RUN: not %clang_cc1 main.c 2>&1 | FileCheck %s
5+
// RUN: echo '{"roots": [],"version": 0}' > %t.yaml
6+
// RUN: not %clang_cc1 -ivfsoverlay %t.yaml main.c 2>&1 | FileCheck %s
7+
// RUN: echo '{"version": 0,"roots":[{"type":"directory","name":"%/t","contents":[{"type":"file","name":"vfsname", "external-contents":"main.c"}]}]}' > %t.yaml
8+
// RUN: not %clang_cc1 -ivfsoverlay %t.yaml vfsname 2>&1 | FileCheck %s
9+
10+
// CHECK: {{^}}main.c:[[# @LINE + 1]]:1: error:
11+
foobarbaz

llvm/include/llvm/Support/VirtualFileSystem.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,14 @@ class File {
121121

122122
/// Closes the file.
123123
virtual std::error_code close() = 0;
124+
125+
// Get the same file with a different path.
126+
static ErrorOr<std::unique_ptr<File>>
127+
getWithPath(ErrorOr<std::unique_ptr<File>> Result, const Twine &P);
128+
129+
protected:
130+
// Set the file's underlying path.
131+
virtual void setPath(const Twine &Path) {}
124132
};
125133

126134
/// A member of a directory, yielded by a directory_iterator.
@@ -757,6 +765,12 @@ class RedirectingFileSystem : public vfs::FileSystem {
757765
/// with the given error code on a path associated with the provided Entry.
758766
bool shouldFallBackToExternalFS(std::error_code EC, Entry *E = nullptr) const;
759767

768+
/// Get the File status, or error, from the underlying external file system.
769+
/// This returns the status with the originally requested name, while looking
770+
/// up the entry using the canonical path.
771+
ErrorOr<Status> getExternalStatus(const Twine &CanonicalPath,
772+
const Twine &OriginalPath) const;
773+
760774
// In a RedirectingFileSystem, keys can be specified in Posix or Windows
761775
// style (or even a mixture of both), so this comparison helper allows
762776
// slashes (representing a root) to match backslashes (and vice versa). Note
@@ -814,7 +828,8 @@ class RedirectingFileSystem : public vfs::FileSystem {
814828
Entry *From) const;
815829

816830
/// Get the status for a path with the provided \c LookupResult.
817-
ErrorOr<Status> status(const Twine &Path, const LookupResult &Result);
831+
ErrorOr<Status> status(const Twine &CanonicalPath, const Twine &OriginalPath,
832+
const LookupResult &Result);
818833

819834
public:
820835
/// Looks up \p Path in \c Roots and returns a LookupResult giving the

llvm/lib/Support/VirtualFileSystem.cpp

Lines changed: 80 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ class RealFile : public File {
194194
bool RequiresNullTerminator,
195195
bool IsVolatile) override;
196196
std::error_code close() override;
197+
void setPath(const Twine &Path) override;
197198
};
198199

199200
} // namespace
@@ -229,6 +230,12 @@ std::error_code RealFile::close() {
229230
return EC;
230231
}
231232

233+
void RealFile::setPath(const Twine &Path) {
234+
RealName = Path.str();
235+
if (auto Status = status())
236+
S = Status.get().copyWithNewName(Status.get(), Path);
237+
}
238+
232239
namespace {
233240

234241
/// A file system according to your operating system.
@@ -639,6 +646,8 @@ class InMemoryFileAdaptor : public File {
639646
}
640647

641648
std::error_code close() override { return {}; }
649+
650+
void setPath(const Twine &Path) override { RequestedName = Path.str(); }
642651
};
643652
} // namespace
644653

@@ -1244,7 +1253,7 @@ directory_iterator RedirectingFileSystem::dir_begin(const Twine &Dir,
12441253
}
12451254

12461255
// Use status to make sure the path exists and refers to a directory.
1247-
ErrorOr<Status> S = status(Path, *Result);
1256+
ErrorOr<Status> S = status(Path, Dir, *Result);
12481257
if (!S) {
12491258
if (shouldFallBackToExternalFS(S.getError(), Result->E))
12501259
return ExternalFS->dir_begin(Dir, EC);
@@ -1971,47 +1980,68 @@ RedirectingFileSystem::lookupPathImpl(
19711980
return make_error_code(llvm::errc::no_such_file_or_directory);
19721981
}
19731982

1974-
static Status getRedirectedFileStatus(const Twine &Path, bool UseExternalNames,
1983+
static Status getRedirectedFileStatus(const Twine &OriginalPath,
1984+
bool UseExternalNames,
19751985
Status ExternalStatus) {
19761986
Status S = ExternalStatus;
19771987
if (!UseExternalNames)
1978-
S = Status::copyWithNewName(S, Path);
1988+
S = Status::copyWithNewName(S, OriginalPath);
19791989
S.IsVFSMapped = true;
19801990
return S;
19811991
}
19821992

19831993
ErrorOr<Status> RedirectingFileSystem::status(
1984-
const Twine &Path, const RedirectingFileSystem::LookupResult &Result) {
1994+
const Twine &CanonicalPath, const Twine &OriginalPath,
1995+
const RedirectingFileSystem::LookupResult &Result) {
19851996
if (Optional<StringRef> ExtRedirect = Result.getExternalRedirect()) {
1986-
ErrorOr<Status> S = ExternalFS->status(*ExtRedirect);
1997+
SmallString<256> CanonicalRemappedPath((*ExtRedirect).str());
1998+
if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
1999+
return EC;
2000+
2001+
ErrorOr<Status> S = ExternalFS->status(CanonicalRemappedPath);
19872002
if (!S)
19882003
return S;
2004+
S = Status::copyWithNewName(*S, *ExtRedirect);
19892005
auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result.E);
1990-
return getRedirectedFileStatus(Path, RE->useExternalName(UseExternalNames),
1991-
*S);
2006+
return getRedirectedFileStatus(OriginalPath,
2007+
RE->useExternalName(UseExternalNames), *S);
19922008
}
19932009

19942010
auto *DE = cast<RedirectingFileSystem::DirectoryEntry>(Result.E);
1995-
return Status::copyWithNewName(DE->getStatus(), Path);
2011+
return Status::copyWithNewName(DE->getStatus(), CanonicalPath);
19962012
}
19972013

1998-
ErrorOr<Status> RedirectingFileSystem::status(const Twine &Path_) {
1999-
SmallString<256> Path;
2000-
Path_.toVector(Path);
2014+
ErrorOr<Status>
2015+
RedirectingFileSystem::getExternalStatus(const Twine &CanonicalPath,
2016+
const Twine &OriginalPath) const {
2017+
if (auto Result = ExternalFS->status(CanonicalPath)) {
2018+
return Result.get().copyWithNewName(Result.get(), OriginalPath);
2019+
} else {
2020+
return Result.getError();
2021+
}
2022+
}
20012023

2002-
if (std::error_code EC = makeCanonical(Path))
2024+
ErrorOr<Status> RedirectingFileSystem::status(const Twine &OriginalPath) {
2025+
SmallString<256> CanonicalPath;
2026+
OriginalPath.toVector(CanonicalPath);
2027+
2028+
if (std::error_code EC = makeCanonical(CanonicalPath))
20032029
return EC;
20042030

2005-
ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
2031+
ErrorOr<RedirectingFileSystem::LookupResult> Result =
2032+
lookupPath(CanonicalPath);
20062033
if (!Result) {
2007-
if (shouldFallBackToExternalFS(Result.getError()))
2008-
return ExternalFS->status(Path);
2034+
if (shouldFallBackToExternalFS(Result.getError())) {
2035+
return getExternalStatus(CanonicalPath, OriginalPath);
2036+
}
20092037
return Result.getError();
20102038
}
20112039

2012-
ErrorOr<Status> S = status(Path, *Result);
2013-
if (!S && shouldFallBackToExternalFS(S.getError(), Result->E))
2014-
S = ExternalFS->status(Path);
2040+
ErrorOr<Status> S = status(CanonicalPath, OriginalPath, *Result);
2041+
if (!S && shouldFallBackToExternalFS(S.getError(), Result->E)) {
2042+
return getExternalStatus(CanonicalPath, OriginalPath);
2043+
}
2044+
20152045
return S;
20162046
}
20172047

@@ -2036,35 +2066,58 @@ class FileWithFixedStatus : public File {
20362066
}
20372067

20382068
std::error_code close() override { return InnerFile->close(); }
2069+
2070+
void setPath(const Twine &Path) override { S = S.copyWithNewName(S, Path); }
20392071
};
20402072

20412073
} // namespace
20422074

20432075
ErrorOr<std::unique_ptr<File>>
2044-
RedirectingFileSystem::openFileForRead(const Twine &Path_) {
2045-
SmallString<256> Path;
2046-
Path_.toVector(Path);
2076+
File::getWithPath(ErrorOr<std::unique_ptr<File>> Result, const Twine &P) {
2077+
if (!Result)
2078+
return Result;
20472079

2048-
if (std::error_code EC = makeCanonical(Path))
2080+
ErrorOr<std::unique_ptr<File>> F = std::move(*Result);
2081+
auto Name = F->get()->getName();
2082+
if (Name && Name.get() != P.str())
2083+
F->get()->setPath(P);
2084+
return F;
2085+
}
2086+
2087+
ErrorOr<std::unique_ptr<File>>
2088+
RedirectingFileSystem::openFileForRead(const Twine &OriginalPath) {
2089+
SmallString<256> CanonicalPath;
2090+
OriginalPath.toVector(CanonicalPath);
2091+
2092+
if (std::error_code EC = makeCanonical(CanonicalPath))
20492093
return EC;
20502094

2051-
ErrorOr<RedirectingFileSystem::LookupResult> Result = lookupPath(Path);
2095+
ErrorOr<RedirectingFileSystem::LookupResult> Result =
2096+
lookupPath(CanonicalPath);
20522097
if (!Result) {
20532098
if (shouldFallBackToExternalFS(Result.getError()))
2054-
return ExternalFS->openFileForRead(Path);
2099+
return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
2100+
OriginalPath);
2101+
20552102
return Result.getError();
20562103
}
20572104

20582105
if (!Result->getExternalRedirect()) // FIXME: errc::not_a_file?
20592106
return make_error_code(llvm::errc::invalid_argument);
20602107

20612108
StringRef ExtRedirect = *Result->getExternalRedirect();
2109+
SmallString<256> CanonicalRemappedPath(ExtRedirect.str());
2110+
if (std::error_code EC = makeCanonical(CanonicalRemappedPath))
2111+
return EC;
2112+
20622113
auto *RE = cast<RedirectingFileSystem::RemapEntry>(Result->E);
20632114

2064-
auto ExternalFile = ExternalFS->openFileForRead(ExtRedirect);
2115+
auto ExternalFile = File::getWithPath(
2116+
ExternalFS->openFileForRead(CanonicalRemappedPath), ExtRedirect);
20652117
if (!ExternalFile) {
20662118
if (shouldFallBackToExternalFS(ExternalFile.getError(), Result->E))
2067-
return ExternalFS->openFileForRead(Path);
2119+
return File::getWithPath(ExternalFS->openFileForRead(CanonicalPath),
2120+
OriginalPath);
20682121
return ExternalFile;
20692122
}
20702123

@@ -2074,7 +2127,7 @@ RedirectingFileSystem::openFileForRead(const Twine &Path_) {
20742127

20752128
// FIXME: Update the status with the name and VFSMapped.
20762129
Status S = getRedirectedFileStatus(
2077-
Path, RE->useExternalName(UseExternalNames), *ExternalStatus);
2130+
OriginalPath, RE->useExternalName(UseExternalNames), *ExternalStatus);
20782131
return std::unique_ptr<File>(
20792132
std::make_unique<FileWithFixedStatus>(std::move(*ExternalFile), S));
20802133
}

llvm/unittests/Support/VirtualFileSystemTest.cpp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,6 +1627,114 @@ TEST_F(VFSFromYAMLTest, RemappedDirectoryOverlayNoFallthrough) {
16271627
EXPECT_EQ(0, NumDiagnostics);
16281628
}
16291629

1630+
TEST_F(VFSFromYAMLTest, ReturnsRequestedPathVFSMiss) {
1631+
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS(
1632+
new vfs::InMemoryFileSystem);
1633+
BaseFS->addFile("//root/foo/a", 0,
1634+
MemoryBuffer::getMemBuffer("contents of a"));
1635+
ASSERT_FALSE(BaseFS->setCurrentWorkingDirectory("//root/foo"));
1636+
auto RemappedFS = vfs::RedirectingFileSystem::create(
1637+
{}, /*UseExternalNames=*/false, *BaseFS);
1638+
1639+
auto OpenedF = RemappedFS->openFileForRead("a");
1640+
ASSERT_FALSE(OpenedF.getError());
1641+
llvm::ErrorOr<std::string> Name = (*OpenedF)->getName();
1642+
ASSERT_FALSE(Name.getError());
1643+
EXPECT_EQ("a", Name.get());
1644+
1645+
auto OpenedS = (*OpenedF)->status();
1646+
ASSERT_FALSE(OpenedS.getError());
1647+
EXPECT_EQ("a", OpenedS->getName());
1648+
EXPECT_FALSE(OpenedS->IsVFSMapped);
1649+
1650+
auto DirectS = RemappedFS->status("a");
1651+
ASSERT_FALSE(DirectS.getError());
1652+
EXPECT_EQ("a", DirectS->getName());
1653+
EXPECT_FALSE(DirectS->IsVFSMapped);
1654+
1655+
EXPECT_EQ(0, NumDiagnostics);
1656+
}
1657+
1658+
TEST_F(VFSFromYAMLTest, ReturnsExternalPathVFSHit) {
1659+
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS(
1660+
new vfs::InMemoryFileSystem);
1661+
BaseFS->addFile("//root/foo/realname", 0,
1662+
MemoryBuffer::getMemBuffer("contents of a"));
1663+
auto FS =
1664+
getFromYAMLString("{ 'use-external-names': true,\n"
1665+
" 'roots': [\n"
1666+
"{\n"
1667+
" 'type': 'directory',\n"
1668+
" 'name': '//root/foo',\n"
1669+
" 'contents': [ {\n"
1670+
" 'type': 'file',\n"
1671+
" 'name': 'vfsname',\n"
1672+
" 'external-contents': 'realname'\n"
1673+
" }\n"
1674+
" ]\n"
1675+
"}]}",
1676+
BaseFS);
1677+
ASSERT_FALSE(FS->setCurrentWorkingDirectory("//root/foo"));
1678+
1679+
auto OpenedF = FS->openFileForRead("vfsname");
1680+
ASSERT_FALSE(OpenedF.getError());
1681+
llvm::ErrorOr<std::string> Name = (*OpenedF)->getName();
1682+
ASSERT_FALSE(Name.getError());
1683+
EXPECT_EQ("realname", Name.get());
1684+
1685+
auto OpenedS = (*OpenedF)->status();
1686+
ASSERT_FALSE(OpenedS.getError());
1687+
EXPECT_EQ("realname", OpenedS->getName());
1688+
EXPECT_TRUE(OpenedS->IsVFSMapped);
1689+
1690+
auto DirectS = FS->status("vfsname");
1691+
ASSERT_FALSE(DirectS.getError());
1692+
EXPECT_EQ("realname", DirectS->getName());
1693+
EXPECT_TRUE(DirectS->IsVFSMapped);
1694+
1695+
EXPECT_EQ(0, NumDiagnostics);
1696+
}
1697+
1698+
TEST_F(VFSFromYAMLTest, ReturnsInternalPathVFSHit) {
1699+
IntrusiveRefCntPtr<vfs::InMemoryFileSystem> BaseFS(
1700+
new vfs::InMemoryFileSystem);
1701+
BaseFS->addFile("//root/foo/realname", 0,
1702+
MemoryBuffer::getMemBuffer("contents of a"));
1703+
auto FS =
1704+
getFromYAMLString("{ 'use-external-names': false,\n"
1705+
" 'roots': [\n"
1706+
"{\n"
1707+
" 'type': 'directory',\n"
1708+
" 'name': '//root/foo',\n"
1709+
" 'contents': [ {\n"
1710+
" 'type': 'file',\n"
1711+
" 'name': 'vfsname',\n"
1712+
" 'external-contents': 'realname'\n"
1713+
" }\n"
1714+
" ]\n"
1715+
"}]}",
1716+
BaseFS);
1717+
ASSERT_FALSE(FS->setCurrentWorkingDirectory("//root/foo"));
1718+
1719+
auto OpenedF = FS->openFileForRead("vfsname");
1720+
ASSERT_FALSE(OpenedF.getError());
1721+
llvm::ErrorOr<std::string> Name = (*OpenedF)->getName();
1722+
ASSERT_FALSE(Name.getError());
1723+
EXPECT_EQ("vfsname", Name.get());
1724+
1725+
auto OpenedS = (*OpenedF)->status();
1726+
ASSERT_FALSE(OpenedS.getError());
1727+
EXPECT_EQ("vfsname", OpenedS->getName());
1728+
EXPECT_TRUE(OpenedS->IsVFSMapped);
1729+
1730+
auto DirectS = FS->status("vfsname");
1731+
ASSERT_FALSE(DirectS.getError());
1732+
EXPECT_EQ("vfsname", DirectS->getName());
1733+
EXPECT_TRUE(DirectS->IsVFSMapped);
1734+
1735+
EXPECT_EQ(0, NumDiagnostics);
1736+
}
1737+
16301738
TEST_F(VFSFromYAMLTest, CaseInsensitive) {
16311739
IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
16321740
Lower->addRegularFile("//root/foo/bar/a");

0 commit comments

Comments
 (0)