Skip to content

Commit 1b27958

Browse files
committed
[clang][deps] Overload 'Filesystem::exists' in 'DependencyScanningFilesystem' to have it use cached status
As-is, calls to `exists()` fallback on the implementation in 'ProxyFileSystem::exists' which explicitly calls out to the underlying `FS`, which for the 'DependencyScanningFilesystem' (overlay) is the real underlying filesystem. Instead, directly overloading 'exists' allows us to have it rely on the cached `status` behavior used elsewhere by the 'DependencyScanningFilesystem'.
1 parent c2b2cd0 commit 1b27958

File tree

6 files changed

+86
-3
lines changed

6 files changed

+86
-3
lines changed

clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,10 @@ class DependencyScanningWorkerFilesystem
310310
/// false if not (i.e. this entry is not a file or its scan fails).
311311
bool ensureDirectiveTokensArePopulated(EntryRef Entry);
312312

313+
/// Check whether \p Path exists. By default checks cached result of \c status(),
314+
/// and falls back on FS if unable to do so.
315+
bool exists(const Twine &Path) override;
316+
313317
private:
314318
/// For a filename that's not yet associated with any entry in the caches,
315319
/// uses the underlying filesystem to either look up the entry based in the

clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,12 @@ DependencyScanningWorkerFilesystem::status(const Twine &Path) {
270270
return Result->getStatus();
271271
}
272272

273+
bool
274+
DependencyScanningWorkerFilesystem::exists(const Twine &Path) {
275+
llvm::ErrorOr<llvm::vfs::Status> Status = status(Path);
276+
return Status && Status->exists();
277+
}
278+
273279
namespace {
274280

275281
/// The VFS that is used by clang consumes the \c CachedFileSystemEntry using

clang/unittests/Tooling/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ add_clang_unittest(ToolingTests
1313
CastExprTest.cpp
1414
CommentHandlerTest.cpp
1515
CompilationDatabaseTest.cpp
16-
DependencyScannerTest.cpp
1716
DiagnosticsYamlTest.cpp
1817
ExecutionTest.cpp
1918
FixItTest.cpp
@@ -24,6 +23,8 @@ add_clang_unittest(ToolingTests
2423
LookupTest.cpp
2524
QualTypeNamesTest.cpp
2625
RangeSelectorTest.cpp
26+
DependencyScanning/DependencyScannerTest.cpp
27+
DependencyScanning/DependencyScanningFilesystemTest.cpp
2728
RecursiveASTVisitorTests/Attr.cpp
2829
RecursiveASTVisitorTests/BitfieldInitializer.cpp
2930
RecursiveASTVisitorTests/CallbacksLeaf.cpp

clang/unittests/Tooling/DependencyScannerTest.cpp renamed to clang/unittests/Tooling/DependencyScanning/DependencyScannerTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===- unittest/Tooling/ToolingTest.cpp - Tooling unit tests --------------===//
1+
//===- DependencyScannerTest.cpp - Tooling unit tests ---------------------===//
22
//
33
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
44
// See https://llvm.org/LICENSE.txt for license information.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
//===- DependencyScanningFilesystemTest.cpp -------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h"
10+
#include "llvm/ADT/Twine.h"
11+
#include "llvm/Support/VirtualFileSystem.h"
12+
#include "gtest/gtest.h"
13+
14+
using namespace clang::tooling::dependencies;
15+
16+
namespace {
17+
struct InstrumentingInMemoryFilesystem
18+
: llvm::RTTIExtends<InstrumentingInMemoryFilesystem, llvm::vfs::InMemoryFileSystem> {
19+
unsigned NumStatCalls = 0;
20+
21+
using llvm::RTTIExtends<InstrumentingInMemoryFilesystem,
22+
llvm::vfs::InMemoryFileSystem>::RTTIExtends;
23+
24+
llvm::ErrorOr<llvm::vfs::Status> status(const llvm::Twine &Path) override {
25+
++NumStatCalls;
26+
return InMemoryFileSystem::status(Path);
27+
}
28+
};
29+
} // namespace
30+
31+
32+
TEST(DependencyScanningFilesystem, CacheStatOnExists) {
33+
auto InMemoryInstrumentingFS = llvm::makeIntrusiveRefCnt<InstrumentingInMemoryFilesystem>();
34+
InMemoryInstrumentingFS->setCurrentWorkingDirectory("/");
35+
InMemoryInstrumentingFS->addFile("/foo", 0, llvm::MemoryBuffer::getMemBuffer(""));
36+
InMemoryInstrumentingFS->addFile("/bar", 0, llvm::MemoryBuffer::getMemBuffer(""));
37+
DependencyScanningFilesystemSharedCache SharedCache;
38+
DependencyScanningWorkerFilesystem DepFS(SharedCache, InMemoryInstrumentingFS);
39+
40+
DepFS.status("/foo");
41+
DepFS.status("/foo");
42+
DepFS.status("/bar");
43+
EXPECT_EQ(InMemoryInstrumentingFS->NumStatCalls, 2u);
44+
45+
DepFS.exists("/foo");
46+
DepFS.exists("/bar");
47+
EXPECT_EQ(InMemoryInstrumentingFS->NumStatCalls, 2u);
48+
}

llvm/unittests/Support/VirtualFileSystemTest.cpp

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ class NoStatusDummyFileSystem : public DummyFileSystem {
211211
}
212212

213213
bool exists(const Twine &Path) override {
214-
auto Status = DummyFileSystem::status(Path);
214+
llvm::ErrorOr<llvm::vfs::Status> Status = status(Path);
215215
return Status && Status->exists();
216216
}
217217
};
@@ -3560,3 +3560,27 @@ TEST(RedirectingFileSystemTest, ExistsRedirectOnly) {
35603560
EXPECT_FALSE(Redirecting->exists("/b"));
35613561
EXPECT_TRUE(Redirecting->exists("/vfile"));
35623562
}
3563+
3564+
TEST(DependencyScanningWorkerFilesystemTest, ExistsUsesStatCache) {
3565+
struct StatCountingProxyFS : llvm::vfs::ProxyFileSystem {
3566+
int StatCount;
3567+
3568+
StatCountingProxyFS(IntrusiveRefCntPtr<FileSystem> UnderlyingFS)
3569+
: ProxyFileSystem(UnderlyingFS), StatCount(0) {}
3570+
3571+
llvm::ErrorOr<llvm::vfs::Status> status(const Twine &Path) override {
3572+
StatCount++;
3573+
return ProxyFileSystem::status(Path);
3574+
}
3575+
};
3576+
auto BaseFS = IntrusiveRefCntPtr<DummyFileSystem>(new DummyFileSystem());
3577+
auto ScanFS = makeIntrusiveRefCnt<StatCountingProxyFS>(BaseFS);
3578+
BaseFS->addRegularFile("/a");
3579+
BaseFS->addRegularFile("/b");
3580+
ScanFS->status("/a");
3581+
ScanFS->status("/b");
3582+
EXPECT_TRUE(ScanFS->StatCount == 2);
3583+
ScanFS->exists("/a");
3584+
ScanFS->exists("/b");
3585+
EXPECT_TRUE(ScanFS->StatCount == 2);
3586+
}

0 commit comments

Comments
 (0)