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