[clang] [clang][deps] Make the service provide the VFS (PR #181424)

Jan Svoboda via cfe-commits cfe-commits at lists.llvm.org
Fri Feb 13 13:42:33 PST 2026


https://github.com/jansvoboda11 created https://github.com/llvm/llvm-project/pull/181424

This PR makes it so that the base VFS used during a scan is provided to the top-level service, not to each worker/tool individually. This enables resolving a FIXME in the async-scan-modules mode of the scanner, will clean up [downstream code](https://github.com/swiftlang/llvm-project/blob/0eb56baa1d92190ed61c1a13caa1112e0f70b109/clang/tools/libclang/CDependencies.cpp#L619-L622), and will make it more difficult to have mismatching VFSs across workers, which may cause non-deterministic poisoning of `DependencyScanningFilesystemSharedCache`.

>From c7ecf43a0117d436db64d8890227230591aaa18e Mon Sep 17 00:00:00 2001
From: Jan Svoboda <jan_svoboda at apple.com>
Date: Fri, 13 Feb 2026 13:02:22 -0800
Subject: [PATCH] [clang][deps] Make the service provide the VFS

---
 .../clang/DependencyScanning/DependencyScanningService.h    | 5 +++++
 .../clang/DependencyScanning/DependencyScanningWorker.h     | 4 +---
 clang/include/clang/Tooling/DependencyScanningTool.h        | 6 ++----
 clang/lib/DependencyScanning/DependencyScannerImpl.cpp      | 3 +--
 clang/lib/DependencyScanning/DependencyScanningService.cpp  | 3 ++-
 clang/lib/DependencyScanning/DependencyScanningWorker.cpp   | 5 +++--
 clang/lib/Tooling/DependencyScanningTool.cpp                | 6 ------
 .../DependencyScanning/DependencyScanningWorkerTest.cpp     | 3 ++-
 clang/unittests/Tooling/DependencyScannerTest.cpp           | 6 ++++--
 9 files changed, 20 insertions(+), 21 deletions(-)

diff --git a/clang/include/clang/DependencyScanning/DependencyScanningService.h b/clang/include/clang/DependencyScanning/DependencyScanningService.h
index 509b6a579ecb4..20ba86bd097b0 100644
--- a/clang/include/clang/DependencyScanning/DependencyScanningService.h
+++ b/clang/include/clang/DependencyScanning/DependencyScanningService.h
@@ -80,6 +80,11 @@ enum class ScanningOptimizations {
 struct DependencyScanningServiceOptions {
   DependencyScanningServiceOptions();
 
+  /// The function invoked to create each worker's VFS. This function and the
+  /// VFS itself must be thread-safe whenever using multiple workers
+  /// concurrently or whenever \c AsyncScanModules is true.
+  std::function<IntrusiveRefCntPtr<llvm::vfs::FileSystem>()>
+      MakeVFS; // = [] { return llvm::vfs::createPhysicalFileSystem(); }
   /// Whether to use optimized dependency directive scan or full preprocessing.
   ScanningMode Mode = ScanningMode::DependencyDirectivesScan;
   /// What output format are we expected to produce.
diff --git a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h
index 2a48f342335de..e1e0c14c7b52c 100644
--- a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h
+++ b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h
@@ -87,9 +87,7 @@ class DependencyScanningWorker {
   /// Construct a dependency scanning worker.
   ///
   /// @param Service The parent service. Must outlive the worker.
-  /// @param BaseFS The filesystem for the worker to use.
-  DependencyScanningWorker(DependencyScanningService &Service,
-                           IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS);
+  DependencyScanningWorker(DependencyScanningService &Service);
 
   ~DependencyScanningWorker();
 
diff --git a/clang/include/clang/Tooling/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanningTool.h
index fe719aceaef1d..96d21866dd7f9 100644
--- a/clang/include/clang/Tooling/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanningTool.h
@@ -36,10 +36,8 @@ class DependencyScanningTool {
   /// Construct a dependency scanning tool.
   ///
   /// @param Service  The parent service. Must outlive the tool.
-  /// @param FS The filesystem for the tool to use. Defaults to the physical FS.
-  DependencyScanningTool(dependencies::DependencyScanningService &Service,
-                         llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS =
-                             llvm::vfs::createPhysicalFileSystem());
+  DependencyScanningTool(dependencies::DependencyScanningService &Service)
+      : Worker(Service) {}
 
   /// Print out the dependency information into a string using the dependency
   /// file format that is specified in the options (-MD is the default) and
diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
index 28fa2571a24dc..3cb63a1a055ce 100644
--- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp
@@ -620,10 +620,9 @@ struct AsyncModuleCompile : PPCallbacks {
     if (!LockErr && !Owned)
       return;
     // We should build the PCM.
-    // FIXME: Pass the correct BaseFS to the worker FS.
     IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
         llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(
-            Service.getSharedCache(), llvm::vfs::getRealFileSystem());
+            Service.getSharedCache(), Service.getOpts().MakeVFS());
     VFS = createVFSFromCompilerInvocation(CI.getInvocation(),
                                           CI.getDiagnostics(), std::move(VFS));
     auto DC = std::make_unique<DiagnosticConsumer>();
diff --git a/clang/lib/DependencyScanning/DependencyScanningService.cpp b/clang/lib/DependencyScanning/DependencyScanningService.cpp
index 3651b9b20a70f..eb06c86040f0a 100644
--- a/clang/lib/DependencyScanning/DependencyScanningService.cpp
+++ b/clang/lib/DependencyScanning/DependencyScanningService.cpp
@@ -14,5 +14,6 @@ using namespace clang;
 using namespace dependencies;
 
 DependencyScanningServiceOptions::DependencyScanningServiceOptions()
-    : BuildSessionTimestamp(
+    : MakeVFS([] { return llvm::vfs::createPhysicalFileSystem(); }),
+      BuildSessionTimestamp(
           llvm::sys::toTimeT(std::chrono::system_clock::now())) {}
diff --git a/clang/lib/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/DependencyScanning/DependencyScanningWorker.cpp
index 7d0c93138d78c..60e5103fde6ef 100644
--- a/clang/lib/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/DependencyScanning/DependencyScanningWorker.cpp
@@ -20,8 +20,7 @@ using namespace clang;
 using namespace dependencies;
 
 DependencyScanningWorker::DependencyScanningWorker(
-    DependencyScanningService &Service,
-    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS)
+    DependencyScanningService &Service)
     : Service(Service) {
   PCHContainerOps = std::make_shared<PCHContainerOperations>();
   // We need to read object files from PCH built outside the scanner.
@@ -30,6 +29,8 @@ DependencyScanningWorker::DependencyScanningWorker(
   // The scanner itself writes only raw ast files.
   PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());
 
+  auto BaseFS = Service.getOpts().MakeVFS();
+
   if (Service.getOpts().TraceVFS)
     BaseFS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(
         std::move(BaseFS));
diff --git a/clang/lib/Tooling/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanningTool.cpp
index cc4c88fc42f5a..2ae149e8fb2cf 100644
--- a/clang/lib/Tooling/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanningTool.cpp
@@ -14,7 +14,6 @@
 #include "clang/Frontend/Utils.h"
 #include "llvm/ADT/SmallVectorExtras.h"
 #include "llvm/ADT/iterator.h"
-#include "llvm/Support/VirtualFileSystem.h"
 #include "llvm/TargetParser/Host.h"
 #include <optional>
 
@@ -22,11 +21,6 @@ using namespace clang;
 using namespace tooling;
 using namespace dependencies;
 
-DependencyScanningTool::DependencyScanningTool(
-    DependencyScanningService &Service,
-    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
-    : Worker(Service, std::move(FS)) {}
-
 namespace {
 /// Prints out all of the gathered dependencies into a string.
 class MakeDependencyPrinterConsumer : public DependencyConsumer {
diff --git a/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp b/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp
index ca51fc3f6fbcb..9fbebcbc4e1ca 100644
--- a/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp
+++ b/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp
@@ -32,9 +32,10 @@ TEST(DependencyScanner, ScanDepsWithDiagConsumer) {
   VFS->addFile(AsmPath, 0, llvm::MemoryBuffer::getMemBuffer(""));
 
   DependencyScanningServiceOptions Opts;
+  Opts.MakeVFS = [&] { return VFS; };
   Opts.Format = ScanningOutputFormat::Make;
   DependencyScanningService Service(std::move(Opts));
-  DependencyScanningWorker Worker(Service, VFS);
+  DependencyScanningWorker Worker(Service);
 
   llvm::DenseSet<ModuleID> AlreadySeen;
   FullDependencyConsumer DC(AlreadySeen);
diff --git a/clang/unittests/Tooling/DependencyScannerTest.cpp b/clang/unittests/Tooling/DependencyScannerTest.cpp
index a764a206c4670..79fd5a312d2b9 100644
--- a/clang/unittests/Tooling/DependencyScannerTest.cpp
+++ b/clang/unittests/Tooling/DependencyScannerTest.cpp
@@ -229,9 +229,10 @@ TEST(DependencyScanner, ScanDepsWithFS) {
                llvm::MemoryBuffer::getMemBuffer("#include \"header.h\"\n"));
 
   DependencyScanningServiceOptions Opts;
+  Opts.MakeVFS = [&] { return VFS; };
   Opts.Format = ScanningOutputFormat::Make;
   DependencyScanningService Service(std::move(Opts));
-  DependencyScanningTool ScanTool(Service, VFS);
+  DependencyScanningTool ScanTool(Service);
 
   TextDiagnosticBuffer DiagConsumer;
   std::optional<std::string> DepFile =
@@ -287,9 +288,10 @@ TEST(DependencyScanner, ScanDepsWithModuleLookup) {
   auto InterceptFS = llvm::makeIntrusiveRefCnt<InterceptorFS>(VFS);
 
   DependencyScanningServiceOptions Opts;
+  Opts.MakeVFS = [&] { return InterceptFS; };
   Opts.Format = ScanningOutputFormat::Make;
   DependencyScanningService Service(std::move(Opts));
-  DependencyScanningTool ScanTool(Service, InterceptFS);
+  DependencyScanningTool ScanTool(Service);
 
   // This will fail with "fatal error: module 'Foo' not found" but it doesn't
   // matter, the point of the test is to check that files are not read



More information about the cfe-commits mailing list