https://github.com/naveen-seth updated https://github.com/llvm/llvm-project/pull/171238
>From 436c999cb584b966b19bca4cce79684eea7fe354 Mon Sep 17 00:00:00 2001 From: Naveen Seth Hanig <[email protected]> Date: Tue, 9 Dec 2025 02:04:46 +0100 Subject: [PATCH 1/3] [clang][DependencyScanning] Move driver-command logic for by-name scanning into DependencyScanningTool This is the second patch in a series that removes the dependency of clangDependencyScanning on clangDriver, splitting the work from #169964 into smaller changes (see comment linked below). This patch updates the by-name scanning interface in DependencyScanningWorker to accept only -cc1 command lines and moves the logic for handling driver-style command lines into DependencyScanningTool in clangTooling. Support for -cc1 command lines in by-name scanning is introduced in this patch. The next patch will update the remaining parts of DependencyScanningWorker to operate only on -cc1 command lines, allowing its dependency on clangDriver to be removed. https://github.com/llvm/llvm-project/pull/169964#pullrequestreview-3545879529 --- .../DependencyScannerImpl.h | 32 ++--- .../DependencyScanningWorker.h | 46 +++---- .../clang/Tooling/DependencyScanningTool.h | 12 +- .../DependencyScannerImpl.cpp | 64 ++++------ .../DependencyScanningWorker.cpp | 47 ++++---- clang/lib/Tooling/DependencyScanningTool.cpp | 113 ++++++++++++++---- .../ClangScanDeps/modules-full-by-mod-name.c | 11 ++ .../modules-full-by-mult-mod-names.c | 11 ++ clang/tools/clang-scan-deps/ClangScanDeps.cpp | 6 +- 9 files changed, 205 insertions(+), 137 deletions(-) diff --git a/clang/include/clang/DependencyScanning/DependencyScannerImpl.h b/clang/include/clang/DependencyScanning/DependencyScannerImpl.h index 352a0ad44fb7f..9e23c0f87f273 100644 --- a/clang/include/clang/DependencyScanning/DependencyScannerImpl.h +++ b/clang/include/clang/DependencyScanning/DependencyScannerImpl.h @@ -17,6 +17,7 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Serialization/ObjectFilePCHContainerReader.h" +#include "llvm/Support/VirtualFileSystem.h" namespace clang { class DiagnosticConsumer; @@ -63,15 +64,15 @@ class DependencyScanningAction { std::unique_ptr<DiagnosticOptions> createDiagOptions(ArrayRef<std::string> CommandLine); -struct DignosticsEngineWithDiagOpts { +struct DiagnosticsEngineWithDiagOpts { // We need to bound the lifetime of the DiagOpts used to create the // DiganosticsEngine with the DiagnosticsEngine itself. std::unique_ptr<DiagnosticOptions> DiagOpts; IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine; - DignosticsEngineWithDiagOpts(ArrayRef<std::string> CommandLine, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, - DiagnosticConsumer &DC); + DiagnosticsEngineWithDiagOpts(ArrayRef<std::string> CommandLine, + IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, + DiagnosticConsumer &DC); }; struct TextDiagnosticsPrinterWithOutput { @@ -143,22 +144,11 @@ class CompilerInstanceWithContext { llvm::StringRef CWD; std::vector<std::string> CommandLine; - // Context - file systems - llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS; - // 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; + std::unique_ptr<DiagnosticsEngineWithDiagOpts> 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; // Context - output options @@ -180,15 +170,13 @@ class CompilerInstanceWithContext { : Worker(Worker), CWD(CWD), CommandLine(CMD) {}; // The three methods below returns false when they fail, with the detail - // accumulated in DiagConsumer. - bool initialize(DiagnosticConsumer *DC); + // accumulated in \c DiagEngineWithDiagOpts's diagnostic consumer. + bool initialize( + std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts, + IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS); 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 clang diff --git a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h index ebd7d42786753..489fba4ed3f6b 100644 --- a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h @@ -12,12 +12,14 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LLVM.h" +#include "clang/DependencyScanning/DependencyScannerImpl.h" #include "clang/DependencyScanning/DependencyScanningService.h" #include "clang/DependencyScanning/ModuleDepCollector.h" #include "clang/Frontend/PCHContainerOperations.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBufferRef.h" +#include "llvm/Support/VirtualFileSystem.h" #include <optional> #include <string> @@ -119,13 +121,28 @@ class DependencyScanningWorker { /// 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. + /// The initialization function asks the client for a DiagnosticsConsumer + /// that it direct the diagnostics to. /// @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 initializeCompilerInstanceWithContextOrError( - StringRef CWD, ArrayRef<std::string> CommandLine); + /// @return False if the initializaiton fails. + bool initializeCompilerInstanceWithContext(StringRef CWD, + ArrayRef<std::string> CommandLine, + DiagnosticConsumer &DC); + + /// @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. + /// @param DiagEngineWithCmdAndOpts Preconfigured diagnostics engine and + /// options associated with the cc1 command line. + /// @param FS The overlay file system to use for this compiler instance. + /// @return False if the initializaiton fails. + bool initializeCompilerInstanceWithContext( + StringRef CWD, ArrayRef<std::string> CommandLine, + std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithCmdAndOpts, + IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS); /// @brief Performaces dependency scanning for the module whose name is /// specified. @@ -133,28 +150,15 @@ class DependencyScanningWorker { /// 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 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 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, - ArrayRef<std::string> CommandLine, - DiagnosticConsumer *DC = nullptr); + /// @return False if the scanner incurs errors. bool computeDependenciesByNameWithContext(StringRef ModuleName, DependencyConsumer &Consumer, DependencyActionController &Controller); - bool finalizeCompilerInstance(); + + /// @brief Finalizes the diagnostics engine and deletes the compiler instance. + /// @return False if errors occur during finalization. + bool finalizeCompilerInstanceWithContext(); llvm::vfs::FileSystem &getVFS() const { return *DepFS; } diff --git a/clang/include/clang/Tooling/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanningTool.h index 0af07ea8ca97a..44d7a338a87f7 100644 --- a/clang/include/clang/Tooling/DependencyScanningTool.h +++ b/clang/include/clang/Tooling/DependencyScanningTool.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_TOOLING_DEPENDENCYSCANNINGTOOL_H #define LLVM_CLANG_TOOLING_DEPENDENCYSCANNINGTOOL_H +#include "clang/DependencyScanning/DependencyScannerImpl.h" #include "clang/DependencyScanning/DependencyScanningService.h" #include "clang/DependencyScanning/DependencyScanningUtils.h" #include "clang/DependencyScanning/DependencyScanningWorker.h" @@ -119,9 +120,8 @@ 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 - initializeCompilerInstanceWithContext(StringRef CWD, - ArrayRef<std::string> CommandLine); + llvm::Error initializeCompilerInstanceWithContextOrError( + StringRef CWD, ArrayRef<std::string> CommandLine); /// @brief Computes the dependeny for the module named ModuleName. /// @param ModuleName The name of the module for which this method computes @@ -137,8 +137,8 @@ class DependencyScanningTool { /// arguments for dependencies. /// @return An instance of \c TranslationUnitDeps if the scan is successful. /// Otherwise it returns an error. - llvm::Expected<dependencies::TranslationUnitDeps> - computeDependenciesByNameWithContext( + llvm::Expected<clang::dependencies::TranslationUnitDeps> + computeDependenciesByNameWithContextOrError( StringRef ModuleName, const llvm::DenseSet<dependencies::ModuleID> &AlreadySeen, dependencies::LookupModuleOutputCallback LookupModuleOutput); @@ -147,7 +147,7 @@ class DependencyScanningTool { /// 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::Error finalizeCompilerInstanceWithContextOrError(); llvm::vfs::FileSystem &getWorkerVFS() const { return Worker.getVFS(); } diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp index acd05cc50daa8..d379680323d22 100644 --- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp +++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp @@ -13,6 +13,7 @@ #include "clang/Driver/Driver.h" #include "clang/Frontend/FrontendActions.h" #include "llvm/ADT/ScopeExit.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/TargetParser/Host.h" using namespace clang; @@ -367,7 +368,7 @@ dependencies::createDiagOptions(ArrayRef<std::string> CommandLine) { return DiagOpts; } -DignosticsEngineWithDiagOpts::DignosticsEngineWithDiagOpts( +DiagnosticsEngineWithDiagOpts::DiagnosticsEngineWithDiagOpts( ArrayRef<std::string> CommandLine, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS, DiagnosticConsumer &DC) { std::vector<const char *> CCommandLine(CommandLine.size(), nullptr); @@ -713,38 +714,31 @@ bool DependencyScanningAction::runInvocation( return Result; } -bool CompilerInstanceWithContext::initialize(DiagnosticConsumer *DC) { - if (DC) { - DiagConsumer = DC; - } else { - DiagPrinterWithOS = - std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine); - DiagConsumer = &DiagPrinterWithOS->DiagPrinter; +bool CompilerInstanceWithContext::initialize( + std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts, + IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS) { + assert(DiagEngineWithDiagOpts && "Valid diagnostics engine required!"); + DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts); + DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient(); + + IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = Worker.DepFS; + if (OverlayFS) { +#ifndef NDEBUG + bool SawDepFS = false; + OverlayFS->visit([&](llvm::vfs::FileSystem &VFS) { + SawDepFS |= &VFS == Worker.DepFS.get(); + }); + assert(SawDepFS && "OverlayFS not based on DepFS"); +#endif + FS = std::move(OverlayFS); } - std::tie(OverlayFS, CommandLine) = initVFSForByNameScanning( - Worker.DepFS, CommandLine, CWD, "ScanningByName"); - - DiagEngineWithCmdAndOpts = std::make_unique<DignosticsEngineWithDiagOpts>( - CommandLine, OverlayFS, *DiagConsumer); - - std::tie(Driver, Compilation) = buildCompilation( - CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS, Alloc); - - if (!Compilation) - return false; + // Reset what might have been modified in the previous worker invocation. + FS->setCurrentWorkingDirectory(CWD); - 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(); - assert(!CommandArgs.empty() && "Cannot have a command with 0 args"); - assert(StringRef(CommandArgs[0]) == "-cc1" && "Requires a cc1 job."); - OriginalInvocation = std::make_unique<CompilerInvocation>(); - - if (!CompilerInvocation::CreateFromArgs(*OriginalInvocation, CommandArgs, - *DiagEngineWithCmdAndOpts->DiagEngine, - Command.getExecutable())) { + OriginalInvocation = createCompilerInvocation( + CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine); + if (!OriginalInvocation) { DiagEngineWithCmdAndOpts->DiagEngine->Report( diag::err_fe_expected_compiler_job) << llvm::join(CommandLine, " "); @@ -763,7 +757,7 @@ bool CompilerInstanceWithContext::initialize(DiagnosticConsumer *DC) { auto &CI = *CIPtr; if (!initializeScanCompilerInstance( - CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(), + CI, FS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(), Worker.Service, Worker.DepFS)) return false; @@ -876,11 +870,3 @@ bool CompilerInstanceWithContext::finalize() { DiagConsumer->finish(); return true; } - -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/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/DependencyScanning/DependencyScanningWorker.cpp index 7b03abd8e3138..ef16b14e7cc6e 100644 --- a/clang/lib/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/DependencyScanning/DependencyScanningWorker.cpp @@ -7,10 +7,13 @@ //===----------------------------------------------------------------------===// #include "clang/DependencyScanning/DependencyScanningWorker.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/DependencyScanning/DependencyScannerImpl.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" +#include "clang/Serialization/ObjectFilePCHContainerReader.h" +#include "llvm/Support/VirtualFileSystem.h" using namespace clang; using namespace dependencies; @@ -100,7 +103,7 @@ bool DependencyScanningWorker::scanDependencies( FS = std::move(OverlayFS); } - DignosticsEngineWithDiagOpts DiagEngineWithCmdAndOpts(CommandLine, FS, DC); + DiagnosticsEngineWithDiagOpts DiagEngineWithCmdAndOpts(CommandLine, FS, DC); DependencyScanningAction Action(Service, WorkingDirectory, Consumer, Controller, DepFS); @@ -165,33 +168,29 @@ bool DependencyScanningWorker::computeDependencies( DC); } -llvm::Error -DependencyScanningWorker::initializeCompilerInstanceWithContextOrError( - StringRef CWD, ArrayRef<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, ArrayRef<std::string> CommandLine, DiagnosticConsumer &DC) { + auto OverlayFSAndArgs = + initVFSForByNameScanning(DepFS, CommandLine, CWD, "ScanningByName"); + auto &OverlayFS = OverlayFSAndArgs.first; + const auto &ModifiedCommandLine = OverlayFSAndArgs.second; + + auto DiagEngineWithCmdAndOpts = + std::make_unique<DiagnosticsEngineWithDiagOpts>(ModifiedCommandLine, + OverlayFS, DC); + + return initializeCompilerInstanceWithContext( + CWD, ModifiedCommandLine, std::move(DiagEngineWithCmdAndOpts), OverlayFS); } bool DependencyScanningWorker::initializeCompilerInstanceWithContext( - StringRef CWD, ArrayRef<std::string> CommandLine, DiagnosticConsumer *DC) { + StringRef CWD, ArrayRef<std::string> CommandLine, + std::unique_ptr<DiagnosticsEngineWithDiagOpts> DiagEngineWithDiagOpts, + IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFS) { CIWithContext = std::make_unique<CompilerInstanceWithContext>(*this, CWD, CommandLine); - return CIWithContext->initialize(DC); + return CIWithContext->initialize(std::move(DiagEngineWithDiagOpts), + OverlayFS); } bool DependencyScanningWorker::computeDependenciesByNameWithContext( @@ -201,6 +200,6 @@ bool DependencyScanningWorker::computeDependenciesByNameWithContext( return CIWithContext->computeDependencies(ModuleName, Consumer, Controller); } -bool DependencyScanningWorker::finalizeCompilerInstance() { +bool DependencyScanningWorker::finalizeCompilerInstanceWithContext() { return CIWithContext->finalize(); } diff --git a/clang/lib/Tooling/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanningTool.cpp index 9c0b095705d49..e138aa20da964 100644 --- a/clang/lib/Tooling/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanningTool.cpp @@ -7,6 +7,9 @@ //===----------------------------------------------------------------------===// #include "clang/Tooling/DependencyScanningTool.h" +#include "clang/Basic/DiagnosticFrontend.h" +#include "clang/DependencyScanning/DependencyScannerImpl.h" +#include "clang/Driver/Tool.h" #include "clang/Frontend/Utils.h" #include <optional> @@ -161,43 +164,109 @@ DependencyScanningTool::getModuleDependencies( StringRef ModuleName, ArrayRef<std::string> CommandLine, StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen, LookupModuleOutputCallback LookupModuleOutput) { - FullDependencyConsumer Consumer(AlreadySeen); - CallbackActionController Controller(LookupModuleOutput); if (auto Error = - Worker.initializeCompilerInstanceWithContextOrError(CWD, CommandLine)) - return std::move(Error); + initializeCompilerInstanceWithContextOrError(CWD, CommandLine)) + return Error; - auto Result = Worker.computeDependenciesByNameWithContextOrError( - ModuleName, Consumer, Controller); + auto Result = computeDependenciesByNameWithContextOrError( + ModuleName, AlreadySeen, LookupModuleOutput); - if (auto Error = Worker.finalizeCompilerInstanceWithContextOrError()) - return std::move(Error); + if (auto Error = finalizeCompilerInstanceWithContextOrError()) + return Error; - if (Result) - return std::move(Result); + return Result; +} - return Consumer.takeTranslationUnitDeps(); +/// Constructs the full -cc1 command line, including executable, for the given +/// driver \c Cmd. +static std::vector<std::string> +buildCC1CommandLine(const driver::Command &Cmd) { + const auto &Args = Cmd.getArguments(); + std::vector<std::string> Out; + Out.reserve(Args.size() + 1); + Out.emplace_back(Cmd.getExecutable()); + llvm::append_range(Out, Args); + return Out; } -llvm::Error DependencyScanningTool::initializeCompilerInstanceWithContext( +static std::optional<std::vector<std::string>> getFirstCC1CommandLine( + ArrayRef<std::string> CommandLine, DiagnosticsEngine &Diags, + llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> ScanFS) { + // Compilation holds a non-owning a reference to the Driver, hence we need to + // keep the Driver alive when we use Compilation. Arguments to commands may be + // owned by Alloc when expanded from response files. + llvm::BumpPtrAllocator Alloc; + const auto [Driver, Compilation] = + buildCompilation(CommandLine, Diags, ScanFS, Alloc); + if (!Compilation) + return std::nullopt; + + const auto IsClangCmd = [](const driver::Command &Cmd) { + return StringRef(Cmd.getCreator().getName()) == "clang"; + }; + const auto CC1CommandLineRange = llvm::map_range( + llvm::make_filter_range(Compilation->getJobs(), IsClangCmd), + buildCC1CommandLine); + + if (CC1CommandLineRange.empty()) + return std::nullopt; + return *CC1CommandLineRange.begin(); +} + +static llvm::Error makeErrorFromDiagnosticsOS( + TextDiagnosticsPrinterWithOutput &DiagPrinterWithOS) { + return llvm::make_error<llvm::StringError>( + DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); +} + +llvm::Error +DependencyScanningTool::initializeCompilerInstanceWithContextOrError( StringRef CWD, ArrayRef<std::string> CommandLine) { - return Worker.initializeCompilerInstanceWithContextOrError(CWD, CommandLine); + DiagPrinterWithOS = + std::make_unique<TextDiagnosticsPrinterWithOutput>(CommandLine); + + if (CommandLine.size() >= 2 && CommandLine[1] == "-cc1") { + if (Worker.initializeCompilerInstanceWithContext( + CWD, CommandLine, DiagPrinterWithOS->DiagPrinter)) + return llvm::Error::success(); + return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); + } + + auto OverlayFSAndArgs = initVFSForByNameScanning( + &Worker.getVFS(), CommandLine, CWD, "ScanningByName"); + auto &OverlayFS = OverlayFSAndArgs.first; + const auto &ModifiedCommandLine = OverlayFSAndArgs.second; + + auto DiagEngineWithCmdAndOpts = + std::make_unique<DiagnosticsEngineWithDiagOpts>( + ModifiedCommandLine, OverlayFS, DiagPrinterWithOS->DiagPrinter); + + const auto MaybeFirstCC1 = getFirstCC1CommandLine( + ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS); + if (!MaybeFirstCC1) + return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); + + if (Worker.initializeCompilerInstanceWithContext( + CWD, *MaybeFirstCC1, std::move(DiagEngineWithCmdAndOpts), OverlayFS)) + return llvm::Error::success(); + return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); } llvm::Expected<TranslationUnitDeps> -DependencyScanningTool::computeDependenciesByNameWithContext( +DependencyScanningTool::computeDependenciesByNameWithContextOrError( StringRef ModuleName, const llvm::DenseSet<ModuleID> &AlreadySeen, LookupModuleOutputCallback LookupModuleOutput) { FullDependencyConsumer Consumer(AlreadySeen); CallbackActionController Controller(LookupModuleOutput); - llvm::Error Result = Worker.computeDependenciesByNameWithContextOrError( - ModuleName, Consumer, Controller); - if (Result) - return std::move(Result); - - return Consumer.takeTranslationUnitDeps(); + if (Worker.computeDependenciesByNameWithContext(ModuleName, Consumer, + Controller)) + return Consumer.takeTranslationUnitDeps(); + return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); } -llvm::Error DependencyScanningTool::finalizeCompilerInstanceWithContext() { - return Worker.finalizeCompilerInstanceWithContextOrError(); +llvm::Error +DependencyScanningTool::finalizeCompilerInstanceWithContextOrError() { + if (Worker.finalizeCompilerInstanceWithContext()) + return llvm::Error::success(); + return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); } diff --git a/clang/test/ClangScanDeps/modules-full-by-mod-name.c b/clang/test/ClangScanDeps/modules-full-by-mod-name.c index edb99636aaf25..2d2c9acd30011 100644 --- a/clang/test/ClangScanDeps/modules-full-by-mod-name.c +++ b/clang/test/ClangScanDeps/modules-full-by-mod-name.c @@ -28,6 +28,17 @@ module transitive { header "transitive.h" } // 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 +//--- cdb.cc1.json.template +[{ + "file": "", + "directory": "DIR", + "command": "clang -cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -I DIR -x c" +}] + +// RUN: sed "s|DIR|%/t|g" %t/cdb.cc1.json.template > %t/cdb.cc1.json +// RUN: clang-scan-deps -compilation-database %t/cdb.cc1.json -format experimental-full -module-names=root > %t/result.cc1.json +// RUN: cat %t/result.cc1.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s + // CHECK: { // CHECK-NEXT: "modules": [ // CHECK-NEXT: { diff --git a/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c b/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c index 030f7f3427810..fdfd7b1e45d5d 100644 --- a/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c +++ b/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c @@ -33,6 +33,17 @@ module root1 { header "root1.h"} // 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 +//--- cdb.cc1.json.template +[{ + "file": "", + "directory": "DIR", + "command": "clang -cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -I DIR -x c" +}] + +// RUN: sed "s|DIR|%/t|g" %t/cdb.cc1.json.template > %t/cdb.cc1.json +// RUN: clang-scan-deps -compilation-database %t/cdb.cc1.json -format experimental-full -module-names=root,root1,direct > %t/result.cc1.json +// RUN: cat %t/result.cc1.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s + // CHECK: { // CHECK-NEXT: "modules": [ // CHECK-NEXT: { diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index 07157ae2dc06a..9acd0aca737ba 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -1105,7 +1105,7 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { HadErrors = true; } else { if (llvm::Error Err = - WorkerTool.initializeCompilerInstanceWithContext( + WorkerTool.initializeCompilerInstanceWithContextOrError( CWD, Input->CommandLine)) { handleErrorWithInfoString( "Compiler instance with context setup error", std::move(Err), @@ -1116,7 +1116,7 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { for (auto N : Names) { auto MaybeModuleDepsGraph = - WorkerTool.computeDependenciesByNameWithContext( + WorkerTool.computeDependenciesByNameWithContextOrError( N, AlreadySeenModules, LookupOutput); if (handleModuleResult(N, MaybeModuleDepsGraph, *FD, LocalIndex, DependencyOS, Errs)) { @@ -1126,7 +1126,7 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { } if (llvm::Error Err = - WorkerTool.finalizeCompilerInstanceWithContext()) { + WorkerTool.finalizeCompilerInstanceWithContextOrError()) { handleErrorWithInfoString( "Compiler instance with context finialization error", std::move(Err), DependencyOS, Errs); >From c3a23a41b18f7224850945e9fb241ceb27aa78a4 Mon Sep 17 00:00:00 2001 From: Naveen Seth Hanig <[email protected]> Date: Tue, 9 Dec 2025 20:20:30 +0100 Subject: [PATCH 2/3] Simplify getFirstCC1CommandLine --- clang/lib/Tooling/DependencyScanningTool.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/clang/lib/Tooling/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanningTool.cpp index e138aa20da964..5265bcc537752 100644 --- a/clang/lib/Tooling/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanningTool.cpp @@ -204,13 +204,11 @@ static std::optional<std::vector<std::string>> getFirstCC1CommandLine( const auto IsClangCmd = [](const driver::Command &Cmd) { return StringRef(Cmd.getCreator().getName()) == "clang"; }; - const auto CC1CommandLineRange = llvm::map_range( - llvm::make_filter_range(Compilation->getJobs(), IsClangCmd), - buildCC1CommandLine); - if (CC1CommandLineRange.empty()) - return std::nullopt; - return *CC1CommandLineRange.begin(); + const auto &Jobs = Compilation->getJobs(); + if (const auto It = llvm::find_if(Jobs, IsClangCmd); It != Jobs.end()) + return buildCC1CommandLine(*It); + return std::nullopt; } static llvm::Error makeErrorFromDiagnosticsOS( >From 99838242e9b803830854e15100b3143548bd86a7 Mon Sep 17 00:00:00 2001 From: Naveen Seth Hanig <[email protected]> Date: Tue, 9 Dec 2025 20:21:11 +0100 Subject: [PATCH 3/3] Remove unnecessary namespace qualifier --- clang/include/clang/Tooling/DependencyScanningTool.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Tooling/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanningTool.h index 44d7a338a87f7..e796ed648db35 100644 --- a/clang/include/clang/Tooling/DependencyScanningTool.h +++ b/clang/include/clang/Tooling/DependencyScanningTool.h @@ -137,7 +137,7 @@ class DependencyScanningTool { /// arguments for dependencies. /// @return An instance of \c TranslationUnitDeps if the scan is successful. /// Otherwise it returns an error. - llvm::Expected<clang::dependencies::TranslationUnitDeps> + llvm::Expected<dependencies::TranslationUnitDeps> computeDependenciesByNameWithContextOrError( StringRef ModuleName, const llvm::DenseSet<dependencies::ModuleID> &AlreadySeen, _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
