diff --git a/clang/include/clang/DependencyScanning/DependencyScannerImpl.h b/clang/include/clang/DependencyScanning/DependencyScannerImpl.h index f43c7f70183fd..231873375a264 100644 --- a/clang/include/clang/DependencyScanning/DependencyScannerImpl.h +++ b/clang/include/clang/DependencyScanning/DependencyScannerImpl.h @@ -89,28 +89,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, diff --git a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h index 3c5e7660a8c7b..75a84e378b5fa 100644 --- a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h @@ -16,7 +16,7 @@ #include "clang/DependencyScanning/DependencyScanningService.h" #include "clang/DependencyScanning/ModuleDepCollector.h" #include "clang/Frontend/PCHContainerOperations.h" -#include "llvm/Support/Error.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/VirtualFileSystem.h" @@ -93,11 +93,13 @@ 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 worker for the given frontend command-line, + /// and report the discovered dependencies to the provided consumer. + /// + /// OverlayFS should be based on the Worker's dependency scanning file-system + /// and can be used to provide any input specified on the command-line as + /// in-memory file. If no overlay file-system is provided, the Worker's + /// dependency scanning file-system is used instead. /// /// \returns false if clang errors occurred (with diagnostics reported to /// \c DiagConsumer), true otherwise. @@ -105,7 +107,25 @@ class DependencyScanningWorker { StringRef WorkingDirectory, ArrayRef CommandLine, DependencyConsumer &DepConsumer, DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, - std::optional TUBuffer = std::nullopt); + llvm::IntrusiveRefCntPtr OverlayFS = + nullptr); + + /// Run the dependency scanning tool for all given frontend command-lines, + /// and report the discovered dependencies to the provided consumer. + /// + /// OverlayFS should be based on the Worker's dependency scanning file-system + /// and can be used to provide any input specified on the command-line as + /// in-memory file. If no overlay file-system is provided, the Worker's + /// dependency scanning file-system is used instead. + /// + /// \returns false if clang errors occurred (with diagnostics reported to + /// \c DiagConsumer), true otherwise. + bool computeDependencies( + StringRef WorkingDirectory, ArrayRef> CommandLines, + DependencyConsumer &DepConsumer, DependencyActionController &Controller, + DiagnosticConsumer &DiagConsumer, + llvm::IntrusiveRefCntPtr OverlayFS = + nullptr); /// The three method below implements a new interface for by name /// dependency scanning. They together enable the dependency scanning worker @@ -162,16 +182,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, ArrayRef CommandLine, - DependencyConsumer &Consumer, DependencyActionController &Controller, - DiagnosticConsumer &DC, - IntrusiveRefCntPtr OverlayFS = nullptr); }; +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); + } // end namespace dependencies } // end namespace clang diff --git a/clang/lib/DependencyScanning/CMakeLists.txt b/clang/lib/DependencyScanning/CMakeLists.txt index 2976f7c236f2e..4c30c3ee57cfd 100644 --- a/clang/lib/DependencyScanning/CMakeLists.txt +++ b/clang/lib/DependencyScanning/CMakeLists.txt @@ -20,7 +20,6 @@ add_clang_library(clangDependencyScanning LINK_LIBS clangAST clangBasic - clangDriver clangFrontend clangLex clangSerialization diff --git a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp index 201230d7d6a8e..7fb214eb2e630 100644 --- a/clang/lib/DependencyScanning/DependencyScannerImpl.cpp +++ b/clang/lib/DependencyScanning/DependencyScannerImpl.cpp @@ -379,42 +379,6 @@ DiagnosticsEngineWithDiagOpts::DiagnosticsEngineWithDiagOpts( /*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,61 +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); - - 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); -} - -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, diff --git a/clang/lib/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/DependencyScanning/DependencyScanningWorker.cpp index ea2a6d67948c3..266660cdfab28 100644 --- a/clang/lib/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/DependencyScanning/DependencyScanningWorker.cpp @@ -13,6 +13,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/Tool.h" #include "clang/Serialization/ObjectFilePCHContainerReader.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" #include "llvm/Support/VirtualFileSystem.h" using namespace clang; @@ -40,24 +41,6 @@ DependencyScanningWorker::DependencyScanningWorker( DependencyScanningWorker::~DependencyScanningWorker() = default; DependencyActionController::~DependencyActionController() = default; -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( ArrayRef CommandLine, DependencyScanningAction &Action, IntrusiveRefCntPtr FS, @@ -72,12 +55,22 @@ static bool createAndRunToolInvocation( Diags.getClient()); } -bool DependencyScanningWorker::scanDependencies( +bool DependencyScanningWorker::computeDependencies( StringRef WorkingDirectory, ArrayRef CommandLine, - DependencyConsumer &Consumer, DependencyActionController &Controller, - DiagnosticConsumer &DC, - IntrusiveRefCntPtr OverlayFS) { - IntrusiveRefCntPtr FS = DepFS; + DependencyConsumer &DepConsumer, DependencyActionController &Controller, + DiagnosticConsumer &DiagConsumer, + llvm::IntrusiveRefCntPtr OverlayFS) { + return computeDependencies(WorkingDirectory, + ArrayRef>(CommandLine), + DepConsumer, Controller, DiagConsumer, OverlayFS); +} + +bool DependencyScanningWorker::computeDependencies( + StringRef WorkingDirectory, ArrayRef> CommandLines, + DependencyConsumer &DepConsumer, DependencyActionController &Controller, + DiagnosticConsumer &DiagConsumer, + llvm::IntrusiveRefCntPtr OverlayFS) { + IntrusiveRefCntPtr FS = nullptr; if (OverlayFS) { #ifndef NDEBUG bool SawDepFS = false; @@ -86,73 +79,39 @@ bool DependencyScanningWorker::scanDependencies( assert(SawDepFS && "OverlayFS not based on DepFS"); #endif FS = std::move(OverlayFS); + } else { + FS = DepFS; + FS->setCurrentWorkingDirectory(WorkingDirectory); } - DiagnosticsEngineWithDiagOpts DiagEngineWithCmdAndOpts(CommandLine, FS, DC); - DependencyScanningAction Action(Service, WorkingDirectory, Consumer, + DependencyScanningAction Action(Service, WorkingDirectory, DepConsumer, 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); - }); - } + 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. + DepConsumer.handleBuildCommand( + {Cmd.front(), {Cmd.begin() + 1, Cmd.end()}}); + return true; + } - if (Success && !Action.hasScanned()) - DiagEngineWithCmdAndOpts.DiagEngine->Report( - diag::err_fe_expected_compiler_job) - << llvm::join(CommandLine, " "); + auto DiagEngineWithDiagOpts = + DiagnosticsEngineWithDiagOpts(Cmd, OverlayFS, DiagConsumer); + auto &Diags = *DiagEngineWithDiagOpts.DiagEngine; + + // 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(); + DiagConsumer.finish(); return Success && Action.hasScanned(); } -bool DependencyScanningWorker::computeDependencies( - StringRef WorkingDirectory, ArrayRef 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); - } - - DepFS->setCurrentWorkingDirectory(WorkingDirectory); - return scanDependencies(WorkingDirectory, CommandLine, Consumer, Controller, - DC); -} - bool DependencyScanningWorker::initializeCompilerInstanceWithContext( StringRef CWD, ArrayRef CommandLine, DiagnosticConsumer &DC) { auto [OverlayFS, ModifiedCommandLine] = @@ -184,3 +143,58 @@ bool DependencyScanningWorker::computeDependenciesByNameWithContext( bool DependencyScanningWorker::finalizeCompilerInstanceWithContext() { return CIWithContext->finalize(); } + +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); + + 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); +} + +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); +} diff --git a/clang/lib/Tooling/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanningTool.cpp index 986b4166bebd4..e61289f4a45d0 100644 --- a/clang/lib/Tooling/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanningTool.cpp @@ -7,10 +7,15 @@ //===----------------------------------------------------------------------===// #include "clang/Tooling/DependencyScanningTool.h" +#include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticFrontend.h" #include "clang/DependencyScanning/DependencyScannerImpl.h" #include "clang/Driver/Tool.h" #include "clang/Frontend/Utils.h" +#include "llvm/ADT/SmallVectorExtras.h" +#include "llvm/ADT/iterator.h" +#include "llvm/Support/VirtualFileSystem.h" +#include "llvm/TargetParser/Host.h" #include using namespace clang; @@ -74,14 +79,124 @@ class MakeDependencyPrinterConsumer : public DependencyConsumer { }; } // anonymous namespace +static std::pair, + std::unique_ptr> +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); + + if (Compilation->getJobs().empty()) { + Diags.Report(diag::err_fe_expected_compiler_job) + << llvm::join(ArgStrs, " "); + return std::make_pair(nullptr, nullptr); + } + + return std::make_pair(std::move(Driver), std::move(Compilation)); +} + +/// Constructs the full frontend command line, including executable, for the +/// given driver \c Cmd. +static SmallVector +buildCC1CommandLine(const driver::Command &Cmd) { + const auto &Args = Cmd.getArguments(); + SmallVector Out; + Out.reserve(Args.size() + 1); + Out.emplace_back(Cmd.getExecutable()); + llvm::append_range(Out, Args); + return Out; +} + +static bool computeDependenciesForDriverCommandLine( + DependencyScanningWorker &Worker, StringRef WorkingDirectory, + ArrayRef CommandLine, DependencyConsumer &Consumer, + DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, + IntrusiveRefCntPtr OverlayFS) { + IntrusiveRefCntPtr FS = nullptr; + if (OverlayFS) { + FS = OverlayFS; + } else { + FS = &Worker.getVFS(); + FS->setCurrentWorkingDirectory(WorkingDirectory); + } + + // 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 DiagEngineWithDiagOpts = + DiagnosticsEngineWithDiagOpts(CommandLine, FS, DiagConsumer); + const auto [Driver, Compilation] = buildCompilation( + CommandLine, *DiagEngineWithDiagOpts.DiagEngine, FS, Alloc); + if (!Compilation) + return false; + + SmallVector> FrontendCommandLines; + for (const auto &Cmd : Compilation->getJobs()) + FrontendCommandLines.push_back(buildCC1CommandLine(Cmd)); + SmallVector> FrontendCommandLinesView( + FrontendCommandLines.begin(), FrontendCommandLines.end()); + + return Worker.computeDependencies(WorkingDirectory, FrontendCommandLinesView, + Consumer, Controller, DiagConsumer, + OverlayFS); +} + +static llvm::Error makeErrorFromDiagnosticsOS( + TextDiagnosticsPrinterWithOutput &DiagPrinterWithOS) { + return llvm::make_error( + DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); +} + +static bool computeDependencies( + DependencyScanningWorker &Worker, StringRef WorkingDirectory, + ArrayRef CommandLine, DependencyConsumer &Consumer, + DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, + llvm::IntrusiveRefCntPtr OverlayFS = + nullptr) { + const auto IsCC1Input = (CommandLine.size() >= 2 && CommandLine[1] == "-cc1"); + return IsCC1Input ? Worker.computeDependencies(WorkingDirectory, CommandLine, + Consumer, Controller, + DiagConsumer, OverlayFS) + : computeDependenciesForDriverCommandLine( + Worker, WorkingDirectory, CommandLine, Consumer, + Controller, DiagConsumer, OverlayFS); +} + std::optional DependencyScanningTool::getDependencyFile(ArrayRef CommandLine, StringRef CWD, DiagnosticConsumer &DiagConsumer) { MakeDependencyPrinterConsumer DepConsumer; CallbackActionController Controller(nullptr); - if (!Worker.computeDependencies(CWD, CommandLine, DepConsumer, Controller, - DiagConsumer)) + if (!computeDependencies(Worker, CWD, CommandLine, DepConsumer, Controller, + DiagConsumer)) return std::nullopt; std::string Output; DepConsumer.printDependencies(Output); @@ -132,8 +247,8 @@ std::optional DependencyScanningTool::getP1689ModuleDependencyFile( P1689Rule Rule; P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command); P1689ActionController Controller; - if (!Worker.computeDependencies(CWD, Command.CommandLine, Consumer, - Controller, DiagConsumer)) + if (!computeDependencies(Worker, CWD, Command.CommandLine, Consumer, + Controller, DiagConsumer)) return std::nullopt; MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath(); @@ -152,8 +267,19 @@ DependencyScanningTool::getTranslationUnitDependencies( FullDependencyConsumer Consumer(AlreadySeen); CallbackActionController Controller(LookupModuleOutput); - if (!Worker.computeDependencies(CWD, CommandLine, Consumer, Controller, - DiagConsumer, TUBuffer)) + // If we are scanning from a TUBuffer, create an overlay filesystem with the + // input as an in-memory file and add it to the command line. + IntrusiveRefCntPtr OverlayFS = nullptr; + std::vector CommandLineWithTUBufferInput; + if (TUBuffer) { + std::tie(OverlayFS, CommandLineWithTUBufferInput) = + initVFSForTUBufferScanning(&Worker.getVFS(), CommandLine, CWD, + *TUBuffer); + CommandLine = CommandLineWithTUBufferInput; + } + + if (!computeDependencies(Worker, CWD, CommandLine, Consumer, Controller, + DiagConsumer, OverlayFS)) return std::nullopt; return Consumer.takeTranslationUnitDeps(); } @@ -176,19 +302,7 @@ DependencyScanningTool::getModuleDependencies( return Result; } -/// 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::optional> getFirstCC1CommandLine( +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 @@ -210,12 +324,6 @@ static std::optional> getFirstCC1CommandLine( return std::nullopt; } -static llvm::Error makeErrorFromDiagnosticsOS( - TextDiagnosticsPrinterWithOutput &DiagPrinterWithOS) { - return llvm::make_error( - DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); -} - bool DependencyScanningTool::initializeWorkerCIWithContextFromCommandline( DependencyScanningWorker &Worker, StringRef CWD, ArrayRef CommandLine, DiagnosticConsumer &DC) { diff --git a/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp b/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp index e6a5684b10cc9..872c7effde3d3 100644 --- a/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp +++ b/clang/unittests/DependencyScanning/DependencyScanningWorkerTest.cpp @@ -47,9 +47,10 @@ TEST(DependencyScanner, ScanDepsWithDiagConsumer) { { // Check that a successful scan calls DiagConsumer.finish(). std::vector Args = {"clang", - "-target", + "-cc1", + "-triple", "x86_64-apple-macosx10.7", - "-c", + "-emit-obj", "test.cpp", "-o" "test.cpp.o"}; @@ -65,7 +66,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); @@ -78,9 +79,10 @@ TEST(DependencyScanner, ScanDepsWithDiagConsumer) { // Check that a valid command line that produces no scanning jobs calls // DiagConsumer.finish(). std::vector Args = {"clang", - "-target", + "-cc1", + "-triple", "x86_64-apple-macosx10.7", - "-c", + "-emit-obj", "-x", "assembler", "test.s",