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
DependencyScanningTool(DependencyScanningService & Service,llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)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:
handleBuildCommand(Command)26bdd1243dSDimitry Andric void handleBuildCommand(Command) override {}
27bdd1243dSDimitry Andric
28fe6060f1SDimitry Andric void
handleDependencyOutputOpts(const DependencyOutputOptions & Opts)29fe6060f1SDimitry Andric handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
30a7dea167SDimitry Andric this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
31fe6060f1SDimitry Andric }
32fe6060f1SDimitry Andric
handleFileDependency(StringRef File)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.
handlePrebuiltModuleDependency(PrebuiltModuleDep PMD)40*5f757f3fSDimitry Andric void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {}
handleModuleDependency(ModuleDeps MD)41*5f757f3fSDimitry Andric void handleModuleDependency(ModuleDeps MD) override {}
handleDirectModuleDependency(ModuleID ID)42*5f757f3fSDimitry Andric void handleDirectModuleDependency(ModuleID ID) override {}
handleContextHash(std::string Hash)43480093f4SDimitry Andric void handleContextHash(std::string Hash) override {}
44480093f4SDimitry Andric
printDependencies(std::string & S)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
getDependencyFile(const std::vector<std::string> & CommandLine,StringRef CWD)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
getP1689ModuleDependencyFile(const CompileCommand & Command,StringRef CWD,std::string & MakeformatOutput,std::string & MakeformatOutputPath)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>
getTranslationUnitDependencies(const std::vector<std::string> & CommandLine,StringRef CWD,const llvm::DenseSet<ModuleID> & AlreadySeen,LookupModuleOutputCallback LookupModuleOutput)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
getModuleDependencies(StringRef ModuleName,const std::vector<std::string> & CommandLine,StringRef CWD,const llvm::DenseSet<ModuleID> & AlreadySeen,LookupModuleOutputCallback LookupModuleOutput)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
takeTranslationUnitDeps()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
takeModuleGraphDeps()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
~CallbackActionController()20406c3fb27SDimitry Andric CallbackActionController::~CallbackActionController() {}
205