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