229 lines · cpp
1//===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===//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/DependencyScanningTool.h"10#include "clang/Frontend/Utils.h"11#include <optional>12 13using namespace clang;14using namespace tooling;15using namespace dependencies;16 17DependencyScanningTool::DependencyScanningTool(18 DependencyScanningService &Service,19 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)20 : Worker(Service, std::move(FS)) {}21 22namespace {23/// Prints out all of the gathered dependencies into a string.24class MakeDependencyPrinterConsumer : public DependencyConsumer {25public:26 void handleBuildCommand(Command) override {}27 28 void29 handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {30 this->Opts = std::make_unique<DependencyOutputOptions>(Opts);31 }32 33 void handleFileDependency(StringRef File) override {34 Dependencies.push_back(std::string(File));35 }36 37 // These are ignored for the make format as it can't support the full38 // set of deps, and handleFileDependency handles enough for implicitly39 // built modules to work.40 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {}41 void handleModuleDependency(ModuleDeps MD) override {}42 void handleDirectModuleDependency(ModuleID ID) override {}43 void handleVisibleModule(std::string ModuleName) override {}44 void handleContextHash(std::string Hash) override {}45 46 void printDependencies(std::string &S) {47 assert(Opts && "Handled dependency output options.");48 49 class DependencyPrinter : public DependencyFileGenerator {50 public:51 DependencyPrinter(DependencyOutputOptions &Opts,52 ArrayRef<std::string> Dependencies)53 : DependencyFileGenerator(Opts) {54 for (const auto &Dep : Dependencies)55 addDependency(Dep);56 }57 58 void printDependencies(std::string &S) {59 llvm::raw_string_ostream OS(S);60 outputDependencyFile(OS);61 }62 };63 64 DependencyPrinter Generator(*Opts, Dependencies);65 Generator.printDependencies(S);66 }67 68protected:69 std::unique_ptr<DependencyOutputOptions> Opts;70 std::vector<std::string> Dependencies;71};72} // anonymous namespace73 74llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(75 const std::vector<std::string> &CommandLine, StringRef CWD) {76 MakeDependencyPrinterConsumer Consumer;77 CallbackActionController Controller(nullptr);78 auto Result =79 Worker.computeDependencies(CWD, CommandLine, Consumer, Controller);80 if (Result)81 return std::move(Result);82 std::string Output;83 Consumer.printDependencies(Output);84 return Output;85}86 87llvm::Expected<P1689Rule> DependencyScanningTool::getP1689ModuleDependencyFile(88 const CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput,89 std::string &MakeformatOutputPath) {90 class P1689ModuleDependencyPrinterConsumer91 : public MakeDependencyPrinterConsumer {92 public:93 P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule,94 const CompileCommand &Command)95 : Filename(Command.Filename), Rule(Rule) {96 Rule.PrimaryOutput = Command.Output;97 }98 99 void handleProvidedAndRequiredStdCXXModules(100 std::optional<P1689ModuleInfo> Provided,101 std::vector<P1689ModuleInfo> Requires) override {102 Rule.Provides = Provided;103 if (Rule.Provides)104 Rule.Provides->SourcePath = Filename.str();105 Rule.Requires = Requires;106 }107 108 StringRef getMakeFormatDependencyOutputPath() {109 if (Opts->OutputFormat != DependencyOutputFormat::Make)110 return {};111 return Opts->OutputFile;112 }113 114 private:115 StringRef Filename;116 P1689Rule &Rule;117 };118 119 class P1689ActionController : public DependencyActionController {120 public:121 // The lookupModuleOutput is for clang modules. P1689 format don't need it.122 std::string lookupModuleOutput(const ModuleDeps &,123 ModuleOutputKind Kind) override {124 return "";125 }126 };127 128 P1689Rule Rule;129 P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command);130 P1689ActionController Controller;131 auto Result = Worker.computeDependencies(CWD, Command.CommandLine, Consumer,132 Controller);133 if (Result)134 return std::move(Result);135 136 MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();137 if (!MakeformatOutputPath.empty())138 Consumer.printDependencies(MakeformatOutput);139 return Rule;140}141 142llvm::Expected<TranslationUnitDeps>143DependencyScanningTool::getTranslationUnitDependencies(144 const std::vector<std::string> &CommandLine, StringRef CWD,145 const llvm::DenseSet<ModuleID> &AlreadySeen,146 LookupModuleOutputCallback LookupModuleOutput,147 std::optional<llvm::MemoryBufferRef> TUBuffer) {148 FullDependencyConsumer Consumer(AlreadySeen);149 CallbackActionController Controller(LookupModuleOutput);150 llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer,151 Controller, TUBuffer);152 153 if (Result)154 return std::move(Result);155 return Consumer.takeTranslationUnitDeps();156}157 158llvm::Expected<TranslationUnitDeps>159DependencyScanningTool::getModuleDependencies(160 StringRef ModuleName, const std::vector<std::string> &CommandLine,161 StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen,162 LookupModuleOutputCallback LookupModuleOutput) {163 FullDependencyConsumer Consumer(AlreadySeen);164 CallbackActionController Controller(LookupModuleOutput);165 if (auto Error =166 Worker.initializeCompilerInstanceWithContextOrError(CWD, CommandLine))167 return std::move(Error);168 169 auto Result = Worker.computeDependenciesByNameWithContextOrError(170 ModuleName, Consumer, Controller);171 172 if (auto Error = Worker.finalizeCompilerInstanceWithContextOrError())173 return std::move(Error);174 175 if (Result)176 return std::move(Result);177 178 return Consumer.takeTranslationUnitDeps();179}180 181llvm::Error DependencyScanningTool::initializeCompilerInstanceWithContext(182 StringRef CWD, const std::vector<std::string> &CommandLine) {183 return Worker.initializeCompilerInstanceWithContextOrError(CWD, CommandLine);184}185 186llvm::Expected<TranslationUnitDeps>187DependencyScanningTool::computeDependenciesByNameWithContext(188 StringRef ModuleName, const llvm::DenseSet<ModuleID> &AlreadySeen,189 LookupModuleOutputCallback LookupModuleOutput) {190 FullDependencyConsumer Consumer(AlreadySeen);191 CallbackActionController Controller(LookupModuleOutput);192 llvm::Error Result = Worker.computeDependenciesByNameWithContextOrError(193 ModuleName, Consumer, Controller);194 if (Result)195 return std::move(Result);196 197 return Consumer.takeTranslationUnitDeps();198}199 200llvm::Error DependencyScanningTool::finalizeCompilerInstanceWithContext() {201 return Worker.finalizeCompilerInstanceWithContextOrError();202}203 204TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() {205 TranslationUnitDeps TU;206 207 TU.ID.ContextHash = std::move(ContextHash);208 TU.ID.ModuleName = std::move(ModuleName);209 TU.NamedModuleDeps = std::move(NamedModuleDeps);210 TU.FileDeps = std::move(Dependencies);211 TU.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);212 TU.VisibleModules = std::move(VisibleModules);213 TU.Commands = std::move(Commands);214 215 for (auto &&M : ClangModuleDeps) {216 auto &MD = M.second;217 // TODO: Avoid handleModuleDependency even being called for modules218 // we've already seen.219 if (AlreadySeen.count(M.first))220 continue;221 TU.ModuleGraph.push_back(std::move(MD));222 }223 TU.ClangModuleDeps = std::move(DirectModuleDeps);224 225 return TU;226}227 228CallbackActionController::~CallbackActionController() {}229