https://github.com/qiongsiwu updated 
https://github.com/llvm/llvm-project/pull/164345

>From 19482768ca28eb478cd45a7bd0ff63f6c0af55ea Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Wed, 15 Oct 2025 09:22:59 -0700
Subject: [PATCH 1/8] Inital commit of CompilerInstanceWithContext, all tests
 passing.

---
 .../include/clang/Frontend/CompilerInstance.h |   6 +
 clang/include/clang/Frontend/Utils.h          |   4 +
 clang/include/clang/Lex/Preprocessor.h        |   1 +
 .../DependencyScannerImpl.h                   |  58 ++++-
 .../DependencyScanningTool.h                  |  38 +++
 .../DependencyScanningWorker.h                |  32 +++
 .../DependencyScanning/ModuleDepCollector.h   |   6 +
 .../DependencyScannerImpl.cpp                 | 245 +++++++++++++++++-
 .../DependencyScanningTool.cpp                |  23 ++
 .../DependencyScanningWorker.cpp              |  21 +-
 .../DependencyScanning/ModuleDepCollector.cpp |   4 +-
 clang/tools/clang-scan-deps/ClangScanDeps.cpp |  33 ++-
 12 files changed, 463 insertions(+), 8 deletions(-)
 rename clang/{lib => 
include/clang}/Tooling/DependencyScanning/DependencyScannerImpl.h (75%)

diff --git a/clang/include/clang/Frontend/CompilerInstance.h 
b/clang/include/clang/Frontend/CompilerInstance.h
index 44fff69c217c5..8c3e9a19b381e 100644
--- a/clang/include/clang/Frontend/CompilerInstance.h
+++ b/clang/include/clang/Frontend/CompilerInstance.h
@@ -946,6 +946,12 @@ class CompilerInstance : public ModuleLoader {
     DependencyCollectors.push_back(std::move(Listener));
   }
 
+  void clearDependencyCollectors() { DependencyCollectors.clear(); }
+
+  std::vector<std::shared_ptr<DependencyCollector>> &getDependencyCollectors() 
{
+    return DependencyCollectors;
+  }
+
   void setExternalSemaSource(IntrusiveRefCntPtr<ExternalSemaSource> ESS);
 
   ModuleCache &getModuleCache() const { return *ModCache; }
diff --git a/clang/include/clang/Frontend/Utils.h 
b/clang/include/clang/Frontend/Utils.h
index 49fd920d1ec43..b58bbc6235b02 100644
--- a/clang/include/clang/Frontend/Utils.h
+++ b/clang/include/clang/Frontend/Utils.h
@@ -40,6 +40,7 @@ class DiagnosticsEngine;
 class ExternalSemaSource;
 class FrontendOptions;
 class PCHContainerReader;
+class PPCallbacks;
 class Preprocessor;
 class PreprocessorOptions;
 class PreprocessorOutputOptions;
@@ -87,6 +88,9 @@ class DependencyCollector {
                                   bool IsSystem, bool IsModuleFile,
                                   bool IsMissing);
 
+  /// @return the PPCallback this collector added to the Preprocessor.
+  virtual PPCallbacks *getPPCallbacks() { return nullptr; };
+
 protected:
   /// Return true if the filename was added to the list of dependencies, false
   /// otherwise.
diff --git a/clang/include/clang/Lex/Preprocessor.h 
b/clang/include/clang/Lex/Preprocessor.h
index 39754847a93e4..953902b13783f 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1327,6 +1327,7 @@ class Preprocessor {
                                                 std::move(Callbacks));
     Callbacks = std::move(C);
   }
+  void removePPCallbacks() { Callbacks.reset(); }
   /// \}
 
   /// Get the number of tokens processed so far.
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
similarity index 75%
rename from clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
rename to clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
index 71c6731803597..9ab795708ddc6 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
@@ -1,4 +1,4 @@
-//===- DependencyScanner.h - Performs module dependency scanning *- C++ 
-*-===//
+//===- DependencyScannerImpl.h - Implements dependency scanning *- C++ 
-*--===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -10,6 +10,7 @@
 #define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNER_H
 
 #include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -23,6 +24,8 @@ class DiagnosticConsumer;
 namespace tooling {
 namespace dependencies {
 class DependencyScanningService;
+class DependencyScanningWorker;
+
 class DependencyConsumer;
 class DependencyActionController;
 class DependencyScanningWorkerFilesystem;
@@ -149,6 +152,59 @@ std::shared_ptr<ModuleDepCollector> 
initializeScanInstanceDependencyCollector(
     DependencyActionController &Controller,
     PrebuiltModulesAttrsMap PrebuiltModulesASTMap,
     llvm::SmallVector<StringRef> &StableDirs);
+
+class CompilerInstanceWithContext {
+  // Context
+  DependencyScanningWorker &Worker;
+  llvm::StringRef CWD;
+  std::vector<std::string> CommandLine;
+  static const uint64_t MAX_NUM_NAMES = (1 << 12);
+  static const std::string FakeFileBuffer;
+
+  // Context - file systems
+  llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS;
+  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFS;
+  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay;
+
+  // Context - Diagnostics engine, file manager and source mamanger.
+  std::string DiagnosticOutput;
+  llvm::raw_string_ostream DiagnosticsOS;
+  std::unique_ptr<TextDiagnosticPrinter> DiagPrinter;
+  IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
+  std::unique_ptr<FileManager> FileMgr;
+  std::unique_ptr<SourceManager> SrcMgr;
+
+  // Context - compiler invocation
+  std::unique_ptr<clang::driver::Driver> Driver;
+  std::unique_ptr<clang::driver::Compilation> Compilation;
+  std::unique_ptr<CompilerInvocation> Invocation;
+  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFSFromCompilerInvocation;
+
+  // Context - output options
+  std::unique_ptr<DependencyOutputOptions> OutputOpts;
+
+  // Context - stable directory handling
+  llvm::SmallVector<StringRef> StableDirs;
+  PrebuiltModulesAttrsMap PrebuiltModuleVFSMap;
+
+  // Compiler Instance
+  std::unique_ptr<CompilerInstance> CIPtr;
+
+  //   // Source location offset.
+  int32_t SrcLocOffset = 0;
+
+public:
+  CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD,
+                              const std::vector<std::string> &CMD)
+      : Worker(Worker), CWD(CWD), CommandLine(CMD),
+        DiagnosticsOS(DiagnosticOutput) {};
+
+  llvm::Error initialize();
+  llvm::Error computeDependencies(StringRef ModuleName,
+                                  DependencyConsumer &Consumer,
+                                  DependencyActionController &Controller);
+  llvm::Error finalize();
+};
 } // namespace dependencies
 } // namespace tooling
 } // namespace clang
diff --git 
a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
index f222ded8a966a..576fee90142b0 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -159,6 +159,44 @@ class DependencyScanningTool {
       StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen,
       LookupModuleOutputCallback LookupModuleOutput);
 
+  /// The following three methods provide a new interface to perform
+  /// by name dependency scan. The new interface's intention is to improve
+  /// dependency scanning performance when a sequence of name is looked up
+  /// with the same current working directory and the command line.
+
+  /// @brief Initializing the context and the compiler instance.
+  ///        This method must be called before calling
+  ///        computeDependenciesByNameWithContext.
+  /// @param CWD The current working directory used during the scan.
+  /// @param CommandLine The commandline used for the scan.
+  /// @return Error if the initializaiton fails.
+  llvm::Error initializeCompilerInstacneWithContext(
+      StringRef CWD, const std::vector<std::string> &CommandLine);
+
+  /// @brief Computes the dependeny for the module named ModuleName.
+  /// @param ModuleName The name of the module for which this method computes
+  ///.                  dependencies.
+  /// @param AlreadySeen This stores modules which have previously been
+  ///                    reported. Use the same instance for all calls to this
+  ///                    function for a single \c DependencyScanningTool in a
+  ///                    single build. Note that this parameter is not part of
+  ///                    the context because it can be shared across different
+  ///                    worker threads and each worker thread may update it.
+  /// @param LookupModuleOutput This function is called to fill in
+  ///                           "-fmodule-file=", "-o" and other output
+  ///                           arguments for dependencies.
+  /// @return An instance of \c TranslationUnitDeps if the scan is successful.
+  ///         Otherwise it returns an error.
+  llvm::Expected<TranslationUnitDeps> computeDependenciesByNameWithContext(
+      StringRef ModuleName, const llvm::DenseSet<ModuleID> &AlreadySeen,
+      LookupModuleOutputCallback LookupModuleOutput);
+
+  /// @brief This method finializes the compiler instance. It finalizes the
+  ///        diagnostics and deletes the compiler instance. Call this method
+  ///        once all names for a same commandline are scanned.
+  /// @return Error if an error occured during finalization.
+  llvm::Error finalizeCompilerInstanceWithContext();
+
   llvm::vfs::FileSystem &getWorkerVFS() const { return Worker.getVFS(); }
 
 private:
diff --git 
a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
index 6060e4b43312e..3a68d8e9bdde4 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -13,6 +13,7 @@
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Frontend/PCHContainerOperations.h"
+#include "clang/Tooling/DependencyScanning/DependencyScannerImpl.h"
 #include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
 #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
 #include "llvm/Support/Error.h"
@@ -136,6 +137,34 @@ class DependencyScanningWorker {
                                   DependencyActionController &Controller,
                                   StringRef ModuleName);
 
+  /// The three method below implements a new interface for by name
+  /// dependency scanning. They together enable the dependency scanning worker
+  /// to more effectively perform scanning for a sequence of modules
+  /// by name when the CWD and CommandLine do not change across the queries.
+
+  /// @brief Initializing the context and the compiler instance.
+  /// @param CWD The current working directory used during the scan.
+  /// @param CommandLine The commandline used for the scan.
+  /// @return Error if the initializaiton fails.
+  llvm::Error initializeCompierInstanceWithContext(
+      StringRef CWD, const std::vector<std::string> &CommandLine);
+
+  /// @brief Performaces dependency scanning for the module whose name is
+  ///        specified.
+  /// @param ModuleName  The name of the module whose dependency will be
+  ///                    scanned.
+  /// @param Consumer The dependency consumer that stores the results.
+  /// @param Controller The controller for the dependency scanning action.
+  /// @return Error if the scanner incurs errors.
+  llvm::Error
+  computeDependenciesByNameWithContext(StringRef ModuleName,
+                                       DependencyConsumer &Consumer,
+                                       DependencyActionController &Controller);
+
+  /// @brief Finalizes the diagnostics engine and deletes the compiler 
instance.
+  /// @return Error if errors occur during finalization.
+  llvm::Error finalizeCompilerInstanceWithContext();
+
   llvm::vfs::FileSystem &getVFS() const { return *BaseFS; }
 
 private:
