xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp (revision a2464ee12761660f50d0b6f59f233949ebcacc87)
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 
12 namespace clang{
13 namespace tooling{
14 namespace dependencies{
15 
16 std::vector<std::string> FullDependencies::getAdditionalArgs(
17     std::function<StringRef(ModuleID)> LookupPCMPath,
18     std::function<const ModuleDeps &(ModuleID)> LookupModuleDeps) const {
19   std::vector<std::string> Ret = getAdditionalArgsWithoutModulePaths();
20 
21   std::vector<std::string> PCMPaths;
22   std::vector<std::string> ModMapPaths;
23   dependencies::detail::collectPCMAndModuleMapPaths(
24       ClangModuleDeps, LookupPCMPath, LookupModuleDeps, PCMPaths, ModMapPaths);
25   for (const std::string &PCMPath : PCMPaths)
26     Ret.push_back("-fmodule-file=" + PCMPath);
27 
28   return Ret;
29 }
30 
31 std::vector<std::string>
32 FullDependencies::getAdditionalArgsWithoutModulePaths() const {
33   std::vector<std::string> Args{
34       "-fno-implicit-modules",
35       "-fno-implicit-module-maps",
36   };
37 
38   for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps)
39     Args.push_back("-fmodule-file=" + PMD.PCMFile);
40 
41   return Args;
42 }
43 
44 DependencyScanningTool::DependencyScanningTool(
45     DependencyScanningService &Service)
46     : Worker(Service) {}
47 
48 llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
49     const std::vector<std::string> &CommandLine, StringRef CWD,
50     llvm::Optional<StringRef> ModuleName) {
51   /// Prints out all of the gathered dependencies into a string.
52   class MakeDependencyPrinterConsumer : public DependencyConsumer {
53   public:
54     void
55     handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
56       this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
57     }
58 
59     void handleFileDependency(StringRef File) override {
60       Dependencies.push_back(std::string(File));
61     }
62 
63     void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
64       // Same as `handleModuleDependency`.
65     }
66 
67     void handleModuleDependency(ModuleDeps MD) override {
68       // These are ignored for the make format as it can't support the full
69       // set of deps, and handleFileDependency handles enough for implicitly
70       // built modules to work.
71     }
72 
73     void handleContextHash(std::string Hash) override {}
74 
75     void printDependencies(std::string &S) {
76       assert(Opts && "Handled dependency output options.");
77 
78       class DependencyPrinter : public DependencyFileGenerator {
79       public:
80         DependencyPrinter(DependencyOutputOptions &Opts,
81                           ArrayRef<std::string> Dependencies)
82             : DependencyFileGenerator(Opts) {
83           for (const auto &Dep : Dependencies)
84             addDependency(Dep);
85         }
86 
87         void printDependencies(std::string &S) {
88           llvm::raw_string_ostream OS(S);
89           outputDependencyFile(OS);
90         }
91       };
92 
93       DependencyPrinter Generator(*Opts, Dependencies);
94       Generator.printDependencies(S);
95     }
96 
97   private:
98     std::unique_ptr<DependencyOutputOptions> Opts;
99     std::vector<std::string> Dependencies;
100   };
101 
102   MakeDependencyPrinterConsumer Consumer;
103   auto Result =
104       Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
105   if (Result)
106     return std::move(Result);
107   std::string Output;
108   Consumer.printDependencies(Output);
109   return Output;
110 }
111 
112 llvm::Expected<FullDependenciesResult>
113 DependencyScanningTool::getFullDependencies(
114     const std::vector<std::string> &CommandLine, StringRef CWD,
115     const llvm::StringSet<> &AlreadySeen,
116     llvm::Optional<StringRef> ModuleName) {
117   class FullDependencyPrinterConsumer : public DependencyConsumer {
118   public:
119     FullDependencyPrinterConsumer(const llvm::StringSet<> &AlreadySeen)
120         : AlreadySeen(AlreadySeen) {}
121 
122     void
123     handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {}
124 
125     void handleFileDependency(StringRef File) override {
126       Dependencies.push_back(std::string(File));
127     }
128 
129     void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override {
130       PrebuiltModuleDeps.emplace_back(std::move(PMD));
131     }
132 
133     void handleModuleDependency(ModuleDeps MD) override {
134       ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD);
135     }
136 
137     void handleContextHash(std::string Hash) override {
138       ContextHash = std::move(Hash);
139     }
140 
141     FullDependenciesResult getFullDependencies() const {
142       FullDependencies FD;
143 
144       FD.ID.ContextHash = std::move(ContextHash);
145 
146       FD.FileDeps.assign(Dependencies.begin(), Dependencies.end());
147 
148       for (auto &&M : ClangModuleDeps) {
149         auto &MD = M.second;
150         if (MD.ImportedByMainFile)
151           FD.ClangModuleDeps.push_back(MD.ID);
152       }
153 
154       FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
155 
156       FullDependenciesResult FDR;
157 
158       for (auto &&M : ClangModuleDeps) {
159         // TODO: Avoid handleModuleDependency even being called for modules
160         //   we've already seen.
161         if (AlreadySeen.count(M.first))
162           continue;
163         FDR.DiscoveredModules.push_back(std::move(M.second));
164       }
165 
166       FDR.FullDeps = std::move(FD);
167       return FDR;
168     }
169 
170   private:
171     std::vector<std::string> Dependencies;
172     std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
173     std::map<std::string, ModuleDeps> ClangModuleDeps;
174     std::string ContextHash;
175     std::vector<std::string> OutputPaths;
176     const llvm::StringSet<> &AlreadySeen;
177   };
178 
179   FullDependencyPrinterConsumer Consumer(AlreadySeen);
180   llvm::Error Result =
181       Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
182   if (Result)
183     return std::move(Result);
184   return Consumer.getFullDependencies();
185 }
186 
187 } // end namespace dependencies
188 } // end namespace tooling
189 } // end namespace clang
190