[clang] [clang][DependencyScanning] Implementation of `CompilerInstanceWithContext` to Improve By-Name Queries (PR #164345)
Qiongsi Wu via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 23 14:54:35 PDT 2025
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 <qiongsi_wu at apple.com>
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 <qiongsi_wu at apple.com>
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 <qiongsi_wu at apple.com>
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 <qiongsi_wu at apple.com>
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 <qiongsi_wu at apple.com>
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 <qiongsi_wu at apple.com>
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 <qiongsi_wu at apple.com>
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 6161886b8b574236ace3625175e80b5925f713cf Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
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 | 10 +-
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, 142 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..ff1dbe4995b7a 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -777,6 +777,11 @@ llvm::Error CompilerInstanceWithContext::initialize() {
PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
OutputOpts = takeDependencyOutputOptionsFrom(CI);
+ // We do not create the target in initializeScanCompilerInstance because
+ // setting it here is unique for by-name lookups. We create the target only
+ // once here, and the information is reused for all computeDependencies calls.
+ // We do not need to call createTarget explicitly if we go through
+ // CompilerInstance::ExecuteAction to perform scanning.
CI.createTarget();
return llvm::Error::success();
@@ -787,7 +792,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 +860,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">;
More information about the cfe-commits
mailing list