diff --git a/clang/include/clang/DependencyScanning/DependencyScannerImpl.h b/clang/include/clang/DependencyScanning/DependencyScannerImpl.h index 352a0ad44fb7f..11a1680f57120 100644 --- a/clang/include/clang/DependencyScanning/DependencyScannerImpl.h +++ b/clang/include/clang/DependencyScanning/DependencyScannerImpl.h @@ -16,7 +16,6 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/TextDiagnosticPrinter.h" -#include "clang/Serialization/ObjectFilePCHContainerReader.h" namespace clang { class DiagnosticConsumer; @@ -88,27 +87,10 @@ struct TextDiagnosticsPrinterWithOutput { DiagPrinter(DiagnosticsOS, *DiagOpts) {} }; -std::pair, std::unique_ptr> -buildCompilation(ArrayRef ArgStrs, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr FS, - llvm::BumpPtrAllocator &Alloc); - std::unique_ptr createCompilerInvocation(ArrayRef CommandLine, DiagnosticsEngine &Diags); -std::pair, std::vector> -initVFSForTUBufferScanning(IntrusiveRefCntPtr BaseFS, - ArrayRef CommandLine, - StringRef WorkingDirectory, - llvm::MemoryBufferRef TUBuffer); - -std::pair, - std::vector> -initVFSForByNameScanning(IntrusiveRefCntPtr BaseFS, - ArrayRef CommandLine, - StringRef WorkingDirectory, StringRef ModuleName); - bool initializeScanCompilerInstance( CompilerInstance &ScanInstance, IntrusiveRefCntPtr FS, @@ -143,22 +125,11 @@ class CompilerInstanceWithContext { llvm::StringRef CWD; std::vector CommandLine; - // Context - file systems - llvm::IntrusiveRefCntPtr OverlayFS; - // Context - Diagnostics engine. - std::unique_ptr DiagPrinterWithOS; - // DiagConsumer may points to DiagPrinterWithOS->DiagPrinter, or a custom - // DiagnosticConsumer passed in from initialize. DiagnosticConsumer *DiagConsumer = nullptr; 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; // Context - output options @@ -180,15 +151,13 @@ class CompilerInstanceWithContext { : Worker(Worker), CWD(CWD), CommandLine(CMD) {}; // The three methods below returns false when they fail, with the detail - // accumulated in DiagConsumer. - bool initialize(DiagnosticConsumer *DC); + // accumulated in \c DiagEngineWithDiagOpts's diagnostic consumer. + bool initialize( + std::unique_ptr DiagEngineWithDiagOpts, + IntrusiveRefCntPtr FS); bool computeDependencies(StringRef ModuleName, DependencyConsumer &Consumer, DependencyActionController &Controller); bool finalize(); - - // The method below turns the return status from the above methods - // into an llvm::Error using a default DiagnosticConsumer. - llvm::Error handleReturnStatus(bool Success); }; } // namespace dependencies } // namespace clang diff --git a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h index 9585691607ca9..862e2f51890db 100644 --- a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h @@ -9,9 +9,11 @@ #ifndef LLVM_CLANG_DEPENDENCYSCANNING_DEPENDENCYSCANNINGWORKER_H #define LLVM_CLANG_DEPENDENCYSCANNING_DEPENDENCYSCANNINGWORKER_H +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LLVM.h" +#include "clang/DependencyScanning/DependencyScannerImpl.h" #include "clang/DependencyScanning/DependencyScanningService.h" #include "clang/DependencyScanning/ModuleDepCollector.h" #include "clang/Frontend/PCHContainerOperations.h" @@ -91,41 +93,56 @@ class DependencyScanningWorker { ~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 - /// scanning. Otherwise, the input should be included as part of the - /// command-line. + /// Run the dependency scanning tool for a given clang -cc1 command-line, + /// and report the discovered dependencies to the provided consumer. /// - /// \returns false if clang errors occurred (with diagnostics reported to + /// \return 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, - std::optional TUBuffer = std::nullopt); + llvm::IntrusiveRefCntPtr ScanFS = nullptr); - /// Run the dependency scanning tool for a given clang driver command-line - /// for a specific translation unit via file system or memory buffer. + /// Run the dependency scanning tool for all given clang -cc1 command-lines, + /// and report the discovered dependencies to the provided consumer. /// - /// \returns A \c StringError with the diagnostic output if clang errors - /// occurred, success otherwise. - llvm::Error computeDependencies( - StringRef WorkingDirectory, const std::vector &CommandLine, + /// \returns false if clang errors occurred (with diagnostics reported to + /// \c Diags), true otherwise. + bool computeDependencies( + StringRef WorkingDirectory, + ArrayRef> CommandLines, DependencyConsumer &Consumer, DependencyActionController &Controller, - std::optional TUBuffer = std::nullopt); + DiagnosticsEngine &Diags, + llvm::IntrusiveRefCntPtr ScanFS = nullptr); /// 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. + /// The initialization function asks the client for a DiagnosticsConsumer + /// that it direct the diagnostics to. /// @brief Initializing the context and the compiler instance. /// @param CWD The current working directory used during the scan. /// @param CommandLine The commandline used for the scan. - /// @return Error if the initializaiton fails. - llvm::Error initializeCompilerInstanceWithContextOrError( - StringRef CWD, const std::vector &CommandLine); + /// @return False if the initializaiton fails. + bool initializeCompilerInstanceWithContext(StringRef CWD, + ArrayRef CommandLine, + DiagnosticConsumer &DC); + + /// @brief Initializing the context and the compiler instance. + /// @param CWD The current working directory used during the scan. + /// @param CommandLine The commandline used for the scan. + /// @param DiagEngineWithCmdAndOpts Preconfigured diagnostics engine and + /// options associated with the cc1 command line. + /// @param FS The file system (typically an overlay) to use for this compiler + /// instance. + /// @return False if the initializaiton fails. + bool initializeCompilerInstanceWithContext( + StringRef CWD, ArrayRef CommandLine, + std::unique_ptr DiagEngineWithCmdAndOpts, + IntrusiveRefCntPtr FS); /// @brief Performaces dependency scanning for the module whose name is /// specified. @@ -133,28 +150,15 @@ class DependencyScanningWorker { /// scanned. /// @param Consumer The dependency consumer that stores the results. /// @param Controller The controller for the dependency scanning action. - /// @return Error if the scanner incurs errors. - llvm::Error computeDependenciesByNameWithContextOrError( - StringRef ModuleName, DependencyConsumer &Consumer, - DependencyActionController &Controller); - - /// @brief Finalizes the diagnostics engine and deletes the compiler instance. - /// @return Error if errors occur during finalization. - llvm::Error finalizeCompilerInstanceWithContextOrError(); - - /// The three methods below provides the same functionality as the - /// three methods above. Instead of returning `llvm::Error`s, these - /// three methods return a flag to indicate if the call is successful. - /// The initialization function asks the client for a DiagnosticsConsumer - /// that it direct the diagnostics to. - bool initializeCompilerInstanceWithContext( - StringRef CWD, const std::vector &CommandLine, - DiagnosticConsumer *DC = nullptr); + /// @return False if the scanner incurs errors. bool computeDependenciesByNameWithContext(StringRef ModuleName, DependencyConsumer &Consumer, DependencyActionController &Controller); - bool finalizeCompilerInstance(); + + /// @brief Finalizes the diagnostics engine and deletes the compiler instance. + /// @return False if errors occur during finalization. + bool finalizeCompilerInstanceWithContext(); llvm::vfs::FileSystem &getVFS() const { return *DepFS; } @@ -169,13 +173,21 @@ class DependencyScanningWorker { friend CompilerInstanceWithContext; std::unique_ptr CIWithContext; - /// Actually carries out the scan. If \c OverlayFS is provided, it must be - /// based on top of DepFS. - bool scanDependencies( - StringRef WorkingDirectory, const std::vector &CommandLine, - DependencyConsumer &Consumer, DependencyActionController &Controller, - DiagnosticConsumer &DC, - IntrusiveRefCntPtr OverlayFS = nullptr); + /// Private helper functions to actually carry out the scan. If \c OverlayFS + /// is provided, it must be based on top of DepFS. + bool scanDependencies(StringRef WorkingDirectory, + const std::vector &CommandLine, + DependencyConsumer &Consumer, + DependencyActionController &Controller, + DiagnosticConsumer &DC, + llvm::IntrusiveRefCntPtr FS); + + bool scanDependencies(StringRef WorkingDirectory, + ArrayRef> CommandLine, + DependencyConsumer &Consumer, + DependencyActionController &Controller, + DiagnosticsEngine &Diags, + llvm::IntrusiveRefCntPtr FS); }; } // end namespace dependencies diff --git a/clang/include/clang/Tooling/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanningTool.h index 9d9c734df6c0d..e91e0806a8eb6 100644 --- a/clang/include/clang/Tooling/DependencyScanningTool.h +++ b/clang/include/clang/Tooling/DependencyScanningTool.h @@ -9,6 +9,7 @@ #ifndef LLVM_CLANG_TOOLING_DEPENDENCYSCANNINGTOOL_H #define LLVM_CLANG_TOOLING_DEPENDENCYSCANNINGTOOL_H +#include "clang/DependencyScanning/DependencyScannerImpl.h" #include "clang/DependencyScanning/DependencyScanningService.h" #include "clang/DependencyScanning/DependencyScanningUtils.h" #include "clang/DependencyScanning/DependencyScanningWorker.h" @@ -119,8 +120,8 @@ class DependencyScanningTool { /// @param CWD The current working directory used during the scan. /// @param CommandLine The commandline used for the scan. /// @return Error if the initializaiton fails. - llvm::Error initializeCompilerInstanceWithContext( - StringRef CWD, const std::vector &CommandLine); + llvm::Error initializeCompilerInstanceWithContextOrError( + StringRef CWD, ArrayRef CommandLine); /// @brief Computes the dependeny for the module named ModuleName. /// @param ModuleName The name of the module for which this method computes @@ -137,7 +138,7 @@ class DependencyScanningTool { /// @return An instance of \c TranslationUnitDeps if the scan is successful. /// Otherwise it returns an error. llvm::Expected - computeDependenciesByNameWithContext( + computeDependenciesByNameWithContextOrError( StringRef ModuleName, const llvm::DenseSet &AlreadySeen, dependencies::LookupModuleOutputCallback LookupModuleOutput); @@ -146,7 +147,7 @@ class DependencyScanningTool { /// diagnostics and deletes the compiler instance. Call this method /// once all names for a same commandline are scanned. /// @return Error if an error occured during finalization. - llvm::Error finalizeCompilerInstanceWithContext(); + llvm::Error finalizeCompilerInstanceWithContextOrError(); llvm::vfs::FileSystem &getWorkerVFS() const { return Worker.getVFS(); } diff --git a/clang/lib/DependencyScanning/CMakeLists.txt b/clang/lib/DependencyScanning/CMakeLists.txt index 2976f7c236f2e..0b46765649a2a 100644 --- a/clang/lib/DependencyScanning/CMakeLists.txt +++ b/clang/lib/DependencyScanning/CMakeLists.txt @@ -18,9 +18,7 @@ add_clang_library(clangDependencyScanning ClangDriverOptions LINK_LIBS - clangAST clangBasic - clangDriver clangFrontend clangLex clangSerialization diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp index 3ca9ce140e887..257ed8473e268 100644 --- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp +++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp @@ -379,42 +379,6 @@ DignosticsEngineWithDiagOpts::DignosticsEngineWithDiagOpts( /*ShouldOwnClient=*/false); } -std::pair, std::unique_ptr> -dependencies::buildCompilation(ArrayRef ArgStrs, - DiagnosticsEngine &Diags, - IntrusiveRefCntPtr FS, - llvm::BumpPtrAllocator &Alloc) { - SmallVector Argv; - Argv.reserve(ArgStrs.size()); - for (const std::string &Arg : ArgStrs) - Argv.push_back(Arg.c_str()); - - std::unique_ptr Driver = std::make_unique( - Argv[0], llvm::sys::getDefaultTargetTriple(), Diags, - "clang LLVM compiler", FS); - Driver->setTitle("clang_based_tool"); - - bool CLMode = driver::IsClangCL( - driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1))); - - if (llvm::Error E = - driver::expandResponseFiles(Argv, CLMode, Alloc, FS.get())) { - Diags.Report(diag::err_drv_expand_response_file) - << llvm::toString(std::move(E)); - return std::make_pair(nullptr, nullptr); - } - - std::unique_ptr Compilation( - Driver->BuildCompilation(Argv)); - if (!Compilation) - return std::make_pair(nullptr, nullptr); - - if (Compilation->containsError()) - return std::make_pair(nullptr, nullptr); - - return std::make_pair(std::move(Driver), std::move(Compilation)); -} - std::unique_ptr dependencies::createCompilerInvocation(ArrayRef CommandLine, DiagnosticsEngine &Diags) { @@ -430,62 +394,6 @@ dependencies::createCompilerInvocation(ArrayRef CommandLine, return Invocation; } -std::pair, std::vector> -dependencies::initVFSForTUBufferScanning( - IntrusiveRefCntPtr BaseFS, - ArrayRef CommandLine, StringRef WorkingDirectory, - llvm::MemoryBufferRef TUBuffer) { - // Reset what might have been modified in the previous worker invocation. - BaseFS->setCurrentWorkingDirectory(WorkingDirectory); - - IntrusiveRefCntPtr ModifiedFS; - auto OverlayFS = - llvm::makeIntrusiveRefCnt(BaseFS); - auto InMemoryFS = llvm::makeIntrusiveRefCnt(); - InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory); - auto InputPath = TUBuffer.getBufferIdentifier(); - InMemoryFS->addFile( - InputPath, 0, llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer())); - IntrusiveRefCntPtr InMemoryOverlay = InMemoryFS; - - OverlayFS->pushOverlay(InMemoryOverlay); - ModifiedFS = OverlayFS; - std::vector ModifiedCommandLine(CommandLine); - ModifiedCommandLine.emplace_back(InputPath); - - return std::make_pair(ModifiedFS, ModifiedCommandLine); -} - -std::pair, - std::vector> -dependencies::initVFSForByNameScanning( - IntrusiveRefCntPtr BaseFS, - ArrayRef CommandLine, StringRef WorkingDirectory, - StringRef ModuleName) { - // Reset what might have been modified in the previous worker invocation. - BaseFS->setCurrentWorkingDirectory(WorkingDirectory); - - // If we're scanning based on a module name alone, we don't expect the client - // to provide us with an input file. However, the driver really wants to have - // one. Let's just make it up to make the driver happy. - auto OverlayFS = - llvm::makeIntrusiveRefCnt(BaseFS); - auto InMemoryFS = llvm::makeIntrusiveRefCnt(); - InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory); - SmallString<128> FakeInputPath; - // TODO: We should retry the creation if the path already exists. - llvm::sys::fs::createUniquePath(ModuleName + "-%%%%%%%%.input", FakeInputPath, - /*MakeAbsolute=*/false); - InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer("")); - IntrusiveRefCntPtr InMemoryOverlay = InMemoryFS; - OverlayFS->pushOverlay(InMemoryOverlay); - - std::vector ModifiedCommandLine(CommandLine); - ModifiedCommandLine.emplace_back(FakeInputPath); - - return std::make_pair(OverlayFS, ModifiedCommandLine); -} - bool dependencies::initializeScanCompilerInstance( CompilerInstance &ScanInstance, IntrusiveRefCntPtr FS, @@ -713,39 +621,20 @@ bool DependencyScanningAction::runInvocation( return Result; } -bool CompilerInstanceWithContext::initialize(DiagnosticConsumer *DC) { - if (DC) { - DiagConsumer = DC; - } else { - DiagPrinterWithOS = - std::make_unique(CommandLine); - DiagConsumer = &DiagPrinterWithOS->DiagPrinter; - } - - std::tie(OverlayFS, CommandLine) = initVFSForByNameScanning( - Worker.DepFS, CommandLine, CWD, "ScanningByName"); - - DiagEngineWithCmdAndOpts = std::make_unique( - CommandLine, OverlayFS, *DiagConsumer); +bool CompilerInstanceWithContext::initialize( + std::unique_ptr DiagEngineWithDiagOpts, + IntrusiveRefCntPtr FS) { + assert(DiagEngineWithDiagOpts && "Valid diagnostics engine required!"); + DiagEngineWithCmdAndOpts = std::move(DiagEngineWithDiagOpts); + DiagConsumer = DiagEngineWithCmdAndOpts->DiagEngine->getClient(); - std::tie(Driver, Compilation) = buildCompilation( - CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS, Alloc); - - if (!Compilation) - return false; + // Reset what might have been modified in the previous worker invocation. + Worker.DepFS->setCurrentWorkingDirectory(CWD); - assert(Compilation->getJobs().size() && - "Must have a job list of non-zero size"); - const driver::Command &Command = *(Compilation->getJobs().begin()); - const auto &CommandArgs = Command.getArguments(); - assert(!CommandArgs.empty() && "Cannot have a command with 0 args"); - assert(StringRef(CommandArgs[0]) == "-cc1" && "Requires a cc1 job."); - OriginalInvocation = std::make_unique(); - - if (!CompilerInvocation::CreateFromArgs(*OriginalInvocation, CommandArgs, - *DiagEngineWithCmdAndOpts->DiagEngine, - Command.getExecutable())) { - DiagEngineWithCmdAndOpts->DiagEngine->Report( + OriginalInvocation = createCompilerInvocation( + CommandLine, *DiagEngineWithCmdAndOpts->DiagEngine); + if (!OriginalInvocation) { + this->DiagEngineWithCmdAndOpts->DiagEngine->Report( diag::err_fe_expected_compiler_job) << llvm::join(CommandLine, " "); return false; @@ -763,7 +652,7 @@ bool CompilerInstanceWithContext::initialize(DiagnosticConsumer *DC) { auto &CI = *CIPtr; if (!initializeScanCompilerInstance( - CI, OverlayFS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(), + CI, FS, DiagEngineWithCmdAndOpts->DiagEngine->getClient(), Worker.Service, Worker.DepFS)) return false; @@ -815,7 +704,7 @@ bool CompilerInstanceWithContext::computeDependencies( // file. In this case, we call BeginSourceFile to initialize. std::unique_ptr Action = std::make_unique(); - auto InputFile = CI.getFrontendOpts().Inputs.begin(); + auto *InputFile = CI.getFrontendOpts().Inputs.begin(); bool ActionBeginSucceeded = Action->BeginSourceFile(CI, *InputFile); assert(ActionBeginSucceeded && "Action BeginSourceFile must succeed"); (void)ActionBeginSucceeded; @@ -876,11 +765,3 @@ bool CompilerInstanceWithContext::finalize() { DiagConsumer->finish(); return true; } - -llvm::Error CompilerInstanceWithContext::handleReturnStatus(bool Success) { - assert(DiagPrinterWithOS && "Must use the default DiagnosticConsumer."); - return Success ? llvm::Error::success() - : llvm::make_error( - DiagPrinterWithOS->DiagnosticsOS.str(), - llvm::inconvertibleErrorCode()); -} diff --git a/clang/lib/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/DependencyScanning/DependencyScanningWorker.cpp index 333edd4862336..0defacfd41759 100644 --- a/clang/lib/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/DependencyScanning/DependencyScanningWorker.cpp @@ -7,10 +7,12 @@ //===----------------------------------------------------------------------===// #include "clang/DependencyScanning/DependencyScanningWorker.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/DependencyScanning/DependencyScannerImpl.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" +#include "clang/Serialization/ObjectFilePCHContainerReader.h" using namespace clang; using namespace dependencies; @@ -37,39 +39,6 @@ DependencyScanningWorker::DependencyScanningWorker( DependencyScanningWorker::~DependencyScanningWorker() = default; DependencyActionController::~DependencyActionController() = default; -llvm::Error DependencyScanningWorker::computeDependencies( - StringRef WorkingDirectory, const std::vector &CommandLine, - DependencyConsumer &Consumer, DependencyActionController &Controller, - std::optional TUBuffer) { - // 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, TUBuffer)) - return llvm::Error::success(); - return llvm::make_error( - DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); -} - -static bool forEachDriverJob( - ArrayRef ArgStrs, DiagnosticsEngine &Diags, - IntrusiveRefCntPtr FS, - llvm::function_ref Callback) { - // Compilation holds a non-owning a reference to the Driver, hence we need to - // keep the Driver alive when we use Compilation. Arguments to commands may be - // owned by Alloc when expanded from response files. - llvm::BumpPtrAllocator Alloc; - auto [Driver, Compilation] = buildCompilation(ArgStrs, Diags, FS, Alloc); - if (!Compilation) - return false; - for (const driver::Command &Job : Compilation->getJobs()) { - if (!Callback(Job)) - return false; - } - return true; -} - static bool createAndRunToolInvocation( const std::vector &CommandLine, DependencyScanningAction &Action, @@ -86,114 +55,76 @@ static bool createAndRunToolInvocation( } bool DependencyScanningWorker::scanDependencies( - StringRef WorkingDirectory, const std::vector &CommandLine, + StringRef WorkingDirectory, ArrayRef> CommandLines, DependencyConsumer &Consumer, DependencyActionController &Controller, - DiagnosticConsumer &DC, - IntrusiveRefCntPtr OverlayFS) { - IntrusiveRefCntPtr FS = DepFS; - if (OverlayFS) { + DiagnosticsEngine &Diags, + llvm::IntrusiveRefCntPtr FS) { #ifndef NDEBUG - bool SawDepFS = false; - OverlayFS->visit( - [&](llvm::vfs::FileSystem &VFS) { SawDepFS |= &VFS == DepFS.get(); }); - assert(SawDepFS && "OverlayFS not based on DepFS"); + bool SawDepFS = false; + FS->visit( + [&](llvm::vfs::FileSystem &VFS) { SawDepFS |= &VFS == DepFS.get(); }); + assert(SawDepFS && "FS not based on DepFS"); #endif - FS = std::move(OverlayFS); - } - - DignosticsEngineWithDiagOpts DiagEngineWithCmdAndOpts(CommandLine, FS, DC); DependencyScanningAction Action(Service, WorkingDirectory, Consumer, Controller, DepFS); - bool Success = false; - if (CommandLine[1] == "-cc1") { - Success = - createAndRunToolInvocation(CommandLine, Action, FS, PCHContainerOps, - *DiagEngineWithCmdAndOpts.DiagEngine); - } else { - Success = forEachDriverJob( - CommandLine, *DiagEngineWithCmdAndOpts.DiagEngine, FS, - [&](const driver::Command &Cmd) { - if (StringRef(Cmd.getCreator().getName()) != "clang") { - // Non-clang command. Just pass through to the dependency - // consumer. - Consumer.handleBuildCommand( - {Cmd.getExecutable(), - {Cmd.getArguments().begin(), Cmd.getArguments().end()}}); - return true; - } - - // Insert -cc1 command line options into Argv - std::vector Argv; - Argv.push_back(Cmd.getExecutable()); - llvm::append_range(Argv, Cmd.getArguments()); - - // Create an invocation that uses the underlying file - // system to ensure that any file system requests that - // are made by the driver do not go through the - // dependency scanning filesystem. - return createAndRunToolInvocation( - std::move(Argv), Action, FS, PCHContainerOps, - *DiagEngineWithCmdAndOpts.DiagEngine); - }); - } - - if (Success && !Action.hasScanned()) - DiagEngineWithCmdAndOpts.DiagEngine->Report( - diag::err_fe_expected_compiler_job) - << llvm::join(CommandLine, " "); + const bool Success = llvm::all_of(CommandLines, [&](const auto &Cmd) { + if (StringRef(Cmd[1]) != "-cc1") { + // Non-clang command. Just pass through to the dependency consumer. + Consumer.handleBuildCommand({Cmd.front(), {Cmd.begin() + 1, Cmd.end()}}); + return true; + } + // Create an invocation that uses the underlying file system to ensure that + // any file system requests that are made by the driver do not go through + // the dependency scanning filesystem. + return createAndRunToolInvocation(Cmd, Action, FS, PCHContainerOps, Diags); + }); // Ensure finish() is called even if we never reached ExecuteAction(). if (!Action.hasDiagConsumerFinished()) - DC.finish(); + Diags.getClient()->finish(); return Success && Action.hasScanned(); } bool DependencyScanningWorker::computeDependencies( StringRef WorkingDirectory, const std::vector &CommandLine, - DependencyConsumer &Consumer, DependencyActionController &Controller, - DiagnosticConsumer &DC, std::optional TUBuffer) { - if (TUBuffer) { - auto [FinalFS, FinalCommandLine] = initVFSForTUBufferScanning( - DepFS, CommandLine, WorkingDirectory, *TUBuffer); - return scanDependencies(WorkingDirectory, FinalCommandLine, Consumer, - Controller, DC, FinalFS); - } else { - DepFS->setCurrentWorkingDirectory(WorkingDirectory); - return scanDependencies(WorkingDirectory, CommandLine, Consumer, Controller, - DC); - } -} - -llvm::Error -DependencyScanningWorker::initializeCompilerInstanceWithContextOrError( - StringRef CWD, const std::vector &CommandLine) { - bool Success = initializeCompilerInstanceWithContext(CWD, CommandLine); - return CIWithContext->handleReturnStatus(Success); + DependencyConsumer &DepConsumer, DependencyActionController &Controller, + DiagnosticConsumer &DiagConsumer, + llvm::IntrusiveRefCntPtr ScanFS) { + auto FinalFS = ScanFS == nullptr ? DepFS : ScanFS; + DignosticsEngineWithDiagOpts DiagEngineWithDiagOpts(CommandLine, FinalFS, + DiagConsumer); + return computeDependencies( + WorkingDirectory, ArrayRef>{CommandLine}, + DepConsumer, Controller, *DiagEngineWithDiagOpts.DiagEngine, ScanFS); } -llvm::Error -DependencyScanningWorker::computeDependenciesByNameWithContextOrError( - StringRef ModuleName, DependencyConsumer &Consumer, - DependencyActionController &Controller) { - bool Success = - computeDependenciesByNameWithContext(ModuleName, Consumer, Controller); - return CIWithContext->handleReturnStatus(Success); +bool DependencyScanningWorker::computeDependencies( + StringRef WorkingDirectory, ArrayRef> CommandLines, + DependencyConsumer &DepConsumer, DependencyActionController &Controller, + DiagnosticsEngine &Diags, + llvm::IntrusiveRefCntPtr ScanFS) { + auto FinalFS = ScanFS == nullptr ? DepFS : ScanFS; + return scanDependencies(WorkingDirectory, CommandLines, DepConsumer, + Controller, Diags, FinalFS); } -llvm::Error -DependencyScanningWorker::finalizeCompilerInstanceWithContextOrError() { - bool Success = finalizeCompilerInstance(); - return CIWithContext->handleReturnStatus(Success); +bool DependencyScanningWorker::initializeCompilerInstanceWithContext( + StringRef CWD, ArrayRef CommandLine, DiagnosticConsumer &DC) { + auto DiagEngineWithCmdAndOpts = + std::make_unique(CommandLine, DepFS, DC); + return initializeCompilerInstanceWithContext( + CWD, CommandLine, std::move(DiagEngineWithCmdAndOpts), DepFS); } bool DependencyScanningWorker::initializeCompilerInstanceWithContext( - StringRef CWD, const std::vector &CommandLine, - DiagnosticConsumer *DC) { + StringRef CWD, ArrayRef CommandLine, + std::unique_ptr DiagEngineWithDiagOpts, + IntrusiveRefCntPtr FS) { CIWithContext = std::make_unique(*this, CWD, CommandLine); - return CIWithContext->initialize(DC); + return CIWithContext->initialize(std::move(DiagEngineWithDiagOpts), FS); } bool DependencyScanningWorker::computeDependenciesByNameWithContext( @@ -203,6 +134,6 @@ bool DependencyScanningWorker::computeDependenciesByNameWithContext( return CIWithContext->computeDependencies(ModuleName, Consumer, Controller); } -bool DependencyScanningWorker::finalizeCompilerInstance() { +bool DependencyScanningWorker::finalizeCompilerInstanceWithContext() { return CIWithContext->finalize(); } diff --git a/clang/lib/Tooling/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanningTool.cpp index 1c3a35d1db3a3..19c5e448107fa 100644 --- a/clang/lib/Tooling/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanningTool.cpp @@ -7,7 +7,13 @@ //===----------------------------------------------------------------------===// #include "clang/Tooling/DependencyScanningTool.h" +#include "clang/Basic/DiagnosticFrontend.h" +#include "clang/DependencyScanning/DependencyScannerImpl.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Tool.h" #include "clang/Frontend/Utils.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/TargetParser/Host.h" #include using namespace clang; @@ -71,13 +77,183 @@ class MakeDependencyPrinterConsumer : public DependencyConsumer { }; } // anonymous namespace +static std::pair, + std::unique_ptr> +buildCompilation(ArrayRef CommandLine, DiagnosticsEngine &Diags, + IntrusiveRefCntPtr FS, + llvm::BumpPtrAllocator &Alloc) { + SmallVector Argv; + Argv.reserve(CommandLine.size()); + for (const std::string &Arg : CommandLine) + Argv.push_back(Arg.c_str()); + + std::unique_ptr Driver = std::make_unique( + Argv[0], llvm::sys::getDefaultTargetTriple(), Diags, + "clang LLVM compiler", FS); + Driver->setTitle("clang_based_tool"); + + bool CLMode = driver::IsClangCL( + driver::getDriverMode(Argv[0], ArrayRef(Argv).slice(1))); + + if (llvm::Error E = + driver::expandResponseFiles(Argv, CLMode, Alloc, FS.get())) { + Diags.Report(diag::err_drv_expand_response_file) + << llvm::toString(std::move(E)); + return std::make_pair(nullptr, nullptr); + } + + std::unique_ptr Compilation( + Driver->BuildCompilation(Argv)); + if (!Compilation) + return std::make_pair(nullptr, nullptr); + + if (Compilation->containsError()) + return std::make_pair(nullptr, nullptr); + + if (Compilation->getJobs().empty()) { + Diags.Report(diag::err_fe_expected_compiler_job) + << llvm::join(CommandLine, " "); + return std::make_pair(nullptr, nullptr); + } + + return std::make_pair(std::move(Driver), std::move(Compilation)); +} + +/// Constructs the full -cc1 command line, including executable, for the given +/// driver \c Cmd. +static std::vector +buildCC1CommandLine(const driver::Command &Cmd) { + const auto &Args = Cmd.getArguments(); + std::vector Out; + Out.reserve(Args.size() + 1); + Out.emplace_back(Cmd.getExecutable()); + llvm::append_range(Out, Args); + return Out; +} + +static std::pair, + std::vector> +initVFSForTUBufferScanning(IntrusiveRefCntPtr BaseFS, + ArrayRef CommandLine, + StringRef WorkingDirectory, + llvm::MemoryBufferRef TUBuffer) { + // Reset what might have been modified in the previous worker invocation. + BaseFS->setCurrentWorkingDirectory(WorkingDirectory); + + IntrusiveRefCntPtr ModifiedFS; + auto OverlayFS = + llvm::makeIntrusiveRefCnt(BaseFS); + auto InMemoryFS = llvm::makeIntrusiveRefCnt(); + InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory); + auto InputPath = TUBuffer.getBufferIdentifier(); + InMemoryFS->addFile( + InputPath, 0, llvm::MemoryBuffer::getMemBufferCopy(TUBuffer.getBuffer())); + IntrusiveRefCntPtr InMemoryOverlay = InMemoryFS; + + OverlayFS->pushOverlay(InMemoryOverlay); + std::vector ModifiedCommandLine(CommandLine); + ModifiedCommandLine.emplace_back(InputPath); + + return std::make_pair(OverlayFS, ModifiedCommandLine); +} + +static std::pair, + std::vector> +initVFSForByNameScanning(IntrusiveRefCntPtr BaseFS, + ArrayRef CommandLine, + StringRef WorkingDirectory, StringRef ModuleName) { + // If we're scanning based on a module name alone, we don't expect the client + // to provide us with an input file. However, the driver really wants to have + // one. Let's just make it up to make the driver happy. + auto OverlayFS = + llvm::makeIntrusiveRefCnt(BaseFS); + // Reset what might have been modified in the previous worker invocation. + OverlayFS->setCurrentWorkingDirectory(WorkingDirectory); + auto InMemoryFS = llvm::makeIntrusiveRefCnt(); + InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory); + SmallString<128> FakeInputPath; + // TODO: We should retry the creation if the path already exists. + llvm::sys::fs::createUniquePath(ModuleName + "-%%%%%%%%.input", FakeInputPath, + /*MakeAbsolute=*/false); + InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer("")); + OverlayFS->pushOverlay(InMemoryFS); + + std::vector ModifiedCommandLine(CommandLine); + ModifiedCommandLine.emplace_back(FakeInputPath); + + return std::make_pair(OverlayFS, ModifiedCommandLine); +} + +static llvm::Error makeErrorFromDiagnosticsOS( + TextDiagnosticsPrinterWithOutput &DiagPrinterWithOS) { + return llvm::make_error( + DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); +} + +static bool computeDependenciesForDriverCommandLine( + DependencyScanningWorker &Worker, StringRef WorkingDirectory, + ArrayRef CommandLine, DependencyConsumer &Consumer, + DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, + IntrusiveRefCntPtr ScanFS) { + Worker.getVFS().setCurrentWorkingDirectory(WorkingDirectory); + + DignosticsEngineWithDiagOpts DiagEngineWithDiagOpts( + CommandLine, &Worker.getVFS(), DiagConsumer); + auto &Diags = *DiagEngineWithDiagOpts.DiagEngine; + + // Compilation holds a non-owning a reference to the Driver, hence we need to + // keep the Driver alive when we use Compilation. Arguments to commands may be + // owned by Alloc when expanded from response files. + llvm::BumpPtrAllocator Alloc; + const auto [Driver, Compilation] = buildCompilation( + CommandLine, *DiagEngineWithDiagOpts.DiagEngine, &Worker.getVFS(), Alloc); + if (!Compilation) + return false; + + const auto CC1Commands = llvm::to_vector( + llvm::map_range(Compilation->getJobs(), buildCC1CommandLine)); + + return Worker.computeDependencies(WorkingDirectory, CC1Commands, Consumer, + Controller, Diags, ScanFS); +} + +static llvm::Error computeDependenciesOrError( + DependencyScanningWorker &Worker, StringRef WorkingDirectory, + ArrayRef CommandLine, DependencyConsumer &Consumer, + DependencyActionController &Controller, + std::optional TUBuffer = std::nullopt) { + auto [OverlayFS, FinalCommandLine] = [&]() { + if (TUBuffer) + return initVFSForTUBufferScanning(&Worker.getVFS(), CommandLine, + WorkingDirectory, *TUBuffer); + return std::make_pair( + IntrusiveRefCntPtr(&Worker.getVFS()), + std::vector(CommandLine.begin(), CommandLine.end())); + }(); + + TextDiagnosticsPrinterWithOutput DiagPrinterWithOS(CommandLine); + + const auto IsCC1Input = (FinalCommandLine[1] == "-cc1"); + const auto Success = + IsCC1Input + ? Worker.computeDependencies(WorkingDirectory, FinalCommandLine, + Consumer, Controller, + DiagPrinterWithOS.DiagPrinter, OverlayFS) + : computeDependenciesForDriverCommandLine( + Worker, WorkingDirectory, FinalCommandLine, Consumer, + Controller, DiagPrinterWithOS.DiagPrinter, OverlayFS); + + if (!Success) + return makeErrorFromDiagnosticsOS(DiagPrinterWithOS); + return llvm::Error::success(); +} + llvm::Expected DependencyScanningTool::getDependencyFile( const std::vector &CommandLine, StringRef CWD) { MakeDependencyPrinterConsumer Consumer; CallbackActionController Controller(nullptr); - auto Result = - Worker.computeDependencies(CWD, CommandLine, Consumer, Controller); - if (Result) + if (auto Result = computeDependenciesOrError(Worker, CWD, CommandLine, + Consumer, Controller)) return std::move(Result); std::string Output; Consumer.printDependencies(Output); @@ -128,9 +304,8 @@ llvm::Expected DependencyScanningTool::getP1689ModuleDependencyFile( P1689Rule Rule; P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command); P1689ActionController Controller; - auto Result = Worker.computeDependencies(CWD, Command.CommandLine, Consumer, - Controller); - if (Result) + if (auto Result = computeDependenciesOrError(Worker, CWD, Command.CommandLine, + Consumer, Controller)) return std::move(Result); MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath(); @@ -147,10 +322,8 @@ DependencyScanningTool::getTranslationUnitDependencies( std::optional TUBuffer) { FullDependencyConsumer Consumer(AlreadySeen); CallbackActionController Controller(LookupModuleOutput); - llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer, - Controller, TUBuffer); - - if (Result) + if (auto Result = computeDependenciesOrError(Worker, CWD, CommandLine, + Consumer, Controller, TUBuffer)) return std::move(Result); return Consumer.takeTranslationUnitDeps(); } @@ -160,43 +333,92 @@ DependencyScanningTool::getModuleDependencies( StringRef ModuleName, const std::vector &CommandLine, StringRef CWD, const llvm::DenseSet &AlreadySeen, LookupModuleOutputCallback LookupModuleOutput) { - FullDependencyConsumer Consumer(AlreadySeen); - CallbackActionController Controller(LookupModuleOutput); if (auto Error = - Worker.initializeCompilerInstanceWithContextOrError(CWD, CommandLine)) - return std::move(Error); + initializeCompilerInstanceWithContextOrError(CWD, CommandLine)) + return Error; - auto Result = Worker.computeDependenciesByNameWithContextOrError( - ModuleName, Consumer, Controller); + auto Result = computeDependenciesByNameWithContextOrError( + ModuleName, AlreadySeen, LookupModuleOutput); - if (auto Error = Worker.finalizeCompilerInstanceWithContextOrError()) - return std::move(Error); + if (auto Error = finalizeCompilerInstanceWithContextOrError()) + return Error; - if (Result) - return std::move(Result); + return Result; +} - return Consumer.takeTranslationUnitDeps(); +static std::optional> getFirstCC1CommandLine( + ArrayRef CommandLine, DiagnosticsEngine &Diags, + llvm::IntrusiveRefCntPtr ScanFS) { + // Compilation holds a non-owning a reference to the Driver, hence we need to + // keep the Driver alive when we use Compilation. Arguments to commands may be + // owned by Alloc when expanded from response files. + llvm::BumpPtrAllocator Alloc; + const auto [Driver, Compilation] = + buildCompilation(CommandLine, Diags, ScanFS, Alloc); + if (!Compilation) + return std::nullopt; + + const auto IsClangCmd = [](const driver::Command &Cmd) { + return StringRef(Cmd.getCreator().getName()) == "clang"; + }; + const auto CC1CommandLineRange = llvm::map_range( + llvm::make_filter_range(Compilation->getJobs(), IsClangCmd), + buildCC1CommandLine); + + if (CC1CommandLineRange.empty()) + return std::nullopt; + return *CC1CommandLineRange.begin(); } -llvm::Error DependencyScanningTool::initializeCompilerInstanceWithContext( - StringRef CWD, const std::vector &CommandLine) { - return Worker.initializeCompilerInstanceWithContextOrError(CWD, CommandLine); +llvm::Error +DependencyScanningTool::initializeCompilerInstanceWithContextOrError( + StringRef CWD, ArrayRef CommandLine) { + // For by name scanning, we allow command lines without an actual input file + // by adding an in-memory placeholder input. + auto OverlayFSAndArgs = initVFSForByNameScanning( + &Worker.getVFS(), CommandLine, CWD, "ScanningByName"); + auto &OverlayFS = OverlayFSAndArgs.first; + const auto &ModifiedCommandLine = OverlayFSAndArgs.second; + + DiagPrinterWithOS = + std::make_unique(CommandLine); + auto DiagEngineWithCmdAndOpts = + std::make_unique( + CommandLine, OverlayFS, DiagPrinterWithOS->DiagPrinter); + + const auto InitWithCommandLine = + [&](ArrayRef CommandLine) -> llvm::Error { + if (Worker.initializeCompilerInstanceWithContext( + CWD, CommandLine, std::move(DiagEngineWithCmdAndOpts), OverlayFS)) + return llvm::Error::success(); + return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); + }; + + if (CommandLine.size() >= 2 && CommandLine[1] == "-cc1") + return InitWithCommandLine(CommandLine); + + const auto MaybeFirstCC1 = getFirstCC1CommandLine( + ModifiedCommandLine, *DiagEngineWithCmdAndOpts->DiagEngine, OverlayFS); + if (!MaybeFirstCC1) + return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); + return InitWithCommandLine(*MaybeFirstCC1); } llvm::Expected -DependencyScanningTool::computeDependenciesByNameWithContext( +DependencyScanningTool::computeDependenciesByNameWithContextOrError( StringRef ModuleName, const llvm::DenseSet &AlreadySeen, LookupModuleOutputCallback LookupModuleOutput) { FullDependencyConsumer Consumer(AlreadySeen); CallbackActionController Controller(LookupModuleOutput); - llvm::Error Result = Worker.computeDependenciesByNameWithContextOrError( - ModuleName, Consumer, Controller); - if (Result) - return std::move(Result); - - return Consumer.takeTranslationUnitDeps(); + if (Worker.computeDependenciesByNameWithContext(ModuleName, Consumer, + Controller)) + return Consumer.takeTranslationUnitDeps(); + return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); } -llvm::Error DependencyScanningTool::finalizeCompilerInstanceWithContext() { - return Worker.finalizeCompilerInstanceWithContextOrError(); +llvm::Error +DependencyScanningTool::finalizeCompilerInstanceWithContextOrError() { + if (Worker.finalizeCompilerInstanceWithContext()) + return llvm::Error::success(); + return makeErrorFromDiagnosticsOS(*DiagPrinterWithOS); } diff --git a/clang/test/ClangScanDeps/modules-full-by-mod-name.c b/clang/test/ClangScanDeps/modules-full-by-mod-name.c index edb99636aaf25..2d2c9acd30011 100644 --- a/clang/test/ClangScanDeps/modules-full-by-mod-name.c +++ b/clang/test/ClangScanDeps/modules-full-by-mod-name.c @@ -28,6 +28,17 @@ module transitive { header "transitive.h" } // RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -module-names=root > %t/result.json // RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s +//--- cdb.cc1.json.template +[{ + "file": "", + "directory": "DIR", + "command": "clang -cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -I DIR -x c" +}] + +// RUN: sed "s|DIR|%/t|g" %t/cdb.cc1.json.template > %t/cdb.cc1.json +// RUN: clang-scan-deps -compilation-database %t/cdb.cc1.json -format experimental-full -module-names=root > %t/result.cc1.json +// RUN: cat %t/result.cc1.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s + // CHECK: { // CHECK-NEXT: "modules": [ // CHECK-NEXT: { diff --git a/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c b/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c index 030f7f3427810..3b7074219db84 100644 --- a/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c +++ b/clang/test/ClangScanDeps/modules-full-by-mult-mod-names.c @@ -22,17 +22,52 @@ module root1 { header "root1.h"} // This is here to verify that the "root" directory doesn't clash with name of // the "root" module. +//--- main.cpp + //--- cdb.json.template [{ "file": "", "directory": "DIR", - "command": "clang -fmodules -fmodules-cache-path=DIR/cache -I DIR -x c" + "command": "clang -fmodules -fmodules-cache-path=DIR/cache -I DIR -x c main.cpp" }] // 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 +//--- cdb.no-input.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.no-input.json.template > %t/cdb.no-input.json +// RUN: clang-scan-deps -compilation-database %t/cdb.no-input.json -format experimental-full -module-names=root,root1,direct > %t/result.no-input.json +// RUN: cat %t/result.no-input.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s + +//--- cdb.cc1.json.template +[{ + "file": "", + "directory": "DIR", + "command": "clang -cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -I DIR -x c main.cpp" +}] + +// RUN: sed "s|DIR|%/t|g" %t/cdb.cc1.json.template > %t/cdb.cc1.json +// RUN: clang-scan-deps -compilation-database %t/cdb.cc1.json -format experimental-full -module-names=root,root1,direct > %t/result.cc1.json +// RUN: cat %t/result.cc1.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s + +//--- cdb.cc1.no-input.json.template +[{ + "file": "", + "directory": "DIR", + "command": "clang -cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -I DIR -x c" +}] + +// RUN: sed "s|DIR|%/t|g" %t/cdb.cc1.no-input.json.template > %t/cdb.cc1.no-input.json +// RUN: clang-scan-deps -compilation-database %t/cdb.cc1.no-input.json -format experimental-full -module-names=root,root1,direct > %t/result.cc1.no-input.json +// RUN: cat %t/result.cc1.no-input.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s + // CHECK: { // CHECK-NEXT: "modules": [ // CHECK-NEXT: { diff --git a/clang/test/ClangScanDeps/tu-buffer.c b/clang/test/ClangScanDeps/tu-buffer.c index b450b13ff434b..ce3b037174c26 100644 --- a/clang/test/ClangScanDeps/tu-buffer.c +++ b/clang/test/ClangScanDeps/tu-buffer.c @@ -37,6 +37,17 @@ module addition { header "addition.h" } // RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -tu-buffer-path %t/tu.c > %t/result.json // RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s --check-prefix=CHECK +//--- cdb.cc1.json.template +[{ + "file": "", + "directory": "DIR", + "command": "clang -cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -I DIR -x c -emit-obj" +}] + +// RUN: sed "s|DIR|%/t|g" %t/cdb.cc1.json.template > %t/cdb.cc1.json +// RUN: clang-scan-deps -compilation-database %t/cdb.cc1.json -format experimental-full -tu-buffer-path %t/tu.c > %t/result.cc1.json +// RUN: cat %t/result.cc1.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s --check-prefix=CHECK + // CHECK: { // CHECK-NEXT: "modules": [ // CHECK-NEXT: { diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index 07157ae2dc06a..9acd0aca737ba 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -1105,7 +1105,7 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { HadErrors = true; } else { if (llvm::Error Err = - WorkerTool.initializeCompilerInstanceWithContext( + WorkerTool.initializeCompilerInstanceWithContextOrError( CWD, Input->CommandLine)) { handleErrorWithInfoString( "Compiler instance with context setup error", std::move(Err), @@ -1116,7 +1116,7 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { for (auto N : Names) { auto MaybeModuleDepsGraph = - WorkerTool.computeDependenciesByNameWithContext( + WorkerTool.computeDependenciesByNameWithContextOrError( N, AlreadySeenModules, LookupOutput); if (handleModuleResult(N, MaybeModuleDepsGraph, *FD, LocalIndex, DependencyOS, Errs)) { @@ -1126,7 +1126,7 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { } if (llvm::Error Err = - WorkerTool.finalizeCompilerInstanceWithContext()) { + WorkerTool.finalizeCompilerInstanceWithContextOrError()) { handleErrorWithInfoString( "Compiler instance with context finialization error", std::move(Err), DependencyOS, Errs); diff --git a/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp b/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp index e6a5684b10cc9..ca51d5ea982d9 100644 --- a/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp +++ b/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp @@ -46,13 +46,9 @@ TEST(DependencyScanner, ScanDepsWithDiagConsumer) { { // Check that a successful scan calls DiagConsumer.finish(). - std::vector Args = {"clang", - "-target", - "x86_64-apple-macosx10.7", - "-c", - "test.cpp", - "-o" - "test.cpp.o"}; + std::vector Args = { + "clang", "-cc1", "-triple", "x86_64-apple-macosx10.7.0", + "-emit-obj", "test.cpp", "-o", "test.cpp.o"}; EnsureFinishedConsumer DiagConsumer; bool Success = Worker.computeDependencies(CWD, Args, DC, AC, DiagConsumer); @@ -65,7 +61,7 @@ TEST(DependencyScanner, ScanDepsWithDiagConsumer) { { // Check that an invalid command-line, which never enters the scanning // action calls DiagConsumer.finish(). - std::vector Args = {"clang", "-invalid-arg"}; + std::vector Args = {"clang", "-cc1", "-invalid-arg"}; EnsureFinishedConsumer DiagConsumer; bool Success = Worker.computeDependencies(CWD, Args, DC, AC, DiagConsumer); @@ -77,15 +73,10 @@ TEST(DependencyScanner, ScanDepsWithDiagConsumer) { { // Check that a valid command line that produces no scanning jobs calls // DiagConsumer.finish(). - std::vector Args = {"clang", - "-target", - "x86_64-apple-macosx10.7", - "-c", - "-x", - "assembler", - "test.s", - "-o" - "test.cpp.o"}; + std::vector Args = { + "clang", "-cc1", "-triple", "x86_64-apple-macosx10.7.0", + "-emit-obj", "-x", "assembler", "test.s", + "-o", "test.cpp.o"}; EnsureFinishedConsumer DiagConsumer; bool Success = Worker.computeDependencies(CWD, Args, DC, AC, DiagConsumer);