1480093f4SDimitry Andric //===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric 9a7dea167SDimitry Andric #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" 10a7dea167SDimitry Andric #include "clang/Frontend/Utils.h" 11bdd1243dSDimitry Andric #include <optional> 12a7dea167SDimitry Andric 13753f127fSDimitry Andric using namespace clang; 14753f127fSDimitry Andric using namespace tooling; 15753f127fSDimitry Andric using namespace dependencies; 16a7dea167SDimitry Andric 17480093f4SDimitry Andric DependencyScanningTool::DependencyScanningTool( 18fcaf7f86SDimitry Andric DependencyScanningService &Service, 19fcaf7f86SDimitry Andric llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) 20fcaf7f86SDimitry Andric : Worker(Service, std::move(FS)) {} 21a7dea167SDimitry Andric 221ac55f4cSDimitry Andric namespace { 23a7dea167SDimitry Andric /// Prints out all of the gathered dependencies into a string. 24480093f4SDimitry Andric class MakeDependencyPrinterConsumer : public DependencyConsumer { 25a7dea167SDimitry Andric public: 26bdd1243dSDimitry Andric void handleBuildCommand(Command) override {} 27bdd1243dSDimitry Andric 28fe6060f1SDimitry Andric void 29fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override { 30a7dea167SDimitry Andric this->Opts = std::make_unique<DependencyOutputOptions>(Opts); 31fe6060f1SDimitry Andric } 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric void handleFileDependency(StringRef File) override { 345ffd83dbSDimitry Andric Dependencies.push_back(std::string(File)); 35a7dea167SDimitry Andric } 36a7dea167SDimitry Andric 37fe6060f1SDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 38fe6060f1SDimitry Andric // Same as `handleModuleDependency`. 39fe6060f1SDimitry Andric } 40fe6060f1SDimitry Andric 41480093f4SDimitry Andric void handleModuleDependency(ModuleDeps MD) override { 42480093f4SDimitry Andric // These are ignored for the make format as it can't support the full 43480093f4SDimitry Andric // set of deps, and handleFileDependency handles enough for implicitly 44480093f4SDimitry Andric // built modules to work. 45480093f4SDimitry Andric } 46480093f4SDimitry Andric 47480093f4SDimitry Andric void handleContextHash(std::string Hash) override {} 48480093f4SDimitry Andric 49a7dea167SDimitry Andric void printDependencies(std::string &S) { 50fe6060f1SDimitry Andric assert(Opts && "Handled dependency output options."); 51a7dea167SDimitry Andric 52a7dea167SDimitry Andric class DependencyPrinter : public DependencyFileGenerator { 53a7dea167SDimitry Andric public: 54a7dea167SDimitry Andric DependencyPrinter(DependencyOutputOptions &Opts, 55a7dea167SDimitry Andric ArrayRef<std::string> Dependencies) 56a7dea167SDimitry Andric : DependencyFileGenerator(Opts) { 57a7dea167SDimitry Andric for (const auto &Dep : Dependencies) 58a7dea167SDimitry Andric addDependency(Dep); 59a7dea167SDimitry Andric } 60a7dea167SDimitry Andric 61a7dea167SDimitry Andric void printDependencies(std::string &S) { 62a7dea167SDimitry Andric llvm::raw_string_ostream OS(S); 63a7dea167SDimitry Andric outputDependencyFile(OS); 64a7dea167SDimitry Andric } 65a7dea167SDimitry Andric }; 66a7dea167SDimitry Andric 67a7dea167SDimitry Andric DependencyPrinter Generator(*Opts, Dependencies); 68a7dea167SDimitry Andric Generator.printDependencies(S); 69a7dea167SDimitry Andric } 70a7dea167SDimitry Andric 711ac55f4cSDimitry Andric protected: 72a7dea167SDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts; 73a7dea167SDimitry Andric std::vector<std::string> Dependencies; 74a7dea167SDimitry Andric }; 751ac55f4cSDimitry Andric } // anonymous namespace 76a7dea167SDimitry Andric 771ac55f4cSDimitry Andric llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 78*06c3fb27SDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD) { 795ffd83dbSDimitry Andric MakeDependencyPrinterConsumer Consumer; 80*06c3fb27SDimitry Andric CallbackActionController Controller(nullptr); 81349cc55cSDimitry Andric auto Result = 82*06c3fb27SDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, Controller); 835ffd83dbSDimitry Andric if (Result) 845ffd83dbSDimitry Andric return std::move(Result); 855ffd83dbSDimitry Andric std::string Output; 865ffd83dbSDimitry Andric Consumer.printDependencies(Output); 875ffd83dbSDimitry Andric return Output; 885ffd83dbSDimitry Andric } 895ffd83dbSDimitry Andric 901ac55f4cSDimitry Andric llvm::Expected<P1689Rule> DependencyScanningTool::getP1689ModuleDependencyFile( 91*06c3fb27SDimitry Andric const CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput, 92*06c3fb27SDimitry Andric std::string &MakeformatOutputPath) { 931ac55f4cSDimitry Andric class P1689ModuleDependencyPrinterConsumer 941ac55f4cSDimitry Andric : public MakeDependencyPrinterConsumer { 951ac55f4cSDimitry Andric public: 961ac55f4cSDimitry Andric P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule, 971ac55f4cSDimitry Andric const CompileCommand &Command) 981ac55f4cSDimitry Andric : Filename(Command.Filename), Rule(Rule) { 991ac55f4cSDimitry Andric Rule.PrimaryOutput = Command.Output; 1001ac55f4cSDimitry Andric } 1011ac55f4cSDimitry Andric 1021ac55f4cSDimitry Andric void handleProvidedAndRequiredStdCXXModules( 1031ac55f4cSDimitry Andric std::optional<P1689ModuleInfo> Provided, 1041ac55f4cSDimitry Andric std::vector<P1689ModuleInfo> Requires) override { 1051ac55f4cSDimitry Andric Rule.Provides = Provided; 1061ac55f4cSDimitry Andric if (Rule.Provides) 1071ac55f4cSDimitry Andric Rule.Provides->SourcePath = Filename.str(); 1081ac55f4cSDimitry Andric Rule.Requires = Requires; 1091ac55f4cSDimitry Andric } 1101ac55f4cSDimitry Andric 1111ac55f4cSDimitry Andric StringRef getMakeFormatDependencyOutputPath() { 1121ac55f4cSDimitry Andric if (Opts->OutputFormat != DependencyOutputFormat::Make) 1131ac55f4cSDimitry Andric return {}; 1141ac55f4cSDimitry Andric return Opts->OutputFile; 1151ac55f4cSDimitry Andric } 1161ac55f4cSDimitry Andric 1171ac55f4cSDimitry Andric private: 1181ac55f4cSDimitry Andric StringRef Filename; 1191ac55f4cSDimitry Andric P1689Rule &Rule; 1201ac55f4cSDimitry Andric }; 1211ac55f4cSDimitry Andric 122*06c3fb27SDimitry Andric class P1689ActionController : public DependencyActionController { 123*06c3fb27SDimitry Andric public: 124*06c3fb27SDimitry Andric // The lookupModuleOutput is for clang modules. P1689 format don't need it. 125*06c3fb27SDimitry Andric std::string lookupModuleOutput(const ModuleID &, 126*06c3fb27SDimitry Andric ModuleOutputKind Kind) override { 127*06c3fb27SDimitry Andric return ""; 128*06c3fb27SDimitry Andric } 129*06c3fb27SDimitry Andric }; 130*06c3fb27SDimitry Andric 1311ac55f4cSDimitry Andric P1689Rule Rule; 1321ac55f4cSDimitry Andric P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command); 133*06c3fb27SDimitry Andric P1689ActionController Controller; 134*06c3fb27SDimitry Andric auto Result = Worker.computeDependencies(CWD, Command.CommandLine, Consumer, 135*06c3fb27SDimitry Andric Controller); 1361ac55f4cSDimitry Andric if (Result) 1371ac55f4cSDimitry Andric return std::move(Result); 1381ac55f4cSDimitry Andric 1391ac55f4cSDimitry Andric MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath(); 1401ac55f4cSDimitry Andric if (!MakeformatOutputPath.empty()) 1411ac55f4cSDimitry Andric Consumer.printDependencies(MakeformatOutput); 1421ac55f4cSDimitry Andric return Rule; 1431ac55f4cSDimitry Andric } 1441ac55f4cSDimitry Andric 145*06c3fb27SDimitry Andric llvm::Expected<TranslationUnitDeps> 146*06c3fb27SDimitry Andric DependencyScanningTool::getTranslationUnitDependencies( 147349cc55cSDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD, 148349cc55cSDimitry Andric const llvm::StringSet<> &AlreadySeen, 149*06c3fb27SDimitry Andric LookupModuleOutputCallback LookupModuleOutput) { 150*06c3fb27SDimitry Andric FullDependencyConsumer Consumer(AlreadySeen); 151*06c3fb27SDimitry Andric CallbackActionController Controller(LookupModuleOutput); 152bdd1243dSDimitry Andric llvm::Error Result = 153*06c3fb27SDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, Controller); 154bdd1243dSDimitry Andric if (Result) 155bdd1243dSDimitry Andric return std::move(Result); 156*06c3fb27SDimitry Andric return Consumer.takeTranslationUnitDeps(); 157480093f4SDimitry Andric } 158480093f4SDimitry Andric 159*06c3fb27SDimitry Andric llvm::Expected<ModuleDepsGraph> DependencyScanningTool::getModuleDependencies( 160*06c3fb27SDimitry Andric StringRef ModuleName, const std::vector<std::string> &CommandLine, 161*06c3fb27SDimitry Andric StringRef CWD, const llvm::StringSet<> &AlreadySeen, 162*06c3fb27SDimitry Andric LookupModuleOutputCallback LookupModuleOutput) { 163*06c3fb27SDimitry Andric FullDependencyConsumer Consumer(AlreadySeen); 164*06c3fb27SDimitry Andric CallbackActionController Controller(LookupModuleOutput); 165*06c3fb27SDimitry Andric llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer, 166*06c3fb27SDimitry Andric Controller, ModuleName); 167bdd1243dSDimitry Andric if (Result) 168bdd1243dSDimitry Andric return std::move(Result); 169*06c3fb27SDimitry Andric return Consumer.takeModuleGraphDeps(); 170fe6060f1SDimitry Andric } 171fe6060f1SDimitry Andric 172*06c3fb27SDimitry Andric TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() { 173*06c3fb27SDimitry Andric TranslationUnitDeps TU; 17481ad6265SDimitry Andric 175*06c3fb27SDimitry Andric TU.ID.ContextHash = std::move(ContextHash); 176*06c3fb27SDimitry Andric TU.FileDeps = std::move(Dependencies); 177*06c3fb27SDimitry Andric TU.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps); 178*06c3fb27SDimitry Andric TU.Commands = std::move(Commands); 179480093f4SDimitry Andric 1805ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1815ffd83dbSDimitry Andric auto &MD = M.second; 182480093f4SDimitry Andric if (MD.ImportedByMainFile) 183*06c3fb27SDimitry Andric TU.ClangModuleDeps.push_back(MD.ID); 184bdd1243dSDimitry Andric // TODO: Avoid handleModuleDependency even being called for modules 185bdd1243dSDimitry Andric // we've already seen. 186bdd1243dSDimitry Andric if (AlreadySeen.count(M.first)) 187bdd1243dSDimitry Andric continue; 188*06c3fb27SDimitry Andric TU.ModuleGraph.push_back(std::move(MD)); 189bdd1243dSDimitry Andric } 190bdd1243dSDimitry Andric 191*06c3fb27SDimitry Andric return TU; 192bdd1243dSDimitry Andric } 193bdd1243dSDimitry Andric 194*06c3fb27SDimitry Andric ModuleDepsGraph FullDependencyConsumer::takeModuleGraphDeps() { 195*06c3fb27SDimitry Andric ModuleDepsGraph ModuleGraph; 196bdd1243dSDimitry Andric 197bdd1243dSDimitry Andric for (auto &&M : ClangModuleDeps) { 198bdd1243dSDimitry Andric auto &MD = M.second; 1995ffd83dbSDimitry Andric // TODO: Avoid handleModuleDependency even being called for modules 2005ffd83dbSDimitry Andric // we've already seen. 2015ffd83dbSDimitry Andric if (AlreadySeen.count(M.first)) 2025ffd83dbSDimitry Andric continue; 203*06c3fb27SDimitry Andric ModuleGraph.push_back(std::move(MD)); 204480093f4SDimitry Andric } 205480093f4SDimitry Andric 206*06c3fb27SDimitry Andric return ModuleGraph; 207480093f4SDimitry Andric } 208*06c3fb27SDimitry Andric 209*06c3fb27SDimitry Andric CallbackActionController::~CallbackActionController() {} 210