brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.2 KiB · 0bc17f9 Raw
211 lines · cpp
1//===- DependencyScanningWorker.cpp - clang-scan-deps worker --------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"10#include "DependencyScannerImpl.h"11#include "clang/Basic/DiagnosticFrontend.h"12#include "clang/Driver/Driver.h"13#include "clang/Driver/Tool.h"14 15using namespace clang;16using namespace tooling;17using namespace dependencies;18 19DependencyScanningWorker::DependencyScanningWorker(20    DependencyScanningService &Service,21    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)22    : Service(Service) {23  PCHContainerOps = std::make_shared<PCHContainerOperations>();24  // We need to read object files from PCH built outside the scanner.25  PCHContainerOps->registerReader(26      std::make_unique<ObjectFilePCHContainerReader>());27  // The scanner itself writes only raw ast files.28  PCHContainerOps->registerWriter(std::make_unique<RawPCHContainerWriter>());29 30  if (Service.shouldTraceVFS())31    FS = llvm::makeIntrusiveRefCnt<llvm::vfs::TracingFileSystem>(std::move(FS));32 33  switch (Service.getMode()) {34  case ScanningMode::DependencyDirectivesScan:35    DepFS = llvm::makeIntrusiveRefCnt<DependencyScanningWorkerFilesystem>(36        Service.getSharedCache(), FS);37    BaseFS = DepFS;38    break;39  case ScanningMode::CanonicalPreprocessing:40    DepFS = nullptr;41    BaseFS = FS;42    break;43  }44}45 46DependencyScanningWorker::~DependencyScanningWorker() = default;47DependencyActionController::~DependencyActionController() = default;48 49llvm::Error DependencyScanningWorker::computeDependencies(50    StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,51    DependencyConsumer &Consumer, DependencyActionController &Controller,52    std::optional<llvm::MemoryBufferRef> TUBuffer) {53  // Capture the emitted diagnostics and report them to the client54  // in the case of a failure.55  TextDiagnosticsPrinterWithOutput DiagPrinterWithOS(CommandLine);56 57  if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller,58                          DiagPrinterWithOS.DiagPrinter, TUBuffer))59    return llvm::Error::success();60  return llvm::make_error<llvm::StringError>(61      DiagPrinterWithOS.DiagnosticsOS.str(), llvm::inconvertibleErrorCode());62}63 64static bool forEachDriverJob(65    ArrayRef<std::string> ArgStrs, DiagnosticsEngine &Diags,66    IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,67    llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {68  // Compilation holds a non-owning a reference to the Driver, hence we need to69  // keep the Driver alive when we use Compilation. Arguments to commands may be70  // owned by Alloc when expanded from response files.71  llvm::BumpPtrAllocator Alloc;72  auto [Driver, Compilation] = buildCompilation(ArgStrs, Diags, FS, Alloc);73  if (!Compilation)74    return false;75  for (const driver::Command &Job : Compilation->getJobs()) {76    if (!Callback(Job))77      return false;78  }79  return true;80}81 82static bool createAndRunToolInvocation(83    const std::vector<std::string> &CommandLine,84    DependencyScanningAction &Action,85    IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,86    std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps,87    DiagnosticsEngine &Diags, DependencyConsumer &Consumer) {88  auto Invocation = createCompilerInvocation(CommandLine, Diags);89  if (!Invocation)90    return false;91 92  if (!Action.runInvocation(std::move(Invocation), std::move(FS),93                            PCHContainerOps, Diags.getClient()))94    return false;95 96  std::vector<std::string> Args = Action.takeLastCC1Arguments();97  Consumer.handleBuildCommand({CommandLine[0], std::move(Args)});98  return true;99}100 101bool DependencyScanningWorker::scanDependencies(102    StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,103    DependencyConsumer &Consumer, DependencyActionController &Controller,104    DiagnosticConsumer &DC,105    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) {106  DignosticsEngineWithDiagOpts DiagEngineWithCmdAndOpts(CommandLine, FS, DC);107  DependencyScanningAction Action(Service, WorkingDirectory, Consumer,108                                  Controller, DepFS);109 110  bool Success = false;111  if (CommandLine[1] == "-cc1") {112    Success = createAndRunToolInvocation(113        CommandLine, Action, FS, PCHContainerOps,114        *DiagEngineWithCmdAndOpts.DiagEngine, Consumer);115  } else {116    Success = forEachDriverJob(117        CommandLine, *DiagEngineWithCmdAndOpts.DiagEngine, FS,118        [&](const driver::Command &Cmd) {119          if (StringRef(Cmd.getCreator().getName()) != "clang") {120            // Non-clang command. Just pass through to the dependency121            // consumer.122            Consumer.handleBuildCommand(123                {Cmd.getExecutable(),124                 {Cmd.getArguments().begin(), Cmd.getArguments().end()}});125            return true;126          }127 128          // Insert -cc1 comand line options into Argv129          std::vector<std::string> Argv;130          Argv.push_back(Cmd.getExecutable());131          llvm::append_range(Argv, Cmd.getArguments());132 133          // Create an invocation that uses the underlying file134          // system to ensure that any file system requests that135          // are made by the driver do not go through the136          // dependency scanning filesystem.137          return createAndRunToolInvocation(138              std::move(Argv), Action, FS, PCHContainerOps,139              *DiagEngineWithCmdAndOpts.DiagEngine, Consumer);140        });141  }142 143  if (Success && !Action.hasScanned())144    DiagEngineWithCmdAndOpts.DiagEngine->Report(145        diag::err_fe_expected_compiler_job)146        << llvm::join(CommandLine, " ");147 148  // Ensure finish() is called even if we never reached ExecuteAction().149  if (!Action.hasDiagConsumerFinished())150    DC.finish();151 152  return Success && Action.hasScanned();153}154 155bool DependencyScanningWorker::computeDependencies(156    StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,157    DependencyConsumer &Consumer, DependencyActionController &Controller,158    DiagnosticConsumer &DC, std::optional<llvm::MemoryBufferRef> TUBuffer) {159  if (TUBuffer) {160    auto [FinalFS, FinalCommandLine] = initVFSForTUBufferScanning(161        BaseFS, CommandLine, WorkingDirectory, *TUBuffer);162    return scanDependencies(WorkingDirectory, FinalCommandLine, Consumer,163                            Controller, DC, FinalFS);164  } else {165    BaseFS->setCurrentWorkingDirectory(WorkingDirectory);166    return scanDependencies(WorkingDirectory, CommandLine, Consumer, Controller,167                            DC, BaseFS);168  }169}170 171llvm::Error172DependencyScanningWorker::initializeCompilerInstanceWithContextOrError(173    StringRef CWD, const std::vector<std::string> &CommandLine) {174  bool Success = initializeCompilerInstanceWithContext(CWD, CommandLine);175  return CIWithContext->handleReturnStatus(Success);176}177 178llvm::Error179DependencyScanningWorker::computeDependenciesByNameWithContextOrError(180    StringRef ModuleName, DependencyConsumer &Consumer,181    DependencyActionController &Controller) {182  bool Success =183      computeDependenciesByNameWithContext(ModuleName, Consumer, Controller);184  return CIWithContext->handleReturnStatus(Success);185}186 187llvm::Error188DependencyScanningWorker::finalizeCompilerInstanceWithContextOrError() {189  bool Success = finalizeCompilerInstance();190  return CIWithContext->handleReturnStatus(Success);191}192 193bool DependencyScanningWorker::initializeCompilerInstanceWithContext(194    StringRef CWD, const std::vector<std::string> &CommandLine,195    DiagnosticConsumer *DC) {196  CIWithContext =197      std::make_unique<CompilerInstanceWithContext>(*this, CWD, CommandLine);198  return CIWithContext->initialize(DC);199}200 201bool DependencyScanningWorker::computeDependenciesByNameWithContext(202    StringRef ModuleName, DependencyConsumer &Consumer,203    DependencyActionController &Controller) {204  assert(CIWithContext && "CompilerInstance with context required!");205  return CIWithContext->computeDependencies(ModuleName, Consumer, Controller);206}207 208bool DependencyScanningWorker::finalizeCompilerInstance() {209  return CIWithContext->finalize();210}211