From 19482768ca28eb478cd45a7bd0ff63f6c0af55ea Mon Sep 17 00:00:00 2001 From: Qiongsi Wu Date: Wed, 15 Oct 2025 09:22:59 -0700 Subject: [PATCH 01/10] 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> &getDependencyCollectors() { + return DependencyCollectors; + } + void setExternalSemaSource(IntrusiveRefCntPtr 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 initializeScanInstanceDependencyCollector( DependencyActionController &Controller, PrebuiltModulesAttrsMap PrebuiltModulesASTMap, llvm::SmallVector &StableDirs); + +class CompilerInstanceWithContext { + // Context + DependencyScanningWorker &Worker; + llvm::StringRef CWD; + std::vector CommandLine; + static const uint64_t MAX_NUM_NAMES = (1 << 12); + static const std::string FakeFileBuffer; + + // Context - file systems + llvm::IntrusiveRefCntPtr OverlayFS; + llvm::IntrusiveRefCntPtr InMemoryFS; + llvm::IntrusiveRefCntPtr InMemoryOverlay; + + // Context - Diagnostics engine, file manager and source mamanger. + std::string DiagnosticOutput; + llvm::raw_string_ostream DiagnosticsOS; + std::unique_ptr DiagPrinter; + IntrusiveRefCntPtr Diags; + std::unique_ptr FileMgr; + std::unique_ptr SrcMgr; + + // Context - compiler invocation + std::unique_ptr Driver; + std::unique_ptr Compilation; + std::unique_ptr Invocation; + llvm::IntrusiveRefCntPtr VFSFromCompilerInvocation; + + // Context - output options + std::unique_ptr OutputOpts; + + // Context - stable directory handling + llvm::SmallVector StableDirs; + PrebuiltModulesAttrsMap PrebuiltModuleVFSMap; + + // Compiler Instance + std::unique_ptr CIPtr; + + // // Source location offset. + int32_t SrcLocOffset = 0; + +public: + CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD, + const std::vector &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 &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 &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 computeDependenciesByNameWithContext( + StringRef ModuleName, const llvm::DenseSet &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 &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 DepFS; + friend class CompilerInstanceWithContext; + std::unique_ptr CIWithContext; + /// Private helper functions. bool scanDependencies(StringRef WorkingDirectory, const std::vector &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 ProvidedStdCXXModule; std::vector 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(Worker.BaseFS); + InMemoryFS = llvm::makeIntrusiveRefCnt(); + 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(FileSystemOptions{}, OverlayFS); + DiagnosticOutput.clear(); + auto DiagOpts = createDiagOptions(CommandLine); + DiagPrinter = std::make_unique(DiagnosticsOS, + *(DiagOpts.release())); + std::vector 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(*Diags, *FileMgr); + Diags->setSourceManager(SrcMgr.get()); + + // Create the compiler invocation. + Driver = std::make_unique( + 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("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( + "Incorrect compilation command, missing cc1", + llvm::inconvertibleErrorCode()); + Invocation = std::make_unique(); + + if (!CompilerInvocation::CreateFromArgs(*Invocation, Command.getArguments(), + *Diags, Command.getExecutable())) { + Diags->Report(diag::err_fe_expected_compiler_job) + << llvm::join(CommandLine, " "); + return llvm::make_error( + "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 ModCache = + makeInProcessModuleCache(Worker.Service.getModuleCacheEntries()); + CIPtr = std::make_unique( + std::make_shared(*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(*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( + "Prebuilt module scanning failed", llvm::inconvertibleErrorCode()); + + OutputOpts = std::make_unique(); + 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(*OutputOpts); + auto MDC = std::make_shared( + Worker.Service, std::move(Opts), CI, Consumer, Controller, Inv, + PrebuiltModuleVFSMap, StableDirs); + + CI.clearDependencyCollectors(); + CI.addDependencyCollector(MDC); + + std::unique_ptr Action = + std::make_unique(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 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 &CommandLine) { + return Worker.initializeCompierInstanceWithContext(CWD, CommandLine); +} + +llvm::Expected +DependencyScanningTool::computeDependenciesByNameWithContext( + StringRef ModuleName, const llvm::DenseSet &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 &CommandLine) { + CIWithContext = + std::make_unique(*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(*this)); + auto CollectorPP = std::make_unique(*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 TU; std::optional TUBuffer; From 094754c289ce6fd190d45f35071f9c248b9977b7 Mon Sep 17 00:00:00 2001 From: Qiongsi Wu Date: Thu, 16 Oct 2025 16:30:10 -0700 Subject: [PATCH 02/10] 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 BaseFS, StringRef WorkingDirectory, llvm::MemoryBufferRef TUBuffer); -std::pair, std::vector> +std::pair, + std::vector> initVFSForByNameScanning(IntrusiveRefCntPtr BaseFS, ArrayRef CommandLine, StringRef WorkingDirectory, StringRef ModuleName); @@ -163,16 +164,10 @@ class CompilerInstanceWithContext { // Context - file systems llvm::IntrusiveRefCntPtr OverlayFS; - llvm::IntrusiveRefCntPtr InMemoryFS; - llvm::IntrusiveRefCntPtr InMemoryOverlay; - // Context - Diagnostics engine, file manager and source mamanger. - std::string DiagnosticOutput; - llvm::raw_string_ostream DiagnosticsOS; - std::unique_ptr DiagPrinter; - IntrusiveRefCntPtr Diags; - std::unique_ptr FileMgr; - std::unique_ptr SrcMgr; + // Context - Diagnostics engine. + std::unique_ptr DiagPrinterWithOS; + std::unique_ptr DiagEngineWithCmdAndOpts; // Context - compiler invocation std::unique_ptr Driver; @@ -196,8 +191,7 @@ class CompilerInstanceWithContext { public: CompilerInstanceWithContext(DependencyScanningWorker &Worker, StringRef CWD, const std::vector &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 BaseFS, return std::make_pair(ModifiedFS, ModifiedCommandLine); } -std::pair, std::vector> +std::pair, + std::vector> initVFSForByNameScanning(IntrusiveRefCntPtr BaseFS, ArrayRef CommandLine, StringRef WorkingDirectory, StringRef ModuleName) { @@ -489,6 +490,9 @@ bool initializeScanCompilerInstance( IntrusiveRefCntPtr FS, DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service, IntrusiveRefCntPtr 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(Worker.BaseFS); - InMemoryFS = llvm::makeIntrusiveRefCnt(); - 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(CommandLine); + DiagEngineWithCmdAndOpts = std::make_unique( + CommandLine, OverlayFS, DiagPrinterWithOS->DiagPrinter); - // Create the file manager, the diagnostics engine, and the source manager. - FileMgr = std::make_unique(FileSystemOptions{}, OverlayFS); - DiagnosticOutput.clear(); - auto DiagOpts = createDiagOptions(CommandLine); - DiagPrinter = std::make_unique(DiagnosticsOS, - *(DiagOpts.release())); - std::vector 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(*Diags, *FileMgr); - Diags->setSourceManager(SrcMgr.get()); - - // Create the compiler invocation. - Driver = std::make_unique( - 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("Failed to build compilation", llvm::inconvertibleErrorCode()); } @@ -776,8 +742,28 @@ llvm::Error CompilerInstanceWithContext::initialize() { Invocation = std::make_unique(); 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( + "Cannot create CompilerInvocation from Args", + llvm::inconvertibleErrorCode()); + } + + // TODO: CMDArgsStrVector is making string copies. We should optimize later + // and avoid the copies. + std::vector 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( "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(*FileMgr)); + if (!initializeScanCompilerInstance( + CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(), + Worker.Service, Worker.DepFS)) { + return llvm::make_error( + "Cannot initialize scanning compiler instance", + llvm::inconvertibleErrorCode()); } - CI.createSourceManager(); + llvm::SmallVector StableDirs = getInitialStableDirs(CI); + auto MaybePrebuiltModulesASTMap = + computePrebuiltModulesASTMap(CI, StableDirs); + if (!MaybePrebuiltModulesASTMap) + return llvm::make_error( + "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( - "Prebuilt module scanning failed", llvm::inconvertibleErrorCode()); - - OutputOpts = std::make_unique(); - 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(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 Date: Mon, 20 Oct 2025 11:01:40 -0700 Subject: [PATCH 03/10] 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 StableDirs; - PrebuiltModulesAttrsMap PrebuiltModuleVFSMap; + PrebuiltModulesAttrsMap PrebuiltModuleASTMap; // Compiler Instance std::unique_ptr 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( "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(*OutputOpts); - auto MDC = std::make_shared( - Worker.Service, std::move(Opts), CI, Consumer, Controller, Inv, - PrebuiltModuleVFSMap, StableDirs); - CI.clearDependencyCollectors(); - CI.addDependencyCollector(MDC); - - std::unique_ptr Action = - std::make_unique(ModuleName); - auto InputFile = CI.getFrontendOpts().Inputs.begin(); + auto MDC = initializeScanInstanceDependencyCollector( + CI, std::make_unique(*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 Action = + std::make_unique(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 Date: Mon, 20 Oct 2025 11:50:28 -0700 Subject: [PATCH 04/10] 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 DepFS, std::optional 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 Invocation, IntrusiveRefCntPtr FS, std::shared_ptr PCHContainerOps, @@ -69,7 +68,6 @@ class DependencyScanningAction { DependencyConsumer &Consumer; DependencyActionController &Controller; IntrusiveRefCntPtr DepFS; - std::optional ModuleName; std::optional ScanInstanceStorage; std::shared_ptr MDC; std::vector LastCC1Arguments; @@ -185,7 +183,7 @@ class CompilerInstanceWithContext { // Compiler Instance std::unique_ptr 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 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 getModuleDependencies( - StringRef ModuleName, const std::vector &CommandLine, - StringRef CWD, const llvm::DenseSet &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 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 &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 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 &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 FS, - std::optional ModuleName); + llvm::IntrusiveRefCntPtr 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(); - else if (ModuleName) - Action = std::make_unique(*ModuleName); else Action = std::make_unique(); 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 -DependencyScanningTool::getModuleDependencies( - StringRef ModuleName, const std::vector &CommandLine, - StringRef CWD, const llvm::DenseSet &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 &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 &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( - DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); -} - static bool forEachDriverJob( ArrayRef ArgStrs, DiagnosticsEngine &Diags, IntrusiveRefCntPtr FS, @@ -110,11 +95,11 @@ static bool createAndRunToolInvocation( bool DependencyScanningWorker::scanDependencies( StringRef WorkingDirectory, const std::vector &CommandLine, DependencyConsumer &Consumer, DependencyActionController &Controller, - DiagnosticConsumer &DC, llvm::IntrusiveRefCntPtr FS, - std::optional ModuleName) { + DiagnosticConsumer &DC, + llvm::IntrusiveRefCntPtr 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 &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 &CommandLine) { CIWithContext = From 03051765b192fa0b5759875d1c7cd3ae3d58a711 Mon Sep 17 00:00:00 2001 From: Qiongsi Wu Date: Wed, 22 Oct 2025 13:56:46 -0700 Subject: [PATCH 05/10] 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 &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 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 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 FS, DiagnosticConsumer *DiagConsumer, DependencyScanningService &Service, IntrusiveRefCntPtr 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( "Incorrect compilation command, missing cc1", llvm::inconvertibleErrorCode()); - Invocation = std::make_unique(); + OriginalInvocation = std::make_unique(); - 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 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( - "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 ModCache = makeInProcessModuleCache(Worker.Service.getModuleCacheEntries()); CIPtr = std::make_unique( - std::make_shared(*Invocation), Worker.PCHContainerOps, - ModCache.get()); + std::make_shared(*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(*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 Action = - std::make_unique(ModuleName); + std::make_unique(); 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 Driver; std::unique_ptr Compilation; - std::unique_ptr Invocation; - llvm::IntrusiveRefCntPtr VFSFromCompilerInvocation; + std::unique_ptr OriginalInvocation; // Context - output options std::unique_ptr 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 &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 &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 Date: Thu, 23 Oct 2025 10:38:40 -0700 Subject: [PATCH 06/10] 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(*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 Date: Thu, 23 Oct 2025 11:12:28 -0700 Subject: [PATCH 07/10] 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("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 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 Driver; std::unique_ptr Compilation; std::unique_ptr OriginalInvocation; From 6161886b8b574236ace3625175e80b5925f713cf Mon Sep 17 00:00:00 2001 From: Qiongsi Wu Date: Thu, 23 Oct 2025 14:00:10 -0700 Subject: [PATCH 08/10] 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(*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 ModuleName; +static std::optional ModuleNames; static std::vector 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 NumStatusCalls = 0; std::atomic 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 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 Date: Thu, 23 Oct 2025 15:28:00 -0700 Subject: [PATCH 09/10] 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 Date: Thu, 23 Oct 2025 15:35:53 -0700 Subject: [PATCH 10/10] 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 &CommandLine); /// @brief Performaces dependency scanning for the module whose name is @@ -159,7 +159,7 @@ class DependencyScanningWorker { /// (passed in the constructor). llvm::IntrusiveRefCntPtr DepFS; - friend class CompilerInstanceWithContext; + friend CompilerInstanceWithContext; std::unique_ptr 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 -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 &StableDirs); std::unique_ptr -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 &CommandLine) { - return Worker.initializeCompierInstanceWithContext(CWD, CommandLine); + return Worker.initializeCompilerInstanceWithContext(CWD, CommandLine); } llvm::Expected 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 &CommandLine) { CIWithContext = std::make_unique(*this, CWD, CommandLine);