@@ -151,6 +180,9 @@ class DependencyScanningWorker {
   /// (passed in the constructor).
   llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
 
+  friend class CompilerInstanceWithContext;
+  std::unique_ptr<CompilerInstanceWithContext> CIWithContext;
+
   /// Private helper functions.
   bool scanDependencies(StringRef WorkingDirectory,
                         const std::vector<std::string> &CommandLine,
diff --git 
a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h 
b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index 4136cb73f7043..fe9e9b364726e 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -288,6 +288,8 @@ class ModuleDepCollector final : public DependencyCollector 
{
   void attachToPreprocessor(Preprocessor &PP) override;
   void attachToASTReader(ASTReader &R) override;
 
+  PPCallbacks *getPPCallbacks() override { return CollectorPPPtr; }
+
   /// Apply any changes implied by the discovered dependencies to the given
   /// invocation, (e.g. disable implicit modules, add explicit module paths).
   void applyDiscoveredDependencies(CompilerInvocation &CI);
@@ -339,6 +341,10 @@ class ModuleDepCollector final : public 
DependencyCollector {
   std::optional<P1689ModuleInfo> ProvidedStdCXXModule;
   std::vector<P1689ModuleInfo> RequiredStdCXXModules;
 
+  /// A pointer to the preprocessor callback so we can invoke it directly
+  /// if needed.
+  ModuleDepCollectorPP *CollectorPPPtr = nullptr;
+
   /// Checks whether the module is known as being prebuilt.
   bool isPrebuiltModule(const Module *M);
 
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index b0096d8e6b08b..9880e3c87d816 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -1,4 +1,4 @@
-//===- DependencyScanner.cpp - Performs module dependency scanning 
--------===//
+//===- DependencyScannerImpl.cpp - Implements module dependency scanning 
--===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,7 +6,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
-#include "DependencyScannerImpl.h"
+#include "clang/Tooling/DependencyScanning/DependencyScannerImpl.h"
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/DiagnosticSerialization.h"
 #include "clang/Driver/Driver.h"
@@ -705,3 +705,244 @@ bool DependencyScanningAction::runInvocation(
 
   return Result;
 }
+
+const std::string CompilerInstanceWithContext::FakeFileBuffer =
+    std::string(MAX_NUM_NAMES, ' ');
+
+llvm::Error CompilerInstanceWithContext::initialize() {
+  // Virtual file system setup
+  // - Set the current working directory.
+  Worker.BaseFS->setCurrentWorkingDirectory(CWD);
+  OverlayFS =
+      llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(Worker.BaseFS);
+  InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
+  InMemoryFS->setCurrentWorkingDirectory(CWD);
+
+  // - Create the fake file as scanning input source file and setup overlay
+  //   FS.
+  SmallString<128> FakeInputPath;
+  llvm::sys::fs::createUniquePath("ScanningCI-%%%%%%%%.input", FakeInputPath,
+                                  /*MakeAbsolute=*/false);
+  InMemoryFS->addFile(FakeInputPath, 0,
+                      llvm::MemoryBuffer::getMemBuffer(FakeFileBuffer));
+  InMemoryOverlay = InMemoryFS;
+  // TODO: we need to handle CAS/CASFS here.
+  //    if (Worker.CAS && !Worker.DepCASFS)
+  //     InMemoryOverlay = llvm::cas::createCASProvidingFileSystem(
+  //         Worker.CAS, std::move(InMemoryFS));
+  OverlayFS->pushOverlay(InMemoryOverlay);
+
+  // Augument the command line.
+  CommandLine.emplace_back(FakeInputPath);
+
+  // Create the file manager, the diagnostics engine, and the source manager.
+  FileMgr = std::make_unique<FileManager>(FileSystemOptions{}, OverlayFS);
+  DiagnosticOutput.clear();
+  auto DiagOpts = createDiagOptions(CommandLine);
+  DiagPrinter = std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS,
+                                                        *(DiagOpts.release()));
+  std::vector<const char *> CCommandLine(CommandLine.size(), nullptr);
+  llvm::transform(CommandLine, CCommandLine.begin(),
+                  [](const std::string &Str) { return Str.c_str(); });
+  DiagOpts = CreateAndPopulateDiagOpts(CCommandLine);
+  sanitizeDiagOpts(*DiagOpts);
+  Diags = CompilerInstance::createDiagnostics(*OverlayFS, 
*(DiagOpts.release()),
+                                              DiagPrinter.get(),
+                                              /*ShouldOwnClient=*/false);
+  SrcMgr = std::make_unique<SourceManager>(*Diags, *FileMgr);
+  Diags->setSourceManager(SrcMgr.get());
+
+  // Create the compiler invocation.
+  Driver = std::make_unique<driver::Driver>(
+      CCommandLine[0], llvm::sys::getDefaultTargetTriple(), *Diags,
+      "clang LLVM compiler", OverlayFS);
+  Driver->setTitle("clang_based_tool");
+  Compilation.reset(Driver->BuildCompilation(llvm::ArrayRef(CCommandLine)));
+
+  if (Compilation->containsError()) {
+    return llvm::make_error<llvm::StringError>("Failed to build compilation",
+                                               llvm::inconvertibleErrorCode());
+  }
+
+  const driver::Command &Command = *(Compilation->getJobs().begin());
+  const auto &CommandArgs = Command.getArguments();
+  size_t ArgSize = CommandArgs.size();
+  assert(ArgSize >= 1 && "Cannot have a command with 0 args");
+  const char *FirstArg = CommandArgs[0];
+  if (strcmp(FirstArg, "-cc1"))
+    return llvm::make_error<llvm::StringError>(
+        "Incorrect compilation command, missing cc1",
+        llvm::inconvertibleErrorCode());
+  Invocation = std::make_unique<CompilerInvocation>();
+
+  if (!CompilerInvocation::CreateFromArgs(*Invocation, Command.getArguments(),
+                                          *Diags, Command.getExecutable())) {
+    Diags->Report(diag::err_fe_expected_compiler_job)
+        << llvm::join(CommandLine, " ");
+    return llvm::make_error<llvm::StringError>(
+        "Cannot create CompilerInvocation from Args",
+        llvm::inconvertibleErrorCode());
+  }
+
+  Invocation->getFrontendOpts().DisableFree = false;
+  Invocation->getCodeGenOpts().DisableFree = false;
+
+  if (any(Worker.Service.getOptimizeArgs() & ScanningOptimizations::Macros))
+    canonicalizeDefines(Invocation->getPreprocessorOpts());
+
+  // Create the CompilerInstance.
+  IntrusiveRefCntPtr<ModuleCache> ModCache =
+      makeInProcessModuleCache(Worker.Service.getModuleCacheEntries());
+  CIPtr = std::make_unique<CompilerInstance>(
+      std::make_shared<CompilerInvocation>(*Invocation), 
Worker.PCHContainerOps,
+      ModCache.get());
+  auto &CI = *CIPtr;
+
+  // TODO: the commented out code here should be un-commented when
+  // we enable CAS.
+  // CI.getInvocation().getCASOpts() = Worker.CASOpts;
+  CI.setBuildingModule(false);
+  CI.createVirtualFileSystem(OverlayFS, Diags->getClient());
+  sanitizeDiagOpts(CI.getDiagnosticOpts());
+  CI.createDiagnostics(DiagPrinter.get(), false);
+  CI.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath = true;
+  CI.getFrontendOpts().GenerateGlobalModuleIndex = false;
+  CI.getFrontendOpts().UseGlobalModuleIndex = false;
+  // CI.getFrontendOpts().ModulesShareFileManager = Worker.DepCASFS ? false :
+  // true;
+  CI.getHeaderSearchOpts().ModuleFormat = "raw";
+  CI.getHeaderSearchOpts().ModulesIncludeVFSUsage =
+      any(Worker.Service.getOptimizeArgs() & ScanningOptimizations::VFS);
+  CI.getHeaderSearchOpts().ModulesStrictContextHash = true;
+  CI.getHeaderSearchOpts().ModulesSerializeOnlyPreprocessor = true;
+  CI.getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true;
+  CI.getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
+  CI.getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings = true;
+  CI.getPreprocessorOpts().ModulesCheckRelocated = false;
+
+  if (CI.getHeaderSearchOpts().ModulesValidateOncePerBuildSession)
+    CI.getHeaderSearchOpts().BuildSessionTimestamp =
+        Worker.Service.getBuildSessionTimestamp();
+
+  CI.createFileManager();
+  auto *FileMgr = CI.getFileManagerPtr().get();
+
+  if (Worker.DepFS) {
+    Worker.DepFS->resetBypassedPathPrefix();
+    if (!CI.getHeaderSearchOpts().ModuleCachePath.empty()) {
+      SmallString<256> ModulesCachePath;
+      normalizeModuleCachePath(
+          *FileMgr, CI.getHeaderSearchOpts().ModuleCachePath, 
ModulesCachePath);
+      Worker.DepFS->setBypassedPathPrefix(ModulesCachePath);
+    }
+
+    CI.setDependencyDirectivesGetter(
+        std::make_unique<ScanningDependencyDirectivesGetter>(*FileMgr));
+  }
+
+  CI.createSourceManager();
+
+  const StringRef Sysroot = CI.getHeaderSearchOpts().Sysroot;
+  if (!Sysroot.empty() && (llvm::sys::path::root_directory(Sysroot) != 
Sysroot))
+    StableDirs = {Sysroot, CI.getHeaderSearchOpts().ResourceDir};
+  if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty())
+    if (visitPrebuiltModule(CI.getPreprocessorOpts().ImplicitPCHInclude, CI,
+                            CI.getHeaderSearchOpts().PrebuiltModuleFiles,
+                            PrebuiltModuleVFSMap, CI.getDiagnostics(),
+                            StableDirs))
+      return llvm::make_error<llvm::StringError>(
+          "Prebuilt module scanning failed", llvm::inconvertibleErrorCode());
+
+  OutputOpts = std::make_unique<DependencyOutputOptions>();
+  std::swap(*OutputOpts, CI.getInvocation().getDependencyOutputOpts());
+  // We need at least one -MT equivalent for the generator of make dependency
+  // files to work.
+  if (OutputOpts->Targets.empty())
+    OutputOpts->Targets = {deduceDepTarget(CI.getFrontendOpts().OutputFile,
+                                           CI.getFrontendOpts().Inputs)};
+  OutputOpts->IncludeSystemHeaders = true;
+
+  CI.createTarget();
+  // CI.initializeDelayedInputFileFromCAS();
+
+  return llvm::Error::success();
+}
+
+llvm::Error CompilerInstanceWithContext::computeDependencies(
+    StringRef ModuleName, DependencyConsumer &Consumer,
+    DependencyActionController &Controller) {
+  auto &CI = *CIPtr;
+  CompilerInvocation Inv(*Invocation);
+
+  auto Opts = std::make_unique<DependencyOutputOptions>(*OutputOpts);
+  auto MDC = std::make_shared<ModuleDepCollector>(
+      Worker.Service, std::move(Opts), CI, Consumer, Controller, Inv,
+      PrebuiltModuleVFSMap, StableDirs);
+
+  CI.clearDependencyCollectors();
+  CI.addDependencyCollector(MDC);
+
+  std::unique_ptr<FrontendAction> Action =
+      std::make_unique<GetDependenciesByModuleNameAction>(ModuleName);
+  auto InputFile = CI.getFrontendOpts().Inputs.begin();
+
+  if (!SrcLocOffset)
+    Action->BeginSourceFile(CI, *InputFile);
+  else {
+    CI.getPreprocessor().removePPCallbacks();
+  }
+
+  Preprocessor &PP = CI.getPreprocessor();
+  SourceManager &SM = PP.getSourceManager();
+  FileID MainFileID = SM.getMainFileID();
+  SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
+  SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
+  if (!SrcLocOffset)
+    PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
+  else {
+    auto DCs = CI.getDependencyCollectors();
+    for (auto &DC : DCs) {
+      DC->attachToPreprocessor(PP);
+      auto *CB = DC->getPPCallbacks();
+
+      FileID PrevFID;
+      SrcMgr::CharacteristicKind FileType =
+          SM.getFileCharacteristic(IDLocation);
+      CB->LexedFileChanged(MainFileID,
+                           
PPChainedCallbacks::LexedFileChangeReason::EnterFile,
+                           FileType, PrevFID, IDLocation);
+    }
+  }
+
+  SrcLocOffset++;
+  SmallVector<IdentifierLoc, 2> Path;
+  IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
+  Path.emplace_back(IDLocation, ModuleID);
+  auto ModResult = CI.loadModule(IDLocation, Path, Module::Hidden, false);
+
+  auto DCs = CI.getDependencyCollectors();
+  for (auto &DC : DCs) {
+    auto *CB = DC->getPPCallbacks();
+    assert(CB && "DC must have dependency collector callback");
+    CB->moduleImport(SourceLocation(), Path, ModResult);
+    CB->EndOfMainFile();
+  }
+
+  MDC->applyDiscoveredDependencies(Inv);
+  Consumer.handleBuildCommand({CommandLine[0], Inv.getCC1CommandLine()});
+
+  // TODO: enable CAS
+  //   std::string ID = Inv.getFileSystemOpts().CASFileSystemRootID;
+  //   if (!ID.empty())
+  //     Consumer.handleCASFileSystemRootID(std::move(ID));
+  //   ID = Inv.getFrontendOpts().CASIncludeTreeID;
+  //   if (!ID.empty())
+  //     Consumer.handleIncludeTreeID(std::move(ID));
+
+  return llvm::Error::success();
+}
+
+llvm::Error CompilerInstanceWithContext::finalize() {
+  DiagPrinter->finish();
+  return llvm::Error::success();
+}
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index 27734ffd0e20b..bad35e6999f04 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -169,6 +169,29 @@ DependencyScanningTool::getModuleDependencies(
   return Consumer.takeTranslationUnitDeps();
 }
 
+llvm::Error DependencyScanningTool::initializeCompilerInstacneWithContext(
+    StringRef CWD, const std::vector<std::string> &CommandLine) {
+  return Worker.initializeCompierInstanceWithContext(CWD, CommandLine);
+}
+
+llvm::Expected<TranslationUnitDeps>
+DependencyScanningTool::computeDependenciesByNameWithContext(
+    StringRef ModuleName, const llvm::DenseSet<ModuleID> &AlreadySeen,
+    LookupModuleOutputCallback LookupModuleOutput) {
+  FullDependencyConsumer Consumer(AlreadySeen);
+  CallbackActionController Controller(LookupModuleOutput);
+  llvm::Error Result = Worker.computeDependenciesByNameWithContext(
+      ModuleName, Consumer, Controller);
+  if (Result)
+    return std::move(Result);
+
+  return Consumer.takeTranslationUnitDeps();
+}
+
+llvm::Error DependencyScanningTool::finalizeCompilerInstanceWithContext() {
+  return Worker.finalizeCompilerInstanceWithContext();
+}
+
 TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() {
   TranslationUnitDeps TU;
 
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 95154212603ac..8c9969e9ad98e 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -7,7 +7,6 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
-#include "DependencyScannerImpl.h"
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/Tool.h"
@@ -190,4 +189,24 @@ bool DependencyScanningWorker::computeDependencies(
                           Controller, DC, OverlayFS, ModuleName);
 }
 
+llvm::Error DependencyScanningWorker::initializeCompierInstanceWithContext(
+    StringRef CWD, const std::vector<std::string> &CommandLine) {
+  CIWithContext =
+      std::make_unique<CompilerInstanceWithContext>(*this, CWD, CommandLine);
+  return CIWithContext->initialize();
+}
+
+llvm::Error DependencyScanningWorker::computeDependenciesByNameWithContext(
+    StringRef ModuleName, DependencyConsumer &Consumer,
+    DependencyActionController &Controller) {
+  assert(CIWithContext && "CompilerInstance with context required!");
+  return CIWithContext->computeDependencies(ModuleName, Consumer, Controller);
+}
+
+llvm::Error DependencyScanningWorker::finalizeCompilerInstanceWithContext() {
+  llvm::Error E = CIWithContext->finalize();
+  CIWithContext.reset();
+  return E;
+}
+
 DependencyActionController::~DependencyActionController() {}
diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp 
b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
index a117bec0d656e..e07a208748b77 100644
--- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
+++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
@@ -965,7 +965,9 @@ ModuleDepCollector::ModuleDepCollector(
           makeCommonInvocationForModuleBuild(std::move(OriginalCI))) {}
 
 void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) {
-  PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(*this));
+  auto CollectorPP = std::make_unique<ModuleDepCollectorPP>(*this);
+  CollectorPPPtr = CollectorPP.get();
+  PP.addPPCallbacks(std::move(CollectorPP));
 }
 
 void ModuleDepCollector::attachToASTReader(ASTReader &R) {}
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp 
b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index e41f4eb7999ae..07146eff65cf2 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -661,6 +661,16 @@ static bool handleModuleResult(StringRef ModuleName,
   return false;
 }
 
+static void handleErrorWithInfoString(StringRef Info, llvm::Error E,
+                                      SharedStream &OS, SharedStream &Errs) {
+  llvm::handleAllErrors(std::move(E), [&Info, &Errs](llvm::StringError &Err) {
+    Errs.applyLocked([&](raw_ostream &OS) {
+      OS << "Error: " << Info << ":\n";
+      OS << Err.getMessage();
+    });
+  });
+}
+
 class P1689Deps {
 public:
   void printDependencies(raw_ostream &OS) {
@@ -1075,12 +1085,29 @@ int clang_scan_deps_main(int argc, char **argv, const 
llvm::ToolContext &) {
             HadErrors = true;
         }
       } else if (ModuleName) {
-        auto MaybeModuleDepsGraph = WorkerTool.getModuleDependencies(
-            *ModuleName, Input->CommandLine, CWD, AlreadySeenModules,
-            LookupOutput);
+        if (llvm::Error Err = WorkerTool.initializeCompilerInstacneWithContext(
+                CWD, Input->CommandLine)) {
+          handleErrorWithInfoString(
+              "Compiler instance with context setup error", std::move(Err),
+              DependencyOS, Errs);
+          HadErrors = true;
+          continue;
+        }
+
+        auto MaybeModuleDepsGraph =
+            WorkerTool.computeDependenciesByNameWithContext(
+                *ModuleName, AlreadySeenModules, LookupOutput);
         if (handleModuleResult(*ModuleName, MaybeModuleDepsGraph, *FD,
                                LocalIndex, DependencyOS, Errs))
           HadErrors = true;
+
+        if (llvm::Error Err =
+                WorkerTool.finalizeCompilerInstanceWithContext()) {
+          handleErrorWithInfoString(
+              "Compiler instance with context finialization error",
+              std::move(Err), DependencyOS, Errs);
+          HadErrors = true;
+        }
       } else {
         std::unique_ptr<llvm::MemoryBuffer> TU;
         std::optional<llvm::MemoryBufferRef> TUBuffer;

>From 094754c289ce6fd190d45f35071f9c248b9977b7 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Thu, 16 Oct 2025 16:30:10 -0700
Subject: [PATCH 2/8] Cleaning up CompilerInstanceWithContext's initialization.

---
 .../DependencyScannerImpl.h                   |  18 +-
 .../DependencyScannerImpl.cpp                 | 165 ++++++------------
 2 files changed, 58 insertions(+), 125 deletions(-)

diff --git 
a/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
index 9ab795708ddc6..3f4f6ff72d325 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
@@ -120,7 +120,8 @@ 
initVFSForTUBuferScanning(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
                           StringRef WorkingDirectory,
                           llvm::MemoryBufferRef TUBuffer);
 
-std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::vector<std::string>>
+std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
+          std::vector<std::string>>
 initVFSForByNameScanning(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
                          ArrayRef<std::string> CommandLine,
                          StringRef WorkingDirectory, StringRef ModuleName);
@@ -163,16 +164,10 @@ class CompilerInstanceWithContext {
 
   // Context - file systems
   llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS;
-  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> InMemoryFS;
-  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay;
 
-  // Context - Diagnostics engine, file manager and source mamanger.
-  std::string DiagnosticOutput;
-  llvm::raw_string_ostream DiagnosticsOS;
-  std::unique_ptr<TextDiagnosticPrinter> DiagPrinter;
-  IntrusiveRefCntPtr<DiagnosticsEngine> Diags;
-  std::unique_ptr<FileManager> FileMgr;
-  std::unique_ptr<SourceManager> SrcMgr;
+  // Context - Diagnostics engine.
+  std::unique_ptr<TextDiagnosticsPrinterWithOutput> DiagPrinterWithOS;
+  std::unique_ptr<DignosticsEngineWithDiagOpts> DiagEngineWithCmdAndOpts;
 
   // Context - compiler invocation
   std::unique_ptr<clang::driver::Driver> Driver;
@@ -196,8 +191,7 @@ class CompilerInstanceWithContext {
 public:
   CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD,
                               const std::vector<std::string> &CMD)
-      : Worker(Worker), CWD(CWD), CommandLine(CMD),
-        DiagnosticsOS(DiagnosticOutput) {};
+      : Worker(Worker), CWD(CWD), CommandLine(CMD) {};
 
   llvm::Error initialize();
   llvm::Error computeDependencies(StringRef ModuleName,
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index 9880e3c87d816..746d1152c92b6 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -456,7 +456,8 @@ 
initVFSForTUBuferScanning(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
   return std::make_pair(ModifiedFS, ModifiedCommandLine);
 }
 
-std::pair<IntrusiveRefCntPtr<llvm::vfs::FileSystem>, std::vector<std::string>>
+std::pair<IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem>,
+          std::vector<std::string>>
 initVFSForByNameScanning(IntrusiveRefCntPtr<llvm::vfs::FileSystem> BaseFS,
                          ArrayRef<std::string> CommandLine,
                          StringRef WorkingDirectory, StringRef ModuleName) {
@@ -489,6 +490,9 @@ bool initializeScanCompilerInstance(
     IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
     DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service,
     IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS) {
+  // TODO: the commented out code here should be un-commented when
+  // we enable CAS.
+  // ScanInstance.getInvocation().getCASOpts() = Worker.CASOpts;
   ScanInstance.setBuildingModule(false);
 
   ScanInstance.createVirtualFileSystem(FS, DiagConsumer);
@@ -710,56 +714,18 @@ const std::string 
CompilerInstanceWithContext::FakeFileBuffer =
     std::string(MAX_NUM_NAMES, ' ');
 
 llvm::Error CompilerInstanceWithContext::initialize() {
-  // Virtual file system setup
-  // - Set the current working directory.
-  Worker.BaseFS->setCurrentWorkingDirectory(CWD);
-  OverlayFS =
-      llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(Worker.BaseFS);
-  InMemoryFS = llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
-  InMemoryFS->setCurrentWorkingDirectory(CWD);
-
-  // - Create the fake file as scanning input source file and setup overlay
-  //   FS.
-  SmallString<128> FakeInputPath;
-  llvm::sys::fs::createUniquePath("ScanningCI-%%%%%%%%.input", FakeInputPath,
-                                  /*MakeAbsolute=*/false);
-  InMemoryFS->addFile(FakeInputPath, 0,
-                      llvm::MemoryBuffer::getMemBuffer(FakeFileBuffer));
-  InMemoryOverlay = InMemoryFS;
-  // TODO: we need to handle CAS/CASFS here.
-  //    if (Worker.CAS && !Worker.DepCASFS)
-  //     InMemoryOverlay = llvm::cas::createCASProvidingFileSystem(
-  //         Worker.CAS, std::move(InMemoryFS));
-  OverlayFS->pushOverlay(InMemoryOverlay);
+  std::tie(OverlayFS, CommandLine) = initVFSForByNameScanning(
+      Worker.BaseFS, CommandLine, CWD, "ScanningByName");
 
-  // Augument the command line.
-  CommandLine.emplace_back(FakeInputPath);
+  DiagPrinterWithOS =
+      std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine);
+  DiagEngineWithCmdAndOpts = std::make_unique<DignosticsEngineWithDiagOpts>(
+      CommandLine, OverlayFS, DiagPrinterWithOS->DiagPrinter);
 
-  // Create the file manager, the diagnostics engine, and the source manager.
-  FileMgr = std::make_unique<FileManager>(FileSystemOptions{}, OverlayFS);
-  DiagnosticOutput.clear();
-  auto DiagOpts = createDiagOptions(CommandLine);
-  DiagPrinter = std::make_unique<TextDiagnosticPrinter>(DiagnosticsOS,
-                                                        *(DiagOpts.release()));
-  std::vector<const char *> CCommandLine(CommandLine.size(), nullptr);
-  llvm::transform(CommandLine, CCommandLine.begin(),
-                  [](const std::string &Str) { return Str.c_str(); });
-  DiagOpts = CreateAndPopulateDiagOpts(CCommandLine);
-  sanitizeDiagOpts(*DiagOpts);
-  Diags = CompilerInstance::createDiagnostics(*OverlayFS, 
*(DiagOpts.release()),
-                                              DiagPrinter.get(),
-                                              /*ShouldOwnClient=*/false);
-  SrcMgr = std::make_unique<SourceManager>(*Diags, *FileMgr);
-  Diags->setSourceManager(SrcMgr.get());
-
-  // Create the compiler invocation.
-  Driver = std::make_unique<driver::Driver>(
-      CCommandLine[0], llvm::sys::getDefaultTargetTriple(), *Diags,
-      "clang LLVM compiler", OverlayFS);
-  Driver->setTitle("clang_based_tool");
-  Compilation.reset(Driver->BuildCompilation(llvm::ArrayRef(CCommandLine)));
+  std::tie(Driver, Compilation) = buildCompilation(
+      CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS);
 
-  if (Compilation->containsError()) {
+  if (!Compilation) {
     return llvm::make_error<llvm::StringError>("Failed to build compilation",
                                                llvm::inconvertibleErrorCode());
   }
@@ -776,8 +742,28 @@ llvm::Error CompilerInstanceWithContext::initialize() {
   Invocation = std::make_unique<CompilerInvocation>();
 
   if (!CompilerInvocation::CreateFromArgs(*Invocation, Command.getArguments(),
-                                          *Diags, Command.getExecutable())) {
-    Diags->Report(diag::err_fe_expected_compiler_job)
+                                          
*DiagEngineWithCmdAndOpts->DiagEngine,
+                                          Command.getExecutable())) {
+    DiagEngineWithCmdAndOpts->DiagEngine->Report(
+        diag::err_fe_expected_compiler_job)
+        << llvm::join(CommandLine, " ");
+    return llvm::make_error<llvm::StringError>(
+        "Cannot create CompilerInvocation from Args",
+        llvm::inconvertibleErrorCode());
+  }
+
+  // TODO: CMDArgsStrVector is making string copies. We should optimize later
+  // and avoid the copies.
+  std::vector<std::string> CMDArgsStrVector(ArgSize + 1);
+  CMDArgsStrVector.push_back(Command.getExecutable());
+  llvm::transform(CommandArgs, CMDArgsStrVector.begin() + 1,
+                  [](const char *s) { return std::string(s); });
+
+  Invocation = createCompilerInvocation(CMDArgsStrVector,
+                                        *DiagEngineWithCmdAndOpts->DiagEngine);
+  if (!Invocation) {
+    DiagEngineWithCmdAndOpts->DiagEngine->Report(
+        diag::err_fe_expected_compiler_job)
         << llvm::join(CommandLine, " ");
     return llvm::make_error<llvm::StringError>(
         "Cannot create CompilerInvocation from Args",
@@ -798,69 +784,22 @@ llvm::Error CompilerInstanceWithContext::initialize() {
       ModCache.get());
   auto &CI = *CIPtr;
 
-  // TODO: the commented out code here should be un-commented when
-  // we enable CAS.
-  // CI.getInvocation().getCASOpts() = Worker.CASOpts;
-  CI.setBuildingModule(false);
-  CI.createVirtualFileSystem(OverlayFS, Diags->getClient());
-  sanitizeDiagOpts(CI.getDiagnosticOpts());
-  CI.createDiagnostics(DiagPrinter.get(), false);
-  CI.getPreprocessorOpts().AllowPCHWithDifferentModulesCachePath = true;
-  CI.getFrontendOpts().GenerateGlobalModuleIndex = false;
-  CI.getFrontendOpts().UseGlobalModuleIndex = false;
-  // CI.getFrontendOpts().ModulesShareFileManager = Worker.DepCASFS ? false :
-  // true;
-  CI.getHeaderSearchOpts().ModuleFormat = "raw";
-  CI.getHeaderSearchOpts().ModulesIncludeVFSUsage =
-      any(Worker.Service.getOptimizeArgs() & ScanningOptimizations::VFS);
-  CI.getHeaderSearchOpts().ModulesStrictContextHash = true;
-  CI.getHeaderSearchOpts().ModulesSerializeOnlyPreprocessor = true;
-  CI.getHeaderSearchOpts().ModulesSkipDiagnosticOptions = true;
-  CI.getHeaderSearchOpts().ModulesSkipHeaderSearchPaths = true;
-  CI.getHeaderSearchOpts().ModulesSkipPragmaDiagnosticMappings = true;
-  CI.getPreprocessorOpts().ModulesCheckRelocated = false;
-
-  if (CI.getHeaderSearchOpts().ModulesValidateOncePerBuildSession)
-    CI.getHeaderSearchOpts().BuildSessionTimestamp =
-        Worker.Service.getBuildSessionTimestamp();
-
-  CI.createFileManager();
-  auto *FileMgr = CI.getFileManagerPtr().get();
-
-  if (Worker.DepFS) {
-    Worker.DepFS->resetBypassedPathPrefix();
-    if (!CI.getHeaderSearchOpts().ModuleCachePath.empty()) {
-      SmallString<256> ModulesCachePath;
-      normalizeModuleCachePath(
-          *FileMgr, CI.getHeaderSearchOpts().ModuleCachePath, 
ModulesCachePath);
-      Worker.DepFS->setBypassedPathPrefix(ModulesCachePath);
-    }
-
-    CI.setDependencyDirectivesGetter(
-        std::make_unique<ScanningDependencyDirectivesGetter>(*FileMgr));
+  if (!initializeScanCompilerInstance(
+          CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
+          Worker.Service, Worker.DepFS)) {
+    return llvm::make_error<llvm::StringError>(
+        "Cannot initialize scanning compiler instance",
+        llvm::inconvertibleErrorCode());
   }
 
-  CI.createSourceManager();
+  llvm::SmallVector<StringRef> StableDirs = getInitialStableDirs(CI);
+  auto MaybePrebuiltModulesASTMap =
+      computePrebuiltModulesASTMap(CI, StableDirs);
+  if (!MaybePrebuiltModulesASTMap)
+    return llvm::make_error<llvm::StringError>(
+        "Prebuilt module scanning failed", llvm::inconvertibleErrorCode());
 
-  const StringRef Sysroot = CI.getHeaderSearchOpts().Sysroot;
-  if (!Sysroot.empty() && (llvm::sys::path::root_directory(Sysroot) != 
Sysroot))
-    StableDirs = {Sysroot, CI.getHeaderSearchOpts().ResourceDir};
-  if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty())
-    if (visitPrebuiltModule(CI.getPreprocessorOpts().ImplicitPCHInclude, CI,
-                            CI.getHeaderSearchOpts().PrebuiltModuleFiles,
-                            PrebuiltModuleVFSMap, CI.getDiagnostics(),
-                            StableDirs))
-      return llvm::make_error<llvm::StringError>(
-          "Prebuilt module scanning failed", llvm::inconvertibleErrorCode());
-
-  OutputOpts = std::make_unique<DependencyOutputOptions>();
-  std::swap(*OutputOpts, CI.getInvocation().getDependencyOutputOpts());
-  // We need at least one -MT equivalent for the generator of make dependency
-  // files to work.
-  if (OutputOpts->Targets.empty())
-    OutputOpts->Targets = {deduceDepTarget(CI.getFrontendOpts().OutputFile,
-                                           CI.getFrontendOpts().Inputs)};
-  OutputOpts->IncludeSystemHeaders = true;
+  OutputOpts = takeDependencyOutputOptionsFrom(CI);
 
   CI.createTarget();
   // CI.initializeDelayedInputFileFromCAS();
@@ -886,9 +825,9 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
       std::make_unique<GetDependenciesByModuleNameAction>(ModuleName);
   auto InputFile = CI.getFrontendOpts().Inputs.begin();
 
-  if (!SrcLocOffset)
+  if (!SrcLocOffset) {
     Action->BeginSourceFile(CI, *InputFile);
-  else {
+  } else {
     CI.getPreprocessor().removePPCallbacks();
   }
 
@@ -943,6 +882,6 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
 }
 
 llvm::Error CompilerInstanceWithContext::finalize() {
-  DiagPrinter->finish();
+  DiagPrinterWithOS->DiagPrinter.finish();
   return llvm::Error::success();
 }

>From 0848e20151857640540deeb22e4a215ade20b378 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Mon, 20 Oct 2025 11:01:40 -0700
Subject: [PATCH 3/8] Refactor CompilerInstanceWithContext::computeDependencies

---
 .../DependencyScannerImpl.h                   |  2 +-
 .../DependencyScannerImpl.cpp                 | 34 +++++++++++--------
 2 files changed, 21 insertions(+), 15 deletions(-)

diff --git 
a/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
index 3f4f6ff72d325..98e5d590ea6bf 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
@@ -180,7 +180,7 @@ class CompilerInstanceWithContext {
 
   // Context - stable directory handling
   llvm::SmallVector<StringRef> StableDirs;
-  PrebuiltModulesAttrsMap PrebuiltModuleVFSMap;
+  PrebuiltModulesAttrsMap PrebuiltModuleASTMap;
 
   // Compiler Instance
   std::unique_ptr<CompilerInstance> CIPtr;
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index 746d1152c92b6..53a8c3c06aad6 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -799,6 +799,7 @@ llvm::Error CompilerInstanceWithContext::initialize() {
     return llvm::make_error<llvm::StringError>(
         "Prebuilt module scanning failed", llvm::inconvertibleErrorCode());
 
+  PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
   OutputOpts = takeDependencyOutputOptionsFrom(CI);
 
   CI.createTarget();
@@ -813,22 +814,20 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
   auto &CI = *CIPtr;
   CompilerInvocation Inv(*Invocation);
 
-  auto Opts = std::make_unique<DependencyOutputOptions>(*OutputOpts);
-  auto MDC = std::make_shared<ModuleDepCollector>(
-      Worker.Service, std::move(Opts), CI, Consumer, Controller, Inv,
-      PrebuiltModuleVFSMap, StableDirs);
-
   CI.clearDependencyCollectors();
-  CI.addDependencyCollector(MDC);
-
-  std::unique_ptr<FrontendAction> Action =
-      std::make_unique<GetDependenciesByModuleNameAction>(ModuleName);
-  auto InputFile = CI.getFrontendOpts().Inputs.begin();
+  auto MDC = initializeScanInstanceDependencyCollector(
+      CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, 
Consumer,
+      Worker.Service, *Invocation, Controller, PrebuiltModuleASTMap,
+      StableDirs);
 
   if (!SrcLocOffset) {
+    // When SrcLocOffset is zero, we are at the beginning of the fake source
+    // file. In this case, we call BeginSourceFile to initialize.
+    std::unique_ptr<FrontendAction> Action =
+        std::make_unique<GetDependenciesByModuleNameAction>(ModuleName);
+    auto InputFile = CI.getFrontendOpts().Inputs.begin();
+
     Action->BeginSourceFile(CI, *InputFile);
-  } else {
-    CI.getPreprocessor().removePPCallbacks();
   }
 
   Preprocessor &PP = CI.getPreprocessor();
@@ -836,9 +835,14 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
   FileID MainFileID = SM.getMainFileID();
   SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
   SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
-  if (!SrcLocOffset)
+  if (!SrcLocOffset) {
+    // We need to call EnterSourceFile when SrcLocOffset is zero to initialize
+    // the preprocessor.
     PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
-  else {
+  } else {
+    // When SrcLocOffset is non-zero, the preprocessor has already been
+    // initialized through a previous call of computeDependencies. We want to
+    // preserve the PP's state, hence we do not call EnterSourceFile again.
     auto DCs = CI.getDependencyCollectors();
     for (auto &DC : DCs) {
       DC->attachToPreprocessor(PP);
@@ -878,6 +882,8 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
   //   if (!ID.empty())
   //     Consumer.handleIncludeTreeID(std::move(ID));
 
+  // Remove the PPCallbacks since they are going out of scope.
+  CI.getPreprocessor().removePPCallbacks();
   return llvm::Error::success();
 }
 

>From 94344cc34268ceaaa11272f479e9c9d598bead7f Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Mon, 20 Oct 2025 11:50:28 -0700
Subject: [PATCH 4/8] Remove by-name query APIs that are no longer used.

---
 .../DependencyScannerImpl.h                   |  6 +--
 .../DependencyScanningTool.h                  |  8 ----
 .../DependencyScanningWorker.h                | 26 +------------
 .../DependencyScannerImpl.cpp                 |  2 -
 .../DependencyScanningTool.cpp                | 14 -------
 .../DependencyScanningWorker.cpp              | 37 +++----------------
 6 files changed, 8 insertions(+), 85 deletions(-)

diff --git 
a/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
index 98e5d590ea6bf..2b42d026728d5 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
@@ -38,8 +38,7 @@ class DependencyScanningAction {
       IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS,
       std::optional<StringRef> ModuleName = std::nullopt)
       : Service(Service), WorkingDirectory(WorkingDirectory),
-        Consumer(Consumer), Controller(Controller), DepFS(std::move(DepFS)),
-        ModuleName(ModuleName) {}
+        Consumer(Consumer), Controller(Controller), DepFS(std::move(DepFS)) {}
   bool runInvocation(std::unique_ptr<CompilerInvocation> Invocation,
                      IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
                      std::shared_ptr<PCHContainerOperations> PCHContainerOps,
@@ -69,7 +68,6 @@ class DependencyScanningAction {
   DependencyConsumer &Consumer;
   DependencyActionController &Controller;
   IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
-  std::optional<StringRef> ModuleName;
   std::optional<CompilerInstance> ScanInstanceStorage;
   std::shared_ptr<ModuleDepCollector> MDC;
   std::vector<std::string> LastCC1Arguments;
@@ -185,7 +183,7 @@ class CompilerInstanceWithContext {
   // Compiler Instance
   std::unique_ptr<CompilerInstance> CIPtr;
 
-  //   // Source location offset.
+  // Source location offset.
   int32_t SrcLocOffset = 0;
 
 public:
diff --git 
a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
index 576fee90142b0..506620d2bca2e 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -151,14 +151,6 @@ class DependencyScanningTool {
       LookupModuleOutputCallback LookupModuleOutput,
       std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt);
 
-  /// Given a compilation context specified via the Clang driver command-line,
-  /// gather modular dependencies of module with the given name, and return the
-  /// information needed for explicit build.
-  llvm::Expected<TranslationUnitDeps> getModuleDependencies(
-      StringRef ModuleName, const std::vector<std::string> &CommandLine,
-      StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen,
-      LookupModuleOutputCallback LookupModuleOutput);
-
   /// The following three methods provide a new interface to perform
   /// by name dependency scan. The new interface's intention is to improve
   /// dependency scanning performance when a sequence of name is looked up
diff --git 
a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
index 3a68d8e9bdde4..f5ff0e727ea94 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -104,18 +104,6 @@ class DependencyScanningWorker {
       DiagnosticConsumer &DiagConsumer,
       std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt);
 
-  /// Run the dependency scanning tool for a given clang driver command-line
-  /// for a specific module.
-  ///
-  /// \returns false if clang errors occurred (with diagnostics reported to
-  /// \c DiagConsumer), true otherwise.
-  bool computeDependencies(StringRef WorkingDirectory,
-                           const std::vector<std::string> &CommandLine,
-                           DependencyConsumer &DepConsumer,
-                           DependencyActionController &Controller,
-                           DiagnosticConsumer &DiagConsumer,
-                           StringRef ModuleName);
-
   /// Run the dependency scanning tool for a given clang driver command-line
   /// for a specific translation unit via file system or memory buffer.
   ///
@@ -126,17 +114,6 @@ class DependencyScanningWorker {
       DependencyConsumer &Consumer, DependencyActionController &Controller,
       std::optional<llvm::MemoryBufferRef> TUBuffer = std::nullopt);
 
-  /// Run the dependency scanning tool for a given clang driver command-line
-  /// for a specific module.
-  ///
-  /// \returns A \c StringError with the diagnostic output if clang errors
-  /// occurred, success otherwise.
-  llvm::Error computeDependencies(StringRef WorkingDirectory,
-                                  const std::vector<std::string> &CommandLine,
-                                  DependencyConsumer &Consumer,
-                                  DependencyActionController &Controller,
-                                  StringRef ModuleName);
-
   /// The three method below implements a new interface for by name
   /// dependency scanning. They together enable the dependency scanning worker
   /// to more effectively perform scanning for a sequence of modules
@@ -189,8 +166,7 @@ class DependencyScanningWorker {
                         DependencyConsumer &Consumer,
                         DependencyActionController &Controller,
                         DiagnosticConsumer &DC,
-                        llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
-                        std::optional<StringRef> ModuleName);
+                        llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS);
 };
 
 } // end namespace dependencies
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index 53a8c3c06aad6..33e3dbffd5eca 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -691,8 +691,6 @@ bool DependencyScanningAction::runInvocation(
 
   if (Service.getFormat() == ScanningOutputFormat::P1689)
     Action = std::make_unique<PreprocessOnlyAction>();
-  else if (ModuleName)
-    Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName);
   else
     Action = std::make_unique<ReadPCHAndPreprocessAction>();
 
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index bad35e6999f04..91a357905be6b 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -155,20 +155,6 @@ DependencyScanningTool::getTranslationUnitDependencies(
   return Consumer.takeTranslationUnitDeps();
 }
 
-llvm::Expected<TranslationUnitDeps>
-DependencyScanningTool::getModuleDependencies(
-    StringRef ModuleName, const std::vector<std::string> &CommandLine,
-    StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen,
-    LookupModuleOutputCallback LookupModuleOutput) {
-  FullDependencyConsumer Consumer(AlreadySeen);
-  CallbackActionController Controller(LookupModuleOutput);
-  llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer,
-                                                  Controller, ModuleName);
-  if (Result)
-    return std::move(Result);
-  return Consumer.takeTranslationUnitDeps();
-}
-
 llvm::Error DependencyScanningTool::initializeCompilerInstacneWithContext(
     StringRef CWD, const std::vector<std::string> &CommandLine) {
   return Worker.initializeCompierInstanceWithContext(CWD, CommandLine);
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 8c9969e9ad98e..e6793d77e3859 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -57,21 +57,6 @@ llvm::Error DependencyScanningWorker::computeDependencies(
       DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
 }
 
-llvm::Error DependencyScanningWorker::computeDependencies(
-    StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
-    DependencyConsumer &Consumer, DependencyActionController &Controller,
-    StringRef ModuleName) {
-  // Capture the emitted diagnostics and report them to the client
-  // in the case of a failure.
-  TextDiagnosticsPrinterWithOutput DiagPrinterWithOS(CommandLine);
-
-  if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,
-                          DiagPrinterWithOS.DiagPrinter, ModuleName))
-    return llvm::Error::success();
-  return llvm::make_error<llvm::StringError>(
-      DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
-}
-
 static bool forEachDriverJob(
     ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,
     IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
@@ -110,11 +95,11 @@ static bool createAndRunToolInvocation(
 bool DependencyScanningWorker::scanDependencies(
     StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
     DependencyConsumer &Consumer, DependencyActionController &Controller,
-    DiagnosticConsumer &DC, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
-    std::optional<StringRef> ModuleName) {
+    DiagnosticConsumer &DC,
+    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {
   DignosticsEngineWithDiagOpts DiagEngineWithCmdAndOpts(CommandLine, FS, DC);
   DependencyScanningAction Action(Service, WorkingDirectory, Consumer,
-                                  Controller, DepFS, ModuleName);
+                                  Controller, DepFS);
 
   bool Success = false;
   if (CommandLine[1] == "-cc1") {
@@ -169,26 +154,14 @@ bool DependencyScanningWorker::computeDependencies(
     auto [FinalFS, FinalCommandLine] = initVFSForTUBuferScanning(
         BaseFS, CommandLine, WorkingDirectory, *TUBuffer);
     return scanDependencies(WorkingDirectory, FinalCommandLine, Consumer,
-                            Controller, DC, FinalFS,
-                            /*ModuleName=*/std::nullopt);
+                            Controller, DC, FinalFS);
   } else {
     BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
     return scanDependencies(WorkingDirectory, CommandLine, Consumer, 
Controller,
-                            DC, BaseFS, /*ModuleName=*/std::nullopt);
+                            DC, BaseFS);
   }
 }
 
-bool DependencyScanningWorker::computeDependencies(
-    StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
-    DependencyConsumer &Consumer, DependencyActionController &Controller,
-    DiagnosticConsumer &DC, StringRef ModuleName) {
-  auto [OverlayFS, ModifiedCommandLine] = initVFSForByNameScanning(
-      BaseFS, CommandLine, WorkingDirectory, ModuleName);
-
-  return scanDependencies(WorkingDirectory, ModifiedCommandLine, Consumer,
-                          Controller, DC, OverlayFS, ModuleName);
-}
-
 llvm::Error DependencyScanningWorker::initializeCompierInstanceWithContext(
     StringRef CWD, const std::vector<std::string> &CommandLine) {
   CIWithContext =

>From 03051765b192fa0b5759875d1c7cd3ae3d58a711 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Wed, 22 Oct 2025 13:56:46 -0700
Subject: [PATCH 5/8] Address code review comments.

---
 .../include/clang/Frontend/FrontendActions.h  |  9 ---
 .../DependencyScanningTool.h                  |  2 +-
 .../DependencyScanningWorker.h                |  4 +-
 clang/lib/Frontend/FrontendActions.cpp        | 14 -----
 .../DependencyScannerImpl.cpp                 | 61 +++++--------------
 .../DependencyScannerImpl.h                   |  4 +-
 .../DependencyScanningTool.cpp                |  2 +-
 .../DependencyScanningWorker.cpp              |  3 +
 clang/tools/clang-scan-deps/ClangScanDeps.cpp |  2 +-
 9 files changed, 24 insertions(+), 77 deletions(-)
 rename clang/{include/clang => 
lib}/Tooling/DependencyScanning/DependencyScannerImpl.h (98%)

diff --git a/clang/include/clang/Frontend/FrontendActions.h 
b/clang/include/clang/Frontend/FrontendActions.h
index 73308c004bd23..87a9f0d4cb06c 100644
--- a/clang/include/clang/Frontend/FrontendActions.h
+++ b/clang/include/clang/Frontend/FrontendActions.h
@@ -320,15 +320,6 @@ class PrintPreprocessedAction : public 
PreprocessorFrontendAction {
   bool hasPCHSupport() const override { return true; }
 };
 
-class GetDependenciesByModuleNameAction : public PreprocessOnlyAction {
-  StringRef ModuleName;
-  void ExecuteAction() override;
-
-public:
-  GetDependenciesByModuleNameAction(StringRef ModuleName)
-      : ModuleName(ModuleName) {}
-};
-
 
//===----------------------------------------------------------------------===//
 // HLSL Specific Actions
 
//===----------------------------------------------------------------------===//
diff --git 
a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
index 506620d2bca2e..7668daf569d61 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -162,7 +162,7 @@ class DependencyScanningTool {
   /// @param CWD The current working directory used during the scan.
   /// @param CommandLine The commandline used for the scan.
   /// @return Error if the initializaiton fails.
-  llvm::Error initializeCompilerInstacneWithContext(
+  llvm::Error initializeCompilerInstanceWithContext(
       StringRef CWD, const std::vector<std::string> &CommandLine);
 
   /// @brief Computes the dependeny for the module named ModuleName.
diff --git 
a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h 
b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
index f5ff0e727ea94..af882442b7cf1 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -13,7 +13,6 @@
 #include "clang/Basic/FileManager.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Frontend/PCHContainerOperations.h"
-#include "clang/Tooling/DependencyScanning/DependencyScannerImpl.h"
 #include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
 #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
 #include "llvm/Support/Error.h"
@@ -30,6 +29,7 @@ namespace tooling {
 namespace dependencies {
 
 class DependencyScanningWorkerFilesystem;
+class CompilerInstanceWithContext;
 
 /// A command-line tool invocation that is part of building a TU.
 ///
@@ -90,6 +90,8 @@ class DependencyScanningWorker {
   DependencyScanningWorker(DependencyScanningService &Service,
                            llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS);
 
+  ~DependencyScanningWorker();
+
   /// Run the dependency scanning tool for a given clang driver command-line,
   /// and report the discovered dependencies to the provided consumer. If
   /// TUBuffer is not nullopt, it is used as TU input for the dependency
diff --git a/clang/lib/Frontend/FrontendActions.cpp 
b/clang/lib/Frontend/FrontendActions.cpp
index d7d56b8166350..3595bbc6c9b9e 100644
--- a/clang/lib/Frontend/FrontendActions.cpp
+++ b/clang/lib/Frontend/FrontendActions.cpp
@@ -1233,20 +1233,6 @@ void 
PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() {
                                     llvm::outs());
 }
 
-void GetDependenciesByModuleNameAction::ExecuteAction() {
-  CompilerInstance &CI = getCompilerInstance();
-  Preprocessor &PP = CI.getPreprocessor();
-  SourceManager &SM = PP.getSourceManager();
-  FileID MainFileID = SM.getMainFileID();
-  SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
-  SmallVector<IdentifierLoc, 2> Path;
-  IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName);
-  Path.emplace_back(FileStart, ModuleID);
-  auto ModResult = CI.loadModule(FileStart, Path, Module::Hidden, false);
-  PPCallbacks *CB = PP.getPPCallbacks();
-  CB->moduleImport(SourceLocation(), Path, ModResult);
-}
-
 
//===----------------------------------------------------------------------===//
 // HLSL Specific Actions
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index 33e3dbffd5eca..81e130f48cf84 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -6,7 +6,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
-#include "clang/Tooling/DependencyScanning/DependencyScannerImpl.h"
+#include "DependencyScannerImpl.h"
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Basic/DiagnosticSerialization.h"
 #include "clang/Driver/Driver.h"
@@ -490,9 +490,6 @@ bool initializeScanCompilerInstance(
     IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
     DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service,
     IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS) {
-  // TODO: the commented out code here should be un-commented when
-  // we enable CAS.
-  // ScanInstance.getInvocation().getCASOpts() = Worker.CASOpts;
   ScanInstance.setBuildingModule(false);
 
   ScanInstance.createVirtualFileSystem(FS, DiagConsumer);
@@ -728,20 +725,22 @@ llvm::Error CompilerInstanceWithContext::initialize() {
                                                llvm::inconvertibleErrorCode());
   }
 
+  assert(Compilation->getJobs().size() &&
+         "Must have a job list of non-zero size");
   const driver::Command &Command = *(Compilation->getJobs().begin());
   const auto &CommandArgs = Command.getArguments();
   size_t ArgSize = CommandArgs.size();
   assert(ArgSize >= 1 && "Cannot have a command with 0 args");
   const char *FirstArg = CommandArgs[0];
-  if (strcmp(FirstArg, "-cc1"))
+  if (StringRef(FirstArg) != "-cc1")
     return llvm::make_error<llvm::StringError>(
         "Incorrect compilation command, missing cc1",
         llvm::inconvertibleErrorCode());
-  Invocation = std::make_unique<CompilerInvocation>();
+  OriginalInvocation = std::make_unique<CompilerInvocation>();
 
-  if (!CompilerInvocation::CreateFromArgs(*Invocation, Command.getArguments(),
-                                          
*DiagEngineWithCmdAndOpts->DiagEngine,
-                                          Command.getExecutable())) {
+  if (!CompilerInvocation::CreateFromArgs(
+          *OriginalInvocation, Command.getArguments(),
+          *DiagEngineWithCmdAndOpts->DiagEngine, Command.getExecutable())) {
     DiagEngineWithCmdAndOpts->DiagEngine->Report(
         diag::err_fe_expected_compiler_job)
         << llvm::join(CommandLine, " ");
@@ -750,36 +749,15 @@ llvm::Error CompilerInstanceWithContext::initialize() {
         llvm::inconvertibleErrorCode());
   }
 
-  // TODO: CMDArgsStrVector is making string copies. We should optimize later
-  // and avoid the copies.
-  std::vector<std::string> CMDArgsStrVector(ArgSize + 1);
-  CMDArgsStrVector.push_back(Command.getExecutable());
-  llvm::transform(CommandArgs, CMDArgsStrVector.begin() + 1,
-                  [](const char *s) { return std::string(s); });
-
-  Invocation = createCompilerInvocation(CMDArgsStrVector,
-                                        *DiagEngineWithCmdAndOpts->DiagEngine);
-  if (!Invocation) {
-    DiagEngineWithCmdAndOpts->DiagEngine->Report(
-        diag::err_fe_expected_compiler_job)
-        << llvm::join(CommandLine, " ");
-    return llvm::make_error<llvm::StringError>(
-        "Cannot create CompilerInvocation from Args",
-        llvm::inconvertibleErrorCode());
-  }
-
-  Invocation->getFrontendOpts().DisableFree = false;
-  Invocation->getCodeGenOpts().DisableFree = false;
-
   if (any(Worker.Service.getOptimizeArgs() & ScanningOptimizations::Macros))
-    canonicalizeDefines(Invocation->getPreprocessorOpts());
+    canonicalizeDefines(OriginalInvocation->getPreprocessorOpts());
 
   // Create the CompilerInstance.
   IntrusiveRefCntPtr<ModuleCache> ModCache =
       makeInProcessModuleCache(Worker.Service.getModuleCacheEntries());
   CIPtr = std::make_unique<CompilerInstance>(
-      std::make_shared<CompilerInvocation>(*Invocation), 
Worker.PCHContainerOps,
-      ModCache.get());
+      std::make_shared<CompilerInvocation>(*OriginalInvocation),
+      Worker.PCHContainerOps, ModCache.get());
   auto &CI = *CIPtr;
 
   if (!initializeScanCompilerInstance(
@@ -801,7 +779,6 @@ llvm::Error CompilerInstanceWithContext::initialize() {
   OutputOpts = takeDependencyOutputOptionsFrom(CI);
 
   CI.createTarget();
-  // CI.initializeDelayedInputFileFromCAS();
 
   return llvm::Error::success();
 }
@@ -810,21 +787,19 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
     StringRef ModuleName, DependencyConsumer &Consumer,
     DependencyActionController &Controller) {
   auto &CI = *CIPtr;
-  CompilerInvocation Inv(*Invocation);
+  CompilerInvocation Inv(*OriginalInvocation);
 
   CI.clearDependencyCollectors();
   auto MDC = initializeScanInstanceDependencyCollector(
       CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, 
Consumer,
-      Worker.Service, *Invocation, Controller, PrebuiltModuleASTMap,
-      StableDirs);
+      Worker.Service, Inv, Controller, PrebuiltModuleASTMap, StableDirs);
 
   if (!SrcLocOffset) {
     // When SrcLocOffset is zero, we are at the beginning of the fake source
     // file. In this case, we call BeginSourceFile to initialize.
     std::unique_ptr<FrontendAction> Action =
-        std::make_unique<GetDependenciesByModuleNameAction>(ModuleName);
+        std::make_unique<PreprocessOnlyAction>();
     auto InputFile = CI.getFrontendOpts().Inputs.begin();
-
     Action->BeginSourceFile(CI, *InputFile);
   }
 
@@ -872,14 +847,6 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
   MDC->applyDiscoveredDependencies(Inv);
   Consumer.handleBuildCommand({CommandLine[0], Inv.getCC1CommandLine()});
 
-  // TODO: enable CAS
-  //   std::string ID = Inv.getFileSystemOpts().CASFileSystemRootID;
-  //   if (!ID.empty())
-  //     Consumer.handleCASFileSystemRootID(std::move(ID));
-  //   ID = Inv.getFrontendOpts().CASIncludeTreeID;
-  //   if (!ID.empty())
-  //     Consumer.handleIncludeTreeID(std::move(ID));
-
   // Remove the PPCallbacks since they are going out of scope.
   CI.getPreprocessor().removePPCallbacks();
   return llvm::Error::success();
diff --git 
a/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h 
b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
similarity index 98%
rename from 
clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
rename to clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
index 2b42d026728d5..f59af0b2b352f 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScannerImpl.h
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
@@ -10,7 +10,6 @@
 #define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNER_H
 
 #include "clang/Driver/Compilation.h"
-#include "clang/Driver/Driver.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
@@ -170,8 +169,7 @@ class CompilerInstanceWithContext {
   // Context - compiler invocation
   std::unique_ptr<clang::driver::Driver> Driver;
   std::unique_ptr<clang::driver::Compilation> Compilation;
-  std::unique_ptr<CompilerInvocation> Invocation;
-  llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFSFromCompilerInvocation;
+  std::unique_ptr<CompilerInvocation> OriginalInvocation;
 
   // Context - output options
   std::unique_ptr<DependencyOutputOptions> OutputOpts;
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index 91a357905be6b..703db6ab01d41 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -155,7 +155,7 @@ DependencyScanningTool::getTranslationUnitDependencies(
   return Consumer.takeTranslationUnitDeps();
 }
 
-llvm::Error DependencyScanningTool::initializeCompilerInstacneWithContext(
+llvm::Error DependencyScanningTool::initializeCompilerInstanceWithContext(
     StringRef CWD, const std::vector<std::string> &CommandLine) {
   return Worker.initializeCompierInstanceWithContext(CWD, CommandLine);
 }
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index e6793d77e3859..24028a06dbdb6 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -7,6 +7,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
+#include "DependencyScannerImpl.h"
 #include "clang/Basic/DiagnosticFrontend.h"
 #include "clang/Driver/Driver.h"
 #include "clang/Driver/Tool.h"
@@ -42,6 +43,8 @@ DependencyScanningWorker::DependencyScanningWorker(
   }
 }
 
+DependencyScanningWorker::~DependencyScanningWorker() = default;
+
 llvm::Error DependencyScanningWorker::computeDependencies(
     StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
     DependencyConsumer &Consumer, DependencyActionController &Controller,
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp 
b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 07146eff65cf2..c990e9372bbad 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -1085,7 +1085,7 @@ int clang_scan_deps_main(int argc, char **argv, const 
llvm::ToolContext &) {
             HadErrors = true;
         }
       } else if (ModuleName) {
-        if (llvm::Error Err = WorkerTool.initializeCompilerInstacneWithContext(
+        if (llvm::Error Err = WorkerTool.initializeCompilerInstanceWithContext(
                 CWD, Input->CommandLine)) {
           handleErrorWithInfoString(
               "Compiler instance with context setup error", std::move(Err),

>From 6e1c2ab35c22624d32c13d276fa5759eba6a4b92 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Thu, 23 Oct 2025 10:38:40 -0700
Subject: [PATCH 6/8] Address code review.

---
 .../DependencyScannerImpl.cpp                 | 24 +++++++++++++------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index 81e130f48cf84..b0f37bcf3ebfe 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -787,12 +787,15 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
     StringRef ModuleName, DependencyConsumer &Consumer,
     DependencyActionController &Controller) {
   auto &CI = *CIPtr;
-  CompilerInvocation Inv(*OriginalInvocation);
 
   CI.clearDependencyCollectors();
   auto MDC = initializeScanInstanceDependencyCollector(
       CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, 
Consumer,
-      Worker.Service, Inv, Controller, PrebuiltModuleASTMap, StableDirs);
+      Worker.Service,
+      /* The MDC's constructor makes a copy of the OriginalInvocation, so
+      we can pass it in without worrying that it might be changed across
+      invocations of computeDependencies. */
+      *OriginalInvocation, Controller, PrebuiltModuleASTMap, StableDirs);
 
   if (!SrcLocOffset) {
     // When SrcLocOffset is zero, we are at the beginning of the fake source
@@ -839,13 +842,20 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
   auto DCs = CI.getDependencyCollectors();
   for (auto &DC : DCs) {
     auto *CB = DC->getPPCallbacks();
-    assert(CB && "DC must have dependency collector callback");
-    CB->moduleImport(SourceLocation(), Path, ModResult);
-    CB->EndOfMainFile();
+    if (CB) {
+      CB->moduleImport(SourceLocation(), Path, ModResult);
+
+      // Note that we are calling the CB's EndOfMainFile function, which
+      // forwards the results to the dependency consumer.
+      // It does not indicate the end of processing the fake file.
+      CB->EndOfMainFile();
+    }
   }
 
-  MDC->applyDiscoveredDependencies(Inv);
-  Consumer.handleBuildCommand({CommandLine[0], Inv.getCC1CommandLine()});
+  CompilerInvocation ModuleInvocation(*OriginalInvocation);
+  MDC->applyDiscoveredDependencies(ModuleInvocation);
+  Consumer.handleBuildCommand(
+      {CommandLine[0], ModuleInvocation.getCC1CommandLine()});
 
   // Remove the PPCallbacks since they are going out of scope.
   CI.getPreprocessor().removePPCallbacks();

>From a5e8e16b7239613a2efea8a29a65b81c558341a2 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Thu, 23 Oct 2025 11:12:28 -0700
Subject: [PATCH 7/8] Fix build break.

---
 clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp | 2 +-
 clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h   | 3 +++
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index 1d0d5c250d3b2..bdcba01f05667 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -717,7 +717,7 @@ llvm::Error CompilerInstanceWithContext::initialize() {
       CommandLine, OverlayFS, DiagPrinterWithOS->DiagPrinter);
 
   std::tie(Driver, Compilation) = buildCompilation(
-      CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS);
+      CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS, Alloc);
 
   if (!Compilation) {
     return llvm::make_error<llvm::StringError>("Failed to build compilation",
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h 
b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
index 2f099b3be24f4..9d10753cc01e3 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
@@ -168,6 +168,9 @@ class CompilerInstanceWithContext {
   std::unique_ptr<DignosticsEngineWithDiagOpts> DiagEngineWithCmdAndOpts;
 
   // Context - compiler invocation
+  // Compilation's command's arguments may be owned by Alloc when expanded from
+  // response files, so we need to keep Alloc alive in the context.
+  llvm::BumpPtrAllocator Alloc;
   std::unique_ptr<clang::driver::Driver> Driver;
   std::unique_ptr<clang::driver::Compilation> Compilation;
   std::unique_ptr<CompilerInvocation> OriginalInvocation;

>From 6b551a86f6a2111502151b7a1e0e5384c2dd3ddc Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <[email protected]>
Date: Thu, 23 Oct 2025 14:00:10 -0700
Subject: [PATCH 8/8] Adding a test case of multiple name lookup using the
 shared compiler instance.

---
 .../DependencyScannerImpl.cpp                 |   5 +-
 clang/test/ClangScanDeps/link-libraries.c     |   2 +-
 .../ClangScanDeps/modules-full-by-mod-name.c  |   2 +-
 .../modules-full-by-mult-mod-names.c          | 108 ++++++++++++++++++
 clang/test/Modules/transitive-system.test     |   4 +-
 clang/tools/clang-scan-deps/ClangScanDeps.cpp |  30 +++--
 clang/tools/clang-scan-deps/Opts.td           |   4 +-
 7 files changed, 137 insertions(+), 18 deletions(-)
 create mode 100644 clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c

diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp 
b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index bdcba01f05667..666b98fcfb3f1 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -787,7 +787,6 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
     DependencyActionController &Controller) {
   auto &CI = *CIPtr;
 
-  CI.clearDependencyCollectors();
   auto MDC = initializeScanInstanceDependencyCollector(
       CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, 
Consumer,
       Worker.Service,
@@ -856,7 +855,9 @@ llvm::Error 
CompilerInstanceWithContext::computeDependencies(
   Consumer.handleBuildCommand(
       {CommandLine[0], ModuleInvocation.getCC1CommandLine()});
 
-  // Remove the PPCallbacks since they are going out of scope.
+  // Remove the DependencyCollecgtors and PPCallbacks since they are going out
+  // of scope.
+  CI.clearDependencyCollectors();
   CI.getPreprocessor().removePPCallbacks();
   return llvm::Error::success();
 }
diff --git a/clang/test/ClangScanDeps/link-libraries.c 
b/clang/test/ClangScanDeps/link-libraries.c
index cc2e223102024..3719d713e775c 100644
--- a/clang/test/ClangScanDeps/link-libraries.c
+++ b/clang/test/ClangScanDeps/link-libraries.c
@@ -32,7 +32,7 @@ module transitive {
 }]
 
 // RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
-// RUN: clang-scan-deps -compilation-database %t/cdb.json -format 
experimental-full -module-name=root > %t/result.json
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format 
experimental-full -module-names=root > %t/result.json
 // RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s
 
 // CHECK:      {
diff --git a/clang/test/ClangScanDeps/modules-full-by-mod-name.c 
b/clang/test/ClangScanDeps/modules-full-by-mod-name.c
index c838614d0bfde..edb99636aaf25 100644
--- a/clang/test/ClangScanDeps/modules-full-by-mod-name.c
+++ b/clang/test/ClangScanDeps/modules-full-by-mod-name.c
@@ -25,7 +25,7 @@ module transitive { header "transitive.h" }
 }]
 
 // RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
-// RUN: clang-scan-deps -compilation-database %t/cdb.json -format 
experimental-full -module-name=root > %t/result.json
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format 
experimental-full -module-names=root > %t/result.json
 // RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s
 
 // CHECK:      {
diff --git a/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c 
b/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c
new file mode 100644
index 0000000000000..030f7f3427810
--- /dev/null
+++ b/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c
@@ -0,0 +1,108 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+
+//--- module.modulemap
+module root { header "root.h" }
+module direct { header "direct.h" }
+module transitive { header "transitive.h" }
+module root1 { header "root1.h"}
+//--- root.h
+#include "direct.h"
+#include "root/textual.h"
+
+//--- root1.h
+#include "direct.h"
+
+//--- direct.h
+#include "transitive.h"
+//--- transitive.h
+// empty
+
+//--- root/textual.h
+// This is here to verify that the "root" directory doesn't clash with name of
+// the "root" module.
+
+//--- cdb.json.template
+[{
+  "file": "",
+  "directory": "DIR",
+  "command": "clang -fmodules -fmodules-cache-path=DIR/cache -I DIR -x c"
+}]
+
+// RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format 
experimental-full -module-names=root,root1,direct > %t/result.json
+// RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s
+
+// CHECK:      {
+// CHECK-NEXT:   "modules": [
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "clang-module-deps": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "context-hash": "{{.*}}",
+// CHECK-NEXT:           "module-name": "transitive"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT:       "command-line": [
+// CHECK:            ],
+// CHECK-NEXT:       "context-hash": "{{.*}}",
+// CHECK-NEXT:       "file-deps": [
+// CHECK-NEXT:         "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT:         "[[PREFIX]]/direct.h"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "link-libraries": [],
+// CHECK-NEXT:       "name": "direct"
+// CHECK-NEXT:     },
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "clang-module-deps": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "context-hash": "{{.*}}",
+// CHECK-NEXT:           "module-name": "direct"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT:       "command-line": [
+// CHECK:            ],
+// CHECK-NEXT:       "context-hash": "{{.*}}",
+// CHECK-NEXT:       "file-deps": [
+// CHECK-NEXT:         "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT:         "[[PREFIX]]/root.h",
+// CHECK-NEXT:         "[[PREFIX]]/root/textual.h"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "link-libraries": [],
+// CHECK-NEXT:       "name": "root"
+// CHECK-NEXT:     },
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "clang-module-deps": [
+// CHECK-NEXT:         {
+// CHECK-NEXT:           "context-hash": "{{.*}}",
+// CHECK-NEXT:           "module-name": "direct"
+// CHECK-NEXT:         }
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT:       "command-line": [
+// CHECK:            ],
+// CHECK-NEXT:       "context-hash": "{{.*}}",
+// CHECK-NEXT:       "file-deps": [
+// CHECK-NEXT:         "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT:         "[[PREFIX]]/root1.h"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "link-libraries": [],
+// CHECK-NEXT:       "name": "root1"
+// CHECK-NEXT:     },
+// CHECK-NEXT:     {
+// CHECK-NEXT:       "clang-module-deps": [],
+// CHECK-NEXT:       "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT:       "command-line": [
+// CHECK:            ],
+// CHECK-NEXT:       "context-hash": "{{.*}}",
+// CHECK-NEXT:       "file-deps": [
+// CHECK-NEXT:         "[[PREFIX]]/module.modulemap",
+// CHECK-NEXT:         "[[PREFIX]]/transitive.h"
+// CHECK-NEXT:       ],
+// CHECK-NEXT:       "link-libraries": [],
+// CHECK-NEXT:       "name": "transitive"
+// CHECK-NEXT:     }
+// CHECK-NEXT:   ],
+// CHECK-NEXT:   "translation-units": []
+// CHECK-NEXT: }
diff --git a/clang/test/Modules/transitive-system.test 
b/clang/test/Modules/transitive-system.test
index b1f1558b31742..5f6196cc1d6a3 100644
--- a/clang/test/Modules/transitive-system.test
+++ b/clang/test/Modules/transitive-system.test
@@ -2,9 +2,9 @@
 // RUN: split-file %s %t
 
 // RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
-// RUN: clang-scan-deps -compilation-database %t/cdb.json -format 
experimental-full -module-name=direct > %t/result1.json
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format 
experimental-full -module-names=direct > %t/result1.json
 // RUN: rm -rf %t/cache
-// RUN: clang-scan-deps -compilation-database %t/cdb.json -format 
experimental-full -module-name=transitive > %t/result2.json
+// RUN: clang-scan-deps -compilation-database %t/cdb.json -format 
experimental-full -module-names=transitive > %t/result2.json
 // RUN: %deps-to-rsp %t/result1.json --module-name transitive > %t/1.rsp
 // RUN: %deps-to-rsp %t/result2.json --module-name transitive > %t/2.rsp
 // RUN: diff %t/1.rsp %t/2.rsp
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp 
b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index ee627e6544123..65f0f40cc5b75 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -87,7 +87,7 @@ static std::string ModuleFilesDir;
 static bool EagerLoadModules;
 static unsigned NumThreads = 0;
 static std::string CompilationDB;
-static std::optional<std::string> ModuleName;
+static std::optional<std::string> ModuleNames;
 static std::vector<std::string> ModuleDepTargets;
 static std::string TranslationUnitFile;
 static bool DeprecatedDriverCommand;
@@ -205,8 +205,8 @@ static void ParseArgs(int argc, char **argv) {
   if (const llvm::opt::Arg *A = Args.getLastArg(OPT_compilation_database_EQ))
     CompilationDB = A->getValue();
 
-  if (const llvm::opt::Arg *A = Args.getLastArg(OPT_module_name_EQ))
-    ModuleName = A->getValue();
+  if (const llvm::opt::Arg *A = Args.getLastArg(OPT_module_names_EQ))
+    ModuleNames = A->getValue();
 
   for (const llvm::opt::Arg *A : Args.filtered(OPT_dependency_target_EQ))
     ModuleDepTargets.emplace_back(A->getValue());
@@ -1018,7 +1018,7 @@ int clang_scan_deps_main(int argc, char **argv, const 
llvm::ToolContext &) {
   };
 
   if (Format == ScanningOutputFormat::Full)
-    FD.emplace(!ModuleName ? Inputs.size() : 0);
+    FD.emplace(!ModuleNames ? Inputs.size() : 0);
 
   std::atomic<size_t> NumStatusCalls = 0;
   std::atomic<size_t> NumOpenFileForReadCalls = 0;
@@ -1092,7 +1092,11 @@ int clang_scan_deps_main(int argc, char **argv, const 
llvm::ToolContext &) {
                                              MakeformatOS, Errs))
             HadErrors = true;
         }
-      } else if (ModuleName) {
+      } else if (ModuleNames) {
+        StringRef ModuleNameRef(*ModuleNames);
+        SmallVector<StringRef> Names;
+        ModuleNameRef.split(Names, ',');
+
         if (llvm::Error Err = WorkerTool.initializeCompilerInstanceWithContext(
                 CWD, Input->CommandLine)) {
           handleErrorWithInfoString(
@@ -1102,12 +1106,16 @@ int clang_scan_deps_main(int argc, char **argv, const 
llvm::ToolContext &) {
           continue;
         }
 
-        auto MaybeModuleDepsGraph =
-            WorkerTool.computeDependenciesByNameWithContext(
-                *ModuleName, AlreadySeenModules, LookupOutput);
-        if (handleModuleResult(*ModuleName, MaybeModuleDepsGraph, *FD,
-                               LocalIndex, DependencyOS, Errs))
-          HadErrors = true;
+        for (auto N : Names) {
+          auto MaybeModuleDepsGraph =
+              WorkerTool.computeDependenciesByNameWithContext(
+                  N, AlreadySeenModules, LookupOutput);
+          if (handleModuleResult(N, MaybeModuleDepsGraph, *FD, LocalIndex,
+                                 DependencyOS, Errs)) {
+            HadErrors = true;
+            break;
+          }
+        }
 
         if (llvm::Error Err =
                 WorkerTool.finalizeCompilerInstanceWithContext()) {
diff --git a/clang/tools/clang-scan-deps/Opts.td 
b/clang/tools/clang-scan-deps/Opts.td
index 7a63b18f6d462..6ea9d824c9646 100644
--- a/clang/tools/clang-scan-deps/Opts.td
+++ b/clang/tools/clang-scan-deps/Opts.td
@@ -26,7 +26,9 @@ def eager_load_pcm : F<"eager-load-pcm", "Load PCM files 
eagerly (instead of laz
 def j : Arg<"j", "Number of worker threads to use (default: use all concurrent 
threads)">;
 
 defm compilation_database : Eq<"compilation-database", "Compilation database">;
-defm module_name : Eq<"module-name", "the module of which the dependencies are 
to be computed">;
+defm module_names
+    : Eq<"module-names", "A comma separated list of names of modules of which "
+                         "the dependencies are to be computed">;
 defm dependency_target : Eq<"dependency-target", "The names of dependency 
targets for the dependency file">;
 
 defm tu_buffer_path: Eq<"tu-buffer-path", "The path to the translation unit 
for depscan. Not compatible with -module-name">;

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to