diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h index 221906f9f9382b..4750c9dfa9a21f 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h @@ -73,6 +73,13 @@ class DependencyScanningWorker { /// ModuleName isn't empty, this function reports the dependencies of module /// \p ModuleName. /// + /// \returns false if clang errors occurred (with diagnostics reported to + /// \c DiagConsumer), true otherwise. + bool computeDependencies(StringRef WorkingDirectory, + const std::vector &CommandLine, + DependencyConsumer &DepConsumer, + DiagnosticConsumer &DiagConsumer, + llvm::Optional ModuleName = None); /// \returns A \c StringError with the diagnostic output if clang errors /// occurred, success otherwise. llvm::Error computeDependencies(StringRef WorkingDirectory, diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 7474e0272505ed..329eded0e34340 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -340,19 +340,23 @@ DependencyScanningWorker::DependencyScanningWorker( Files = new FileManager(FileSystemOptions(), RealFS); } -static llvm::Error -runWithDiags(DiagnosticOptions *DiagOpts, - llvm::function_ref - BodyShouldSucceed) { +llvm::Error DependencyScanningWorker::computeDependencies( + StringRef WorkingDirectory, const std::vector &CommandLine, + DependencyConsumer &Consumer, llvm::Optional ModuleName) { + std::vector CLI; + for (const std::string &Arg : CommandLine) + CLI.push_back(Arg.c_str()); + auto DiagOpts = CreateAndPopulateDiagOpts(CLI); sanitizeDiagOpts(*DiagOpts); // Capture the emitted diagnostics and report them to the client // in the case of a failure. std::string DiagnosticOutput; llvm::raw_string_ostream DiagnosticsOS(DiagnosticOutput); - TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts); + TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release()); - if (BodyShouldSucceed(DiagPrinter, *DiagOpts)) + if (computeDependencies(WorkingDirectory, CommandLine, Consumer, DiagPrinter, + ModuleName)) return llvm::Error::success(); return llvm::make_error(DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); @@ -388,9 +392,10 @@ static bool forEachDriverJob( return true; } -llvm::Error DependencyScanningWorker::computeDependencies( +bool DependencyScanningWorker::computeDependencies( StringRef WorkingDirectory, const std::vector &CommandLine, - DependencyConsumer &Consumer, llvm::Optional ModuleName) { + DependencyConsumer &Consumer, DiagnosticConsumer &DC, + llvm::Optional ModuleName) { // Reset what might have been modified in the previous worker invocation. RealFS->setCurrentWorkingDirectory(WorkingDirectory); if (Files) @@ -413,60 +418,57 @@ llvm::Error DependencyScanningWorker::computeDependencies( llvm::transform(CommandLine, FinalCCommandLine.begin(), [](const std::string &Str) { return Str.c_str(); }); - return runWithDiags( - CreateAndPopulateDiagOpts(FinalCCommandLine).release(), - [&](DiagnosticConsumer &DC, DiagnosticOptions &DiagOpts) { - IntrusiveRefCntPtr Diags = - CompilerInstance::createDiagnostics(&DiagOpts, &DC, false); - // Although `Diagnostics` are used only for command-line parsing, the - // custom `DiagConsumer` might expect a `SourceManager` to be present. - SourceManager SrcMgr(*Diags, *CurrentFiles); - Diags->setSourceManager(&SrcMgr); - // DisableFree is modified by Tooling for running - // in-process; preserve the original value, which is - // always true for a driver invocation. - bool DisableFree = true; - DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS, - Format, OptimizeArgs, EagerLoadModules, - DisableFree, ModuleName); - bool Success = forEachDriverJob( - FinalCommandLine, *Diags, *CurrentFiles, - [&](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; - } - - std::vector Argv; - Argv.push_back(Cmd.getExecutable()); - Argv.insert(Argv.end(), Cmd.getArguments().begin(), - Cmd.getArguments().end()); - - // 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. - ToolInvocation Invocation(std::move(Argv), &Action, - &*CurrentFiles, PCHContainerOps); - Invocation.setDiagnosticConsumer(Diags->getClient()); - Invocation.setDiagnosticOptions(&Diags->getDiagnosticOptions()); - if (!Invocation.run()) - return false; - - std::vector Args = Action.takeLastCC1Arguments(); - Consumer.handleBuildCommand( - {Cmd.getExecutable(), std::move(Args)}); - return true; - }); - - if (Success && !Action.hasScanned()) { - Diags->Report(diag::err_fe_expected_compiler_job) - << llvm::join(FinalCommandLine, " "); + auto DiagOpts = CreateAndPopulateDiagOpts(FinalCCommandLine); + sanitizeDiagOpts(*DiagOpts); + IntrusiveRefCntPtr Diags = + CompilerInstance::createDiagnostics(DiagOpts.release(), &DC, + /*ShouldOwnClient=*/false); + + // Although `Diagnostics` are used only for command-line parsing, the + // custom `DiagConsumer` might expect a `SourceManager` to be present. + SourceManager SrcMgr(*Diags, *CurrentFiles); + Diags->setSourceManager(&SrcMgr); + // DisableFree is modified by Tooling for running + // in-process; preserve the original value, which is + // always true for a driver invocation. + bool DisableFree = true; + DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS, Format, + OptimizeArgs, EagerLoadModules, DisableFree, + ModuleName); + bool Success = forEachDriverJob( + FinalCommandLine, *Diags, *CurrentFiles, [&](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; } - return Success && Action.hasScanned(); + + std::vector Argv; + Argv.push_back(Cmd.getExecutable()); + Argv.insert(Argv.end(), Cmd.getArguments().begin(), + Cmd.getArguments().end()); + + // 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. + ToolInvocation Invocation(std::move(Argv), &Action, &*CurrentFiles, + PCHContainerOps); + Invocation.setDiagnosticConsumer(Diags->getClient()); + Invocation.setDiagnosticOptions(&Diags->getDiagnosticOptions()); + if (!Invocation.run()) + return false; + + std::vector Args = Action.takeLastCC1Arguments(); + Consumer.handleBuildCommand({Cmd.getExecutable(), std::move(Args)}); + return true; }); + + if (Success && !Action.hasScanned()) + Diags->Report(diag::err_fe_expected_compiler_job) + << llvm::join(FinalCommandLine, " "); + return Success && Action.hasScanned(); }