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 37480093f4SDimitry Andric // These are ignored for the make format as it can't support the full 38480093f4SDimitry Andric // set of deps, and handleFileDependency handles enough for implicitly 39480093f4SDimitry Andric // built modules to work. 40*5f757f3fSDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {} 41*5f757f3fSDimitry Andric void handleModuleDependency(ModuleDeps MD) override {} 42*5f757f3fSDimitry Andric void handleDirectModuleDependency(ModuleID ID) override {} 43480093f4SDimitry Andric void handleContextHash(std::string Hash) override {} 44480093f4SDimitry Andric 45a7dea167SDimitry Andric void printDependencies(std::string &S) { 46fe6060f1SDimitry Andric assert(Opts && "Handled dependency output options."); 47a7dea167SDimitry Andric 48a7dea167SDimitry Andric class DependencyPrinter : public DependencyFileGenerator { 49a7dea167SDimitry Andric public: 50a7dea167SDimitry Andric DependencyPrinter(DependencyOutputOptions &Opts, 51a7dea167SDimitry Andric ArrayRef<std::string> Dependencies) 52a7dea167SDimitry Andric : DependencyFileGenerator(Opts) { 53a7dea167SDimitry Andric for (const auto &Dep : Dependencies) 54a7dea167SDimitry Andric addDependency(Dep); 55a7dea167SDimitry Andric } 56a7dea167SDimitry Andric 57a7dea167SDimitry Andric void printDependencies(std::string &S) { 58a7dea167SDimitry Andric llvm::raw_string_ostream OS(S); 59a7dea167SDimitry Andric outputDependencyFile(OS); 60a7dea167SDimitry Andric } 61a7dea167SDimitry Andric }; 62a7dea167SDimitry Andric 63a7dea167SDimitry Andric DependencyPrinter Generator(*Opts, Dependencies); 64a7dea167SDimitry Andric Generator.printDependencies(S); 65a7dea167SDimitry Andric } 66a7dea167SDimitry Andric 671ac55f4cSDimitry Andric protected: 68a7dea167SDimitry Andric std::unique_ptr<DependencyOutputOptions> Opts; 69a7dea167SDimitry Andric std::vector<std::string> Dependencies; 70a7dea167SDimitry Andric }; 711ac55f4cSDimitry Andric } // anonymous namespace 72a7dea167SDimitry Andric 731ac55f4cSDimitry Andric llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( 7406c3fb27SDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD) { 755ffd83dbSDimitry Andric MakeDependencyPrinterConsumer Consumer; 7606c3fb27SDimitry Andric CallbackActionController Controller(nullptr); 77349cc55cSDimitry Andric auto Result = 7806c3fb27SDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, Controller); 795ffd83dbSDimitry Andric if (Result) 805ffd83dbSDimitry Andric return std::move(Result); 815ffd83dbSDimitry Andric std::string Output; 825ffd83dbSDimitry Andric Consumer.printDependencies(Output); 835ffd83dbSDimitry Andric return Output; 845ffd83dbSDimitry Andric } 855ffd83dbSDimitry Andric 861ac55f4cSDimitry Andric llvm::Expected<P1689Rule> DependencyScanningTool::getP1689ModuleDependencyFile( 8706c3fb27SDimitry Andric const CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput, 8806c3fb27SDimitry Andric std::string &MakeformatOutputPath) { 891ac55f4cSDimitry Andric class P1689ModuleDependencyPrinterConsumer 901ac55f4cSDimitry Andric : public MakeDependencyPrinterConsumer { 911ac55f4cSDimitry Andric public: 921ac55f4cSDimitry Andric P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule, 931ac55f4cSDimitry Andric const CompileCommand &Command) 941ac55f4cSDimitry Andric : Filename(Command.Filename), Rule(Rule) { 951ac55f4cSDimitry Andric Rule.PrimaryOutput = Command.Output; 961ac55f4cSDimitry Andric } 971ac55f4cSDimitry Andric 981ac55f4cSDimitry Andric void handleProvidedAndRequiredStdCXXModules( 991ac55f4cSDimitry Andric std::optional<P1689ModuleInfo> Provided, 1001ac55f4cSDimitry Andric std::vector<P1689ModuleInfo> Requires) override { 1011ac55f4cSDimitry Andric Rule.Provides = Provided; 1021ac55f4cSDimitry Andric if (Rule.Provides) 1031ac55f4cSDimitry Andric Rule.Provides->SourcePath = Filename.str(); 1041ac55f4cSDimitry Andric Rule.Requires = Requires; 1051ac55f4cSDimitry Andric } 1061ac55f4cSDimitry Andric 1071ac55f4cSDimitry Andric StringRef getMakeFormatDependencyOutputPath() { 1081ac55f4cSDimitry Andric if (Opts->OutputFormat != DependencyOutputFormat::Make) 1091ac55f4cSDimitry Andric return {}; 1101ac55f4cSDimitry Andric return Opts->OutputFile; 1111ac55f4cSDimitry Andric } 1121ac55f4cSDimitry Andric 1131ac55f4cSDimitry Andric private: 1141ac55f4cSDimitry Andric StringRef Filename; 1151ac55f4cSDimitry Andric P1689Rule &Rule; 1161ac55f4cSDimitry Andric }; 1171ac55f4cSDimitry Andric 11806c3fb27SDimitry Andric class P1689ActionController : public DependencyActionController { 11906c3fb27SDimitry Andric public: 12006c3fb27SDimitry Andric // The lookupModuleOutput is for clang modules. P1689 format don't need it. 12106c3fb27SDimitry Andric std::string lookupModuleOutput(const ModuleID &, 12206c3fb27SDimitry Andric ModuleOutputKind Kind) override { 12306c3fb27SDimitry Andric return ""; 12406c3fb27SDimitry Andric } 12506c3fb27SDimitry Andric }; 12606c3fb27SDimitry Andric 1271ac55f4cSDimitry Andric P1689Rule Rule; 1281ac55f4cSDimitry Andric P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command); 12906c3fb27SDimitry Andric P1689ActionController Controller; 13006c3fb27SDimitry Andric auto Result = Worker.computeDependencies(CWD, Command.CommandLine, Consumer, 13106c3fb27SDimitry Andric Controller); 1321ac55f4cSDimitry Andric if (Result) 1331ac55f4cSDimitry Andric return std::move(Result); 1341ac55f4cSDimitry Andric 1351ac55f4cSDimitry Andric MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath(); 1361ac55f4cSDimitry Andric if (!MakeformatOutputPath.empty()) 1371ac55f4cSDimitry Andric Consumer.printDependencies(MakeformatOutput); 1381ac55f4cSDimitry Andric return Rule; 1391ac55f4cSDimitry Andric } 1401ac55f4cSDimitry Andric 14106c3fb27SDimitry Andric llvm::Expected<TranslationUnitDeps> 14206c3fb27SDimitry Andric DependencyScanningTool::getTranslationUnitDependencies( 143349cc55cSDimitry Andric const std::vector<std::string> &CommandLine, StringRef CWD, 144*5f757f3fSDimitry Andric const llvm::DenseSet<ModuleID> &AlreadySeen, 14506c3fb27SDimitry Andric LookupModuleOutputCallback LookupModuleOutput) { 14606c3fb27SDimitry Andric FullDependencyConsumer Consumer(AlreadySeen); 14706c3fb27SDimitry Andric CallbackActionController Controller(LookupModuleOutput); 148bdd1243dSDimitry Andric llvm::Error Result = 14906c3fb27SDimitry Andric Worker.computeDependencies(CWD, CommandLine, Consumer, Controller); 150bdd1243dSDimitry Andric if (Result) 151bdd1243dSDimitry Andric return std::move(Result); 15206c3fb27SDimitry Andric return Consumer.takeTranslationUnitDeps(); 153480093f4SDimitry Andric } 154480093f4SDimitry Andric 15506c3fb27SDimitry Andric llvm::Expected<ModuleDepsGraph> DependencyScanningTool::getModuleDependencies( 15606c3fb27SDimitry Andric StringRef ModuleName, const std::vector<std::string> &CommandLine, 157*5f757f3fSDimitry Andric StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen, 15806c3fb27SDimitry Andric LookupModuleOutputCallback LookupModuleOutput) { 15906c3fb27SDimitry Andric FullDependencyConsumer Consumer(AlreadySeen); 16006c3fb27SDimitry Andric CallbackActionController Controller(LookupModuleOutput); 16106c3fb27SDimitry Andric llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer, 16206c3fb27SDimitry Andric Controller, ModuleName); 163bdd1243dSDimitry Andric if (Result) 164bdd1243dSDimitry Andric return std::move(Result); 16506c3fb27SDimitry Andric return Consumer.takeModuleGraphDeps(); 166fe6060f1SDimitry Andric } 167fe6060f1SDimitry Andric 16806c3fb27SDimitry Andric TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() { 16906c3fb27SDimitry Andric TranslationUnitDeps TU; 17081ad6265SDimitry Andric 17106c3fb27SDimitry Andric TU.ID.ContextHash = std::move(ContextHash); 17206c3fb27SDimitry Andric TU.FileDeps = std::move(Dependencies); 17306c3fb27SDimitry Andric TU.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps); 17406c3fb27SDimitry Andric TU.Commands = std::move(Commands); 175480093f4SDimitry Andric 1765ffd83dbSDimitry Andric for (auto &&M : ClangModuleDeps) { 1775ffd83dbSDimitry Andric auto &MD = M.second; 178bdd1243dSDimitry Andric // TODO: Avoid handleModuleDependency even being called for modules 179bdd1243dSDimitry Andric // we've already seen. 180bdd1243dSDimitry Andric if (AlreadySeen.count(M.first)) 181bdd1243dSDimitry Andric continue; 18206c3fb27SDimitry Andric TU.ModuleGraph.push_back(std::move(MD)); 183bdd1243dSDimitry Andric } 184*5f757f3fSDimitry Andric TU.ClangModuleDeps = std::move(DirectModuleDeps); 185bdd1243dSDimitry Andric 18606c3fb27SDimitry Andric return TU; 187bdd1243dSDimitry Andric } 188bdd1243dSDimitry Andric 18906c3fb27SDimitry Andric ModuleDepsGraph FullDependencyConsumer::takeModuleGraphDeps() { 19006c3fb27SDimitry Andric ModuleDepsGraph ModuleGraph; 191bdd1243dSDimitry Andric 192bdd1243dSDimitry Andric for (auto &&M : ClangModuleDeps) { 193bdd1243dSDimitry Andric auto &MD = M.second; 1945ffd83dbSDimitry Andric // TODO: Avoid handleModuleDependency even being called for modules 1955ffd83dbSDimitry Andric // we've already seen. 1965ffd83dbSDimitry Andric if (AlreadySeen.count(M.first)) 1975ffd83dbSDimitry Andric continue; 19806c3fb27SDimitry Andric ModuleGraph.push_back(std::move(MD)); 199480093f4SDimitry Andric } 200480093f4SDimitry Andric 20106c3fb27SDimitry Andric return ModuleGraph; 202480093f4SDimitry Andric } 20306c3fb27SDimitry Andric 20406c3fb27SDimitry Andric CallbackActionController::~CallbackActionController() {} 205