xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
10 #include "clang/Frontend/Utils.h"
11 #include <optional>
12 
13 using namespace clang;
14 using namespace tooling;
15 using namespace dependencies;
16 
DependencyScanningTool(DependencyScanningService & Service,llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)17 DependencyScanningTool::DependencyScanningTool(
18     DependencyScanningService &Service,
19     llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
20     : Worker(Service, std::move(FS)) {}
21 
22 namespace {
23 /// Prints out all of the gathered dependencies into a string.
24 class MakeDependencyPrinterConsumer : public DependencyConsumer {
25 public:
handleBuildCommand(Command)26   void handleBuildCommand(Command) override {}
27 
28   void
handleDependencyOutputOpts(const DependencyOutputOptions & Opts)29   handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
30     this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
31   }
32 
handleFileDependency(StringRef File)33   void handleFileDependency(StringRef File) override {
34     Dependencies.push_back(std::string(File));
35   }
36 
37   // These are ignored for the make format as it can't support the full
38   // set of deps, and handleFileDependency handles enough for implicitly
39   // built modules to work.
handlePrebuiltModuleDependency(PrebuiltModuleDep PMD)40   void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {}
handleModuleDependency(ModuleDeps MD)41   void handleModuleDependency(ModuleDeps MD) override {}
handleDirectModuleDependency(ModuleID ID)42   void handleDirectModuleDependency(ModuleID ID) override {}
handleVisibleModule(std::string ModuleName)43   void handleVisibleModule(std::string ModuleName) override {}
handleContextHash(std::string Hash)44   void handleContextHash(std::string Hash) override {}
45 
printDependencies(std::string & S)46   void printDependencies(std::string &S) {
47     assert(Opts && "Handled dependency output options.");
48 
49     class DependencyPrinter : public DependencyFileGenerator {
50     public:
51       DependencyPrinter(DependencyOutputOptions &Opts,
52                         ArrayRef<std::string> Dependencies)
53           : DependencyFileGenerator(Opts) {
54         for (const auto &Dep : Dependencies)
55           addDependency(Dep);
56       }
57 
58       void printDependencies(std::string &S) {
59         llvm::raw_string_ostream OS(S);
60         outputDependencyFile(OS);
61       }
62     };
63 
64     DependencyPrinter Generator(*Opts, Dependencies);
65     Generator.printDependencies(S);
66   }
67 
68 protected:
69   std::unique_ptr<DependencyOutputOptions> Opts;
70   std::vector<std::string> Dependencies;
71 };
72 } // anonymous namespace
73 
getDependencyFile(const std::vector<std::string> & CommandLine,StringRef CWD)74 llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
75     const std::vector<std::string> &CommandLine, StringRef CWD) {
76   MakeDependencyPrinterConsumer Consumer;
77   CallbackActionController Controller(nullptr);
78   auto Result =
79       Worker.computeDependencies(CWD, CommandLine, Consumer, Controller);
80   if (Result)
81     return std::move(Result);
82   std::string Output;
83   Consumer.printDependencies(Output);
84   return Output;
85 }
86 
getP1689ModuleDependencyFile(const CompileCommand & Command,StringRef CWD,std::string & MakeformatOutput,std::string & MakeformatOutputPath)87 llvm::Expected<P1689Rule> DependencyScanningTool::getP1689ModuleDependencyFile(
88     const CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput,
89     std::string &MakeformatOutputPath) {
90   class P1689ModuleDependencyPrinterConsumer
91       : public MakeDependencyPrinterConsumer {
92   public:
93     P1689ModuleDependencyPrinterConsumer(P1689Rule &Rule,
94                                          const CompileCommand &Command)
95         : Filename(Command.Filename), Rule(Rule) {
96       Rule.PrimaryOutput = Command.Output;
97     }
98 
99     void handleProvidedAndRequiredStdCXXModules(
100         std::optional<P1689ModuleInfo> Provided,
101         std::vector<P1689ModuleInfo> Requires) override {
102       Rule.Provides = Provided;
103       if (Rule.Provides)
104         Rule.Provides->SourcePath = Filename.str();
105       Rule.Requires = Requires;
106     }
107 
108     StringRef getMakeFormatDependencyOutputPath() {
109       if (Opts->OutputFormat != DependencyOutputFormat::Make)
110         return {};
111       return Opts->OutputFile;
112     }
113 
114   private:
115     StringRef Filename;
116     P1689Rule &Rule;
117   };
118 
119   class P1689ActionController : public DependencyActionController {
120   public:
121     // The lookupModuleOutput is for clang modules. P1689 format don't need it.
122     std::string lookupModuleOutput(const ModuleDeps &,
123                                    ModuleOutputKind Kind) override {
124       return "";
125     }
126   };
127 
128   P1689Rule Rule;
129   P1689ModuleDependencyPrinterConsumer Consumer(Rule, Command);
130   P1689ActionController Controller;
131   auto Result = Worker.computeDependencies(CWD, Command.CommandLine, Consumer,
132                                            Controller);
133   if (Result)
134     return std::move(Result);
135 
136   MakeformatOutputPath = Consumer.getMakeFormatDependencyOutputPath();
137   if (!MakeformatOutputPath.empty())
138     Consumer.printDependencies(MakeformatOutput);
139   return Rule;
140 }
141 
142 llvm::Expected<TranslationUnitDeps>
getTranslationUnitDependencies(const std::vector<std::string> & CommandLine,StringRef CWD,const llvm::DenseSet<ModuleID> & AlreadySeen,LookupModuleOutputCallback LookupModuleOutput,std::optional<llvm::MemoryBufferRef> TUBuffer)143 DependencyScanningTool::getTranslationUnitDependencies(
144     const std::vector<std::string> &CommandLine, StringRef CWD,
145     const llvm::DenseSet<ModuleID> &AlreadySeen,
146     LookupModuleOutputCallback LookupModuleOutput,
147     std::optional<llvm::MemoryBufferRef> TUBuffer) {
148   FullDependencyConsumer Consumer(AlreadySeen);
149   CallbackActionController Controller(LookupModuleOutput);
150   llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer,
151                                                   Controller, TUBuffer);
152 
153   if (Result)
154     return std::move(Result);
155   return Consumer.takeTranslationUnitDeps();
156 }
157 
158 llvm::Expected<TranslationUnitDeps>
getModuleDependencies(StringRef ModuleName,const std::vector<std::string> & CommandLine,StringRef CWD,const llvm::DenseSet<ModuleID> & AlreadySeen,LookupModuleOutputCallback LookupModuleOutput)159 DependencyScanningTool::getModuleDependencies(
160     StringRef ModuleName, const std::vector<std::string> &CommandLine,
161     StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen,
162     LookupModuleOutputCallback LookupModuleOutput) {
163   FullDependencyConsumer Consumer(AlreadySeen);
164   CallbackActionController Controller(LookupModuleOutput);
165   llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer,
166                                                   Controller, ModuleName);
167   if (Result)
168     return std::move(Result);
169   return Consumer.takeTranslationUnitDeps();
170 }
171 
takeTranslationUnitDeps()172 TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() {
173   TranslationUnitDeps TU;
174 
175   TU.ID.ContextHash = std::move(ContextHash);
176   TU.ID.ModuleName = std::move(ModuleName);
177   TU.NamedModuleDeps = std::move(NamedModuleDeps);
178   TU.FileDeps = std::move(Dependencies);
179   TU.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
180   TU.VisibleModules = std::move(VisibleModules);
181   TU.Commands = std::move(Commands);
182 
183   for (auto &&M : ClangModuleDeps) {
184     auto &MD = M.second;
185     // TODO: Avoid handleModuleDependency even being called for modules
186     //   we've already seen.
187     if (AlreadySeen.count(M.first))
188       continue;
189     TU.ModuleGraph.push_back(std::move(MD));
190   }
191   TU.ClangModuleDeps = std::move(DirectModuleDeps);
192 
193   return TU;
194 }
195 
~CallbackActionController()196 CallbackActionController::~CallbackActionController() {}
197