xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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