[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 Nov 6 16:49:17 PST 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 01/13] 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 02/13] 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 03/13] 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 04/13] 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 05/13] 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 06/13] 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 07/13] 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 08/13] 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">;
>From 0403d3f86c82db2ba679867adb85be82b8957fef Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
Date: Thu, 23 Oct 2025 15:28:00 -0700
Subject: [PATCH 09/13] Remove the getPPCallbacks interface from
DependencyCollector.
---
clang/include/clang/Frontend/Utils.h | 4 --
.../DependencyScanning/ModuleDepCollector.h | 2 +-
.../DependencyScannerImpl.cpp | 40 ++++++++-----------
3 files changed, 17 insertions(+), 29 deletions(-)
diff --git a/clang/include/clang/Frontend/Utils.h b/clang/include/clang/Frontend/Utils.h
index b58bbc6235b02..49fd920d1ec43 100644
--- a/clang/include/clang/Frontend/Utils.h
+++ b/clang/include/clang/Frontend/Utils.h
@@ -40,7 +40,6 @@ class DiagnosticsEngine;
class ExternalSemaSource;
class FrontendOptions;
class PCHContainerReader;
-class PPCallbacks;
class Preprocessor;
class PreprocessorOptions;
class PreprocessorOutputOptions;
@@ -88,9 +87,6 @@ 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/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index fe9e9b364726e..9c6e3bfd8d97b 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -288,7 +288,7 @@ class ModuleDepCollector final : public DependencyCollector {
void attachToPreprocessor(Preprocessor &PP) override;
void attachToASTReader(ASTReader &R) override;
- PPCallbacks *getPPCallbacks() override { return CollectorPPPtr; }
+ PPCallbacks *getPPCallbacks() { return CollectorPPPtr; }
/// Apply any changes implied by the discovered dependencies to the given
/// invocation, (e.g. disable implicit modules, add explicit module paths).
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index ff1dbe4995b7a..0b8401f678642 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -814,26 +814,24 @@ llvm::Error CompilerInstanceWithContext::computeDependencies(
FileID MainFileID = SM.getMainFileID();
SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID);
SourceLocation IDLocation = FileStart.getLocWithOffset(SrcLocOffset);
+ PPCallbacks *CB = nullptr;
if (!SrcLocOffset) {
// We need to call EnterSourceFile when SrcLocOffset is zero to initialize
// the preprocessor.
PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
+ CB = MDC->getPPCallbacks();
} 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);
- auto *CB = DC->getPPCallbacks();
-
- FileID PrevFID;
- SrcMgr::CharacteristicKind FileType =
- SM.getFileCharacteristic(IDLocation);
- CB->LexedFileChanged(MainFileID,
- PPChainedCallbacks::LexedFileChangeReason::EnterFile,
- FileType, PrevFID, IDLocation);
- }
+ MDC->attachToPreprocessor(PP);
+ CB = MDC->getPPCallbacks();
+
+ FileID PrevFID;
+ SrcMgr::CharacteristicKind FileType = SM.getFileCharacteristic(IDLocation);
+ CB->LexedFileChanged(MainFileID,
+ PPChainedCallbacks::LexedFileChangeReason::EnterFile,
+ FileType, PrevFID, IDLocation);
}
SrcLocOffset++;
@@ -842,18 +840,12 @@ llvm::Error CompilerInstanceWithContext::computeDependencies(
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();
- 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();
- }
- }
+ assert(CB && "Must have PPCallbacks after module loading");
+ 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();
CompilerInvocation ModuleInvocation(*OriginalInvocation);
MDC->applyDiscoveredDependencies(ModuleInvocation);
>From 9691b5b8f791e8cab35b7c6db1b16bcba63474af Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
Date: Thu, 23 Oct 2025 15:35:53 -0700
Subject: [PATCH 10/13] Address review comments.
---
.../Tooling/DependencyScanning/DependencyScanningWorker.h | 4 ++--
.../Tooling/DependencyScanning/DependencyScannerImpl.cpp | 6 +++---
.../lib/Tooling/DependencyScanning/DependencyScannerImpl.h | 2 +-
.../Tooling/DependencyScanning/DependencyScanningTool.cpp | 2 +-
.../Tooling/DependencyScanning/DependencyScanningWorker.cpp | 2 +-
5 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
index af882442b7cf1..c56a2e1c87cc0 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -125,7 +125,7 @@ class DependencyScanningWorker {
/// @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(
+ llvm::Error initializeCompilerInstanceWithContext(
StringRef CWD, const std::vector<std::string> &CommandLine);
/// @brief Performaces dependency scanning for the module whose name is
@@ -159,7 +159,7 @@ class DependencyScanningWorker {
/// (passed in the constructor).
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
- friend class CompilerInstanceWithContext;
+ friend CompilerInstanceWithContext;
std::unique_ptr<CompilerInstanceWithContext> CIWithContext;
/// Private helper functions.
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index 0b8401f678642..cf65272b9c43d 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -589,7 +589,7 @@ computePrebuiltModulesASTMap(CompilerInstance &ScanInstance,
}
std::unique_ptr<DependencyOutputOptions>
-takeDependencyOutputOptionsFrom(CompilerInstance &ScanInstance) {
+takeAndUpdateDependencyOutputOptionsFrom(CompilerInstance &ScanInstance) {
// This function moves the existing dependency output options from the
// invocation to the collector. The options in the invocation are reset,
// which ensures that the compiler won't create new dependency collectors,
@@ -676,7 +676,7 @@ bool DependencyScanningAction::runInvocation(
if (!MaybePrebuiltModulesASTMap)
return false;
- auto DepOutputOpts = takeDependencyOutputOptionsFrom(ScanInstance);
+ auto DepOutputOpts = takeAndUpdateDependencyOutputOptionsFrom(ScanInstance);
MDC = initializeScanInstanceDependencyCollector(
ScanInstance, std::move(DepOutputOpts), WorkingDirectory, Consumer,
@@ -775,7 +775,7 @@ llvm::Error CompilerInstanceWithContext::initialize() {
"Prebuilt module scanning failed", llvm::inconvertibleErrorCode());
PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
- OutputOpts = takeDependencyOutputOptionsFrom(CI);
+ OutputOpts = takeAndUpdateDependencyOutputOptionsFrom(CI);
// We do not create the target in initializeScanCompilerInstance because
// setting it here is unique for by-name lookups. We create the target only
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
index 9d10753cc01e3..accd36fba6824 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
@@ -138,7 +138,7 @@ computePrebuiltModulesASTMap(CompilerInstance &ScanInstance,
SmallVector<StringRef> &StableDirs);
std::unique_ptr<DependencyOutputOptions>
-takeDependencyOutputOptionsFrom(CompilerInstance &ScanInstance);
+takeAndUpdateDependencyOutputOptionsFrom(CompilerInstance &ScanInstance);
/// Create the dependency collector that will collect the produced
/// dependencies. May return the created ModuleDepCollector depending
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index 703db6ab01d41..f3bc99d66d07d 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -157,7 +157,7 @@ DependencyScanningTool::getTranslationUnitDependencies(
llvm::Error DependencyScanningTool::initializeCompilerInstanceWithContext(
StringRef CWD, const std::vector<std::string> &CommandLine) {
- return Worker.initializeCompierInstanceWithContext(CWD, CommandLine);
+ return Worker.initializeCompilerInstanceWithContext(CWD, CommandLine);
}
llvm::Expected<TranslationUnitDeps>
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index d6006c1b30bd8..37e54a63217b3 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -167,7 +167,7 @@ bool DependencyScanningWorker::computeDependencies(
}
}
-llvm::Error DependencyScanningWorker::initializeCompierInstanceWithContext(
+llvm::Error DependencyScanningWorker::initializeCompilerInstanceWithContext(
StringRef CWD, const std::vector<std::string> &CommandLine) {
CIWithContext =
std::make_unique<CompilerInstanceWithContext>(*this, CWD, CommandLine);
>From b393d6a75703f1b3a1e8b04762e2b5ffde996694 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
Date: Fri, 31 Oct 2025 15:49:12 -0700
Subject: [PATCH 11/13] Adding error checking to computeDependencies and remove
unused string buffer.
---
.../DependencyScannerImpl.cpp | 31 +++++++++++++------
.../DependencyScannerImpl.h | 2 --
2 files changed, 22 insertions(+), 11 deletions(-)
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index cf65272b9c43d..33dc785a4a5aa 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -12,6 +12,7 @@
#include "clang/Driver/Driver.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/TargetParser/Host.h"
using namespace clang;
@@ -704,9 +705,6 @@ bool DependencyScanningAction::runInvocation(
return Result;
}
-const std::string CompilerInstanceWithContext::FakeFileBuffer =
- std::string(MAX_NUM_NAMES, ' ');
-
llvm::Error CompilerInstanceWithContext::initialize() {
std::tie(OverlayFS, CommandLine) = initVFSForByNameScanning(
Worker.BaseFS, CommandLine, CWD, "ScanningByName");
@@ -792,6 +790,17 @@ llvm::Error CompilerInstanceWithContext::computeDependencies(
DependencyActionController &Controller) {
auto &CI = *CIPtr;
+ // We create this cleanup object because computeDependencies may exit
+ // early with errors.
+ auto CleanUp = llvm::make_scope_exit([&]() {
+ CI.clearDependencyCollectors();
+ // The preprocessor may not be created at the entry of this method,
+ // but it must have been created when this method returns, whether
+ // there are errors during scanning or not.
+ CI.getPreprocessor().removePPCallbacks();
+ });
+
+ CI.clearDependencyCollectors();
auto MDC = initializeScanInstanceDependencyCollector(
CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, Consumer,
Worker.Service,
@@ -806,7 +815,9 @@ llvm::Error CompilerInstanceWithContext::computeDependencies(
std::unique_ptr<FrontendAction> Action =
std::make_unique<PreprocessOnlyAction>();
auto InputFile = CI.getFrontendOpts().Inputs.begin();
- Action->BeginSourceFile(CI, *InputFile);
+ bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile);
+ assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed");
+ (void)ActionBeginSucceeded;
}
Preprocessor &PP = CI.getPreprocessor();
@@ -818,7 +829,9 @@ llvm::Error CompilerInstanceWithContext::computeDependencies(
if (!SrcLocOffset) {
// We need to call EnterSourceFile when SrcLocOffset is zero to initialize
// the preprocessor.
- PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
+ bool PPFailed = PP.EnterSourceFile(MainFileID, nullptr, SourceLocation());
+ assert(!PPFailed && "Preprocess must be able to enter the main file.");
+ (void)PPFailed;
CB = MDC->getPPCallbacks();
} else {
// When SrcLocOffset is non-zero, the preprocessor has already been
@@ -847,15 +860,15 @@ llvm::Error CompilerInstanceWithContext::computeDependencies(
// It does not indicate the end of processing the fake file.
CB->EndOfMainFile();
+ if (!ModResult)
+ return llvm::make_error<llvm::StringError>(
+ DiagPrinterWithOS->DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
+
CompilerInvocation ModuleInvocation(*OriginalInvocation);
MDC->applyDiscoveredDependencies(ModuleInvocation);
Consumer.handleBuildCommand(
{CommandLine[0], ModuleInvocation.getCC1CommandLine()});
- // 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/lib/Tooling/DependencyScanning/DependencyScannerImpl.h b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
index accd36fba6824..d6f68e0ebc678 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
@@ -157,8 +157,6 @@ class CompilerInstanceWithContext {
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;
>From e32945139f88deea9d8ddb0313dbfbdf4f043e66 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
Date: Mon, 3 Nov 2025 11:24:35 -0800
Subject: [PATCH 12/13] Adding back the by-name API to DependencyScanningTool
to make it easier to land for Swift.
---
.../DependencyScanningTool.h | 11 ++++
.../DependencyScanningTool.cpp | 23 ++++++++
clang/tools/clang-scan-deps/ClangScanDeps.cpp | 56 +++++++++++--------
3 files changed, 67 insertions(+), 23 deletions(-)
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
index 7668daf569d61..ed562f46cfdaa 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h
@@ -151,6 +151,17 @@ 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.
+ /// TODO: this method should be removed as soon as Swift and our C-APIs adopt
+ /// CompilerInstanceWithContext. We are keeping it here so that it is easier
+ /// to coordinate with Swift and C-API changes.
+ 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/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index f3bc99d66d07d..675684604047c 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -155,6 +155,29 @@ 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);
+ if (auto Error =
+ Worker.initializeCompilerInstanceWithContext(CWD, CommandLine))
+ return std::move(Error);
+
+ auto Result = Worker.computeDependenciesByNameWithContext(
+ ModuleName, Consumer, Controller);
+
+ if (auto Error = Worker.finalizeCompilerInstanceWithContext())
+ return std::move(Error);
+
+ if (Result)
+ return std::move(Result);
+
+ return Consumer.takeTranslationUnitDeps();
+}
+
llvm::Error DependencyScanningTool::initializeCompilerInstanceWithContext(
StringRef CWD, const std::vector<std::string> &CommandLine) {
return Worker.initializeCompilerInstanceWithContext(CWD, CommandLine);
diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 65f0f40cc5b75..5f5bf42df5e6b 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -1097,32 +1097,42 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
SmallVector<StringRef> Names;
ModuleNameRef.split(Names, ',');
- if (llvm::Error Err = WorkerTool.initializeCompilerInstanceWithContext(
- CWD, Input->CommandLine)) {
- handleErrorWithInfoString(
- "Compiler instance with context setup error", std::move(Err),
- DependencyOS, Errs);
- HadErrors = true;
- continue;
- }
-
- for (auto N : Names) {
- auto MaybeModuleDepsGraph =
- WorkerTool.computeDependenciesByNameWithContext(
- N, AlreadySeenModules, LookupOutput);
- if (handleModuleResult(N, MaybeModuleDepsGraph, *FD, LocalIndex,
- DependencyOS, Errs)) {
+ if (Names.size() == 1) {
+ auto MaybeModuleDepsGraph = WorkerTool.getModuleDependencies(
+ Names[0], Input->CommandLine, CWD, AlreadySeenModules,
+ LookupOutput);
+ if (handleModuleResult(Names[0], MaybeModuleDepsGraph, *FD,
+ LocalIndex, DependencyOS, Errs))
HadErrors = true;
- break;
+ } else {
+ if (llvm::Error Err =
+ WorkerTool.initializeCompilerInstanceWithContext(
+ CWD, Input->CommandLine)) {
+ handleErrorWithInfoString(
+ "Compiler instance with context setup error", std::move(Err),
+ DependencyOS, Errs);
+ HadErrors = true;
+ continue;
}
- }
- if (llvm::Error Err =
- WorkerTool.finalizeCompilerInstanceWithContext()) {
- handleErrorWithInfoString(
- "Compiler instance with context finialization error",
- std::move(Err), 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()) {
+ handleErrorWithInfoString(
+ "Compiler instance with context finialization error",
+ std::move(Err), DependencyOS, Errs);
+ HadErrors = true;
+ }
}
} else {
std::unique_ptr<llvm::MemoryBuffer> TU;
>From 356c48d1c2f099c2e7ce8f555e40ae542e76f6f5 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
Date: Mon, 3 Nov 2025 17:10:29 -0800
Subject: [PATCH 13/13] Adding a set of APIs that returns a flag instead of
llvm::Erros to DepedencyScanningWorker. Fix two minor issues.
---
.../DependencyScanningWorker.h | 25 +++++--
.../DependencyScanning/ModuleDepCollector.h | 3 +-
.../DependencyScannerImpl.cpp | 70 ++++++++++---------
.../DependencyScannerImpl.h | 18 +++--
.../DependencyScanningTool.cpp | 12 ++--
.../DependencyScanningWorker.cpp | 38 +++++++---
6 files changed, 105 insertions(+), 61 deletions(-)
diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
index c56a2e1c87cc0..e2c353a254bf3 100644
--- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
+++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h
@@ -125,7 +125,7 @@ class DependencyScanningWorker {
/// @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 initializeCompilerInstanceWithContext(
+ llvm::Error initializeCompilerInstanceWithContextOrError(
StringRef CWD, const std::vector<std::string> &CommandLine);
/// @brief Performaces dependency scanning for the module whose name is
@@ -135,14 +135,27 @@ class DependencyScanningWorker {
/// @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);
+ llvm::Error computeDependenciesByNameWithContextOrError(
+ 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::Error finalizeCompilerInstanceWithContextOrError();
+
+ /// The three methods below provides the same functionality as the
+ /// three methods above. Instead of returning `llvm::Error`s, these
+ /// three methods return a flag to indicate if the call is successful.
+ /// The initialization function asks the client for a DiagnosticsConsumer
+ /// that it direct the diagnostics to.
+ bool initializeCompilerInstanceWithContext(
+ StringRef CWD, const std::vector<std::string> &CommandLine,
+ DiagnosticConsumer *DC = nullptr);
+ bool
+ computeDependenciesByNameWithContext(StringRef ModuleName,
+ DependencyConsumer &Consumer,
+ DependencyActionController &Controller);
+ bool finalizeCompilerInstance();
llvm::vfs::FileSystem &getVFS() const { return *BaseFS; }
diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
index 9c6e3bfd8d97b..b0a91b60ff6da 100644
--- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
+++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h
@@ -342,7 +342,8 @@ class ModuleDepCollector final : public DependencyCollector {
std::vector<P1689ModuleInfo> RequiredStdCXXModules;
/// A pointer to the preprocessor callback so we can invoke it directly
- /// if needed.
+ /// if needed. The callback is created and added to a Preprocessor instance by
+ /// attachToPreprocessor and the Preprocessor instance owns it.
ModuleDepCollectorPP *CollectorPPPtr = nullptr;
/// Checks whether the module is known as being prebuilt.
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
index 33dc785a4a5aa..fff26ea9d115a 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.cpp
@@ -705,22 +705,26 @@ bool DependencyScanningAction::runInvocation(
return Result;
}
-llvm::Error CompilerInstanceWithContext::initialize() {
- std::tie(OverlayFS, CommandLine) = initVFSForByNameScanning(
- Worker.BaseFS, CommandLine, CWD, "ScanningByName");
+bool CompilerInstanceWithContext::initialize(DiagnosticConsumer *DC) {
+ if (DC) {
+ DiagConsumer = DC;
+ } else {
+ DiagPrinterWithOS =
+ std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine);
+ DiagConsumer = &DiagPrinterWithOS->DiagPrinter;
+ }
- DiagPrinterWithOS =
- std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine);
DiagEngineWithCmdAndOpts = std::make_unique<DignosticsEngineWithDiagOpts>(
- CommandLine, OverlayFS, DiagPrinterWithOS->DiagPrinter);
+ CommandLine, OverlayFS, *DiagConsumer);
+
+ std::tie(OverlayFS, CommandLine) = initVFSForByNameScanning(
+ Worker.BaseFS, CommandLine, CWD, "ScanningByName");
std::tie(Driver, Compilation) = buildCompilation(
CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS, Alloc);
- if (!Compilation) {
- return llvm::make_error<llvm::StringError>("Failed to build compilation",
- llvm::inconvertibleErrorCode());
- }
+ if (!Compilation)
+ return false;
assert(Compilation->getJobs().size() &&
"Must have a job list of non-zero size");
@@ -729,10 +733,7 @@ llvm::Error CompilerInstanceWithContext::initialize() {
size_t ArgSize = CommandArgs.size();
assert(ArgSize >= 1 && "Cannot have a command with 0 args");
const char *FirstArg = CommandArgs[0];
- if (StringRef(FirstArg) != "-cc1")
- return llvm::make_error<llvm::StringError>(
- "Incorrect compilation command, missing cc1",
- llvm::inconvertibleErrorCode());
+ assert(StringRef(FirstArg) == "-cc1" && "Requires a cc1 job.");
OriginalInvocation = std::make_unique<CompilerInvocation>();
if (!CompilerInvocation::CreateFromArgs(
@@ -741,9 +742,7 @@ llvm::Error CompilerInstanceWithContext::initialize() {
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());
+ return false;
}
if (any(Worker.Service.getOptimizeArgs() & ScanningOptimizations::Macros))
@@ -759,18 +758,14 @@ llvm::Error CompilerInstanceWithContext::initialize() {
if (!initializeScanCompilerInstance(
CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(),
- Worker.Service, Worker.DepFS)) {
- return llvm::make_error<llvm::StringError>(
- "Cannot initialize scanning compiler instance",
- llvm::inconvertibleErrorCode());
- }
+ Worker.Service, Worker.DepFS))
+ return false;
- llvm::SmallVector<StringRef> StableDirs = getInitialStableDirs(CI);
+ StableDirs = getInitialStableDirs(CI);
auto MaybePrebuiltModulesASTMap =
computePrebuiltModulesASTMap(CI, StableDirs);
if (!MaybePrebuiltModulesASTMap)
- return llvm::make_error<llvm::StringError>(
- "Prebuilt module scanning failed", llvm::inconvertibleErrorCode());
+ return false;
PrebuiltModuleASTMap = std::move(*MaybePrebuiltModulesASTMap);
OutputOpts = takeAndUpdateDependencyOutputOptionsFrom(CI);
@@ -782,12 +777,13 @@ llvm::Error CompilerInstanceWithContext::initialize() {
// CompilerInstance::ExecuteAction to perform scanning.
CI.createTarget();
- return llvm::Error::success();
+ return true;
}
-llvm::Error CompilerInstanceWithContext::computeDependencies(
+bool CompilerInstanceWithContext::computeDependencies(
StringRef ModuleName, DependencyConsumer &Consumer,
DependencyActionController &Controller) {
+ assert(CIPtr && "CIPtr must be initialized before calling this method");
auto &CI = *CIPtr;
// We create this cleanup object because computeDependencies may exit
@@ -800,7 +796,6 @@ llvm::Error CompilerInstanceWithContext::computeDependencies(
CI.getPreprocessor().removePPCallbacks();
});
- CI.clearDependencyCollectors();
auto MDC = initializeScanInstanceDependencyCollector(
CI, std::make_unique<DependencyOutputOptions>(*OutputOpts), CWD, Consumer,
Worker.Service,
@@ -861,18 +856,25 @@ llvm::Error CompilerInstanceWithContext::computeDependencies(
CB->EndOfMainFile();
if (!ModResult)
- return llvm::make_error<llvm::StringError>(
- DiagPrinterWithOS->DiagnosticsOS.str(), llvm::inconvertibleErrorCode());
+ return false;
CompilerInvocation ModuleInvocation(*OriginalInvocation);
MDC->applyDiscoveredDependencies(ModuleInvocation);
Consumer.handleBuildCommand(
{CommandLine[0], ModuleInvocation.getCC1CommandLine()});
- return llvm::Error::success();
+ return true;
+}
+
+bool CompilerInstanceWithContext::finalize() {
+ DiagConsumer->finish();
+ return true;
}
-llvm::Error CompilerInstanceWithContext::finalize() {
- DiagPrinterWithOS->DiagPrinter.finish();
- return llvm::Error::success();
+llvm::Error CompilerInstanceWithContext::handleReturnStatus(bool Success) {
+ assert(DiagPrinterWithOS && "Must use the default DiagnosticConsumer.");
+ return Success ? llvm::Error::success()
+ : llvm::make_error<llvm::StringError>(
+ DiagPrinterWithOS->DiagnosticsOS.str(),
+ llvm::inconvertibleErrorCode());
}
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
index d6f68e0ebc678..54166dabebb05 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScannerImpl.h
@@ -163,6 +163,9 @@ class CompilerInstanceWithContext {
// Context - Diagnostics engine.
std::unique_ptr<TextDiagnosticsPrinterWithOutput> DiagPrinterWithOS;
+ // DiagConsumer may points to DiagPrinterWithOS->DiagPrinter, or a custom
+ // DiagnosticConsumer passed in from initialize.
+ DiagnosticConsumer *DiagConsumer = nullptr;
std::unique_ptr<DignosticsEngineWithDiagOpts> DiagEngineWithCmdAndOpts;
// Context - compiler invocation
@@ -191,11 +194,16 @@ class CompilerInstanceWithContext {
const std::vector<std::string> &CMD)
: Worker(Worker), CWD(CWD), CommandLine(CMD) {};
- llvm::Error initialize();
- llvm::Error computeDependencies(StringRef ModuleName,
- DependencyConsumer &Consumer,
- DependencyActionController &Controller);
- llvm::Error finalize();
+ // The three methods below returns false when they fail, with the detail
+ // accumulated in DiagConsumer.
+ bool initialize(DiagnosticConsumer *DC);
+ bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer,
+ DependencyActionController &Controller);
+ bool finalize();
+
+ // The method below turns the return status from the above methods
+ // into an llvm::Error using a default DiagnosticConsumer.
+ llvm::Error handleReturnStatus(bool Success);
};
} // namespace dependencies
} // namespace tooling
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
index 675684604047c..a1f2db7a471be 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -163,13 +163,13 @@ DependencyScanningTool::getModuleDependencies(
FullDependencyConsumer Consumer(AlreadySeen);
CallbackActionController Controller(LookupModuleOutput);
if (auto Error =
- Worker.initializeCompilerInstanceWithContext(CWD, CommandLine))
+ Worker.initializeCompilerInstanceWithContextOrError(CWD, CommandLine))
return std::move(Error);
- auto Result = Worker.computeDependenciesByNameWithContext(
+ auto Result = Worker.computeDependenciesByNameWithContextOrError(
ModuleName, Consumer, Controller);
- if (auto Error = Worker.finalizeCompilerInstanceWithContext())
+ if (auto Error = Worker.finalizeCompilerInstanceWithContextOrError())
return std::move(Error);
if (Result)
@@ -180,7 +180,7 @@ DependencyScanningTool::getModuleDependencies(
llvm::Error DependencyScanningTool::initializeCompilerInstanceWithContext(
StringRef CWD, const std::vector<std::string> &CommandLine) {
- return Worker.initializeCompilerInstanceWithContext(CWD, CommandLine);
+ return Worker.initializeCompilerInstanceWithContextOrError(CWD, CommandLine);
}
llvm::Expected<TranslationUnitDeps>
@@ -189,7 +189,7 @@ DependencyScanningTool::computeDependenciesByNameWithContext(
LookupModuleOutputCallback LookupModuleOutput) {
FullDependencyConsumer Consumer(AlreadySeen);
CallbackActionController Controller(LookupModuleOutput);
- llvm::Error Result = Worker.computeDependenciesByNameWithContext(
+ llvm::Error Result = Worker.computeDependenciesByNameWithContextOrError(
ModuleName, Consumer, Controller);
if (Result)
return std::move(Result);
@@ -198,7 +198,7 @@ DependencyScanningTool::computeDependenciesByNameWithContext(
}
llvm::Error DependencyScanningTool::finalizeCompilerInstanceWithContext() {
- return Worker.finalizeCompilerInstanceWithContext();
+ return Worker.finalizeCompilerInstanceWithContextOrError();
}
TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() {
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 37e54a63217b3..dc408b10542c3 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -44,6 +44,7 @@ DependencyScanningWorker::DependencyScanningWorker(
}
DependencyScanningWorker::~DependencyScanningWorker() = default;
+DependencyActionController::~DependencyActionController() = default;
llvm::Error DependencyScanningWorker::computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
@@ -167,24 +168,43 @@ bool DependencyScanningWorker::computeDependencies(
}
}
-llvm::Error DependencyScanningWorker::initializeCompilerInstanceWithContext(
+llvm::Error
+DependencyScanningWorker::initializeCompilerInstanceWithContextOrError(
StringRef CWD, const std::vector<std::string> &CommandLine) {
+ bool Success = initializeCompilerInstanceWithContext(CWD, CommandLine);
+ return CIWithContext->handleReturnStatus(Success);
+}
+
+llvm::Error
+DependencyScanningWorker::computeDependenciesByNameWithContextOrError(
+ StringRef ModuleName, DependencyConsumer &Consumer,
+ DependencyActionController &Controller) {
+ bool Success =
+ computeDependenciesByNameWithContext(ModuleName, Consumer, Controller);
+ return CIWithContext->handleReturnStatus(Success);
+}
+
+llvm::Error
+DependencyScanningWorker::finalizeCompilerInstanceWithContextOrError() {
+ bool Success = finalizeCompilerInstance();
+ return CIWithContext->handleReturnStatus(Success);
+}
+
+bool DependencyScanningWorker::initializeCompilerInstanceWithContext(
+ StringRef CWD, const std::vector<std::string> &CommandLine,
+ DiagnosticConsumer *DC) {
CIWithContext =
std::make_unique<CompilerInstanceWithContext>(*this, CWD, CommandLine);
- return CIWithContext->initialize();
+ return CIWithContext->initialize(DC);
}
-llvm::Error DependencyScanningWorker::computeDependenciesByNameWithContext(
+bool 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;
+bool DependencyScanningWorker::finalizeCompilerInstance() {
+ return CIWithContext->finalize();
}
-
-DependencyActionController::~DependencyActionController() {}
More information about the cfe-commits
mailing list