annotate clang/lib/Tooling/CompilationDatabase.cpp @ 176:de4ac79aef9d

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 17:13:11 +0900
parents 0572611fdcc8
children 2e18cbf3894f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- CompilationDatabase.cpp --------------------------------------------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // This file contains implementations of the CompilationDatabase base class
anatofuz
parents:
diff changeset
10 // and the FixedCompilationDatabase.
anatofuz
parents:
diff changeset
11 //
anatofuz
parents:
diff changeset
12 // FIXME: Various functions that take a string &ErrorMessage should be upgraded
anatofuz
parents:
diff changeset
13 // to Expected.
anatofuz
parents:
diff changeset
14 //
anatofuz
parents:
diff changeset
15 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
16
anatofuz
parents:
diff changeset
17 #include "clang/Tooling/CompilationDatabase.h"
anatofuz
parents:
diff changeset
18 #include "clang/Basic/Diagnostic.h"
anatofuz
parents:
diff changeset
19 #include "clang/Basic/DiagnosticIDs.h"
anatofuz
parents:
diff changeset
20 #include "clang/Basic/DiagnosticOptions.h"
anatofuz
parents:
diff changeset
21 #include "clang/Basic/LLVM.h"
anatofuz
parents:
diff changeset
22 #include "clang/Driver/Action.h"
anatofuz
parents:
diff changeset
23 #include "clang/Driver/Compilation.h"
anatofuz
parents:
diff changeset
24 #include "clang/Driver/Driver.h"
anatofuz
parents:
diff changeset
25 #include "clang/Driver/DriverDiagnostic.h"
anatofuz
parents:
diff changeset
26 #include "clang/Driver/Job.h"
anatofuz
parents:
diff changeset
27 #include "clang/Frontend/TextDiagnosticPrinter.h"
anatofuz
parents:
diff changeset
28 #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
anatofuz
parents:
diff changeset
29 #include "clang/Tooling/Tooling.h"
anatofuz
parents:
diff changeset
30 #include "llvm/ADT/ArrayRef.h"
anatofuz
parents:
diff changeset
31 #include "llvm/ADT/IntrusiveRefCntPtr.h"
anatofuz
parents:
diff changeset
32 #include "llvm/ADT/STLExtras.h"
anatofuz
parents:
diff changeset
33 #include "llvm/ADT/SmallString.h"
anatofuz
parents:
diff changeset
34 #include "llvm/ADT/SmallVector.h"
anatofuz
parents:
diff changeset
35 #include "llvm/ADT/StringRef.h"
anatofuz
parents:
diff changeset
36 #include "llvm/Option/Arg.h"
anatofuz
parents:
diff changeset
37 #include "llvm/Support/Casting.h"
anatofuz
parents:
diff changeset
38 #include "llvm/Support/Compiler.h"
anatofuz
parents:
diff changeset
39 #include "llvm/Support/ErrorOr.h"
anatofuz
parents:
diff changeset
40 #include "llvm/Support/Host.h"
anatofuz
parents:
diff changeset
41 #include "llvm/Support/LineIterator.h"
anatofuz
parents:
diff changeset
42 #include "llvm/Support/MemoryBuffer.h"
anatofuz
parents:
diff changeset
43 #include "llvm/Support/Path.h"
anatofuz
parents:
diff changeset
44 #include "llvm/Support/raw_ostream.h"
anatofuz
parents:
diff changeset
45 #include <algorithm>
anatofuz
parents:
diff changeset
46 #include <cassert>
anatofuz
parents:
diff changeset
47 #include <cstring>
anatofuz
parents:
diff changeset
48 #include <iterator>
anatofuz
parents:
diff changeset
49 #include <memory>
anatofuz
parents:
diff changeset
50 #include <sstream>
anatofuz
parents:
diff changeset
51 #include <string>
anatofuz
parents:
diff changeset
52 #include <system_error>
anatofuz
parents:
diff changeset
53 #include <utility>
anatofuz
parents:
diff changeset
54 #include <vector>
anatofuz
parents:
diff changeset
55
anatofuz
parents:
diff changeset
56 using namespace clang;
anatofuz
parents:
diff changeset
57 using namespace tooling;
anatofuz
parents:
diff changeset
58
anatofuz
parents:
diff changeset
59 LLVM_INSTANTIATE_REGISTRY(CompilationDatabasePluginRegistry)
anatofuz
parents:
diff changeset
60
anatofuz
parents:
diff changeset
61 CompilationDatabase::~CompilationDatabase() = default;
anatofuz
parents:
diff changeset
62
anatofuz
parents:
diff changeset
63 std::unique_ptr<CompilationDatabase>
anatofuz
parents:
diff changeset
64 CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
anatofuz
parents:
diff changeset
65 std::string &ErrorMessage) {
anatofuz
parents:
diff changeset
66 llvm::raw_string_ostream ErrorStream(ErrorMessage);
anatofuz
parents:
diff changeset
67 for (CompilationDatabasePluginRegistry::iterator
anatofuz
parents:
diff changeset
68 It = CompilationDatabasePluginRegistry::begin(),
anatofuz
parents:
diff changeset
69 Ie = CompilationDatabasePluginRegistry::end();
anatofuz
parents:
diff changeset
70 It != Ie; ++It) {
anatofuz
parents:
diff changeset
71 std::string DatabaseErrorMessage;
anatofuz
parents:
diff changeset
72 std::unique_ptr<CompilationDatabasePlugin> Plugin(It->instantiate());
anatofuz
parents:
diff changeset
73 if (std::unique_ptr<CompilationDatabase> DB =
anatofuz
parents:
diff changeset
74 Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
anatofuz
parents:
diff changeset
75 return DB;
anatofuz
parents:
diff changeset
76 ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
anatofuz
parents:
diff changeset
77 }
anatofuz
parents:
diff changeset
78 return nullptr;
anatofuz
parents:
diff changeset
79 }
anatofuz
parents:
diff changeset
80
anatofuz
parents:
diff changeset
81 static std::unique_ptr<CompilationDatabase>
anatofuz
parents:
diff changeset
82 findCompilationDatabaseFromDirectory(StringRef Directory,
anatofuz
parents:
diff changeset
83 std::string &ErrorMessage) {
anatofuz
parents:
diff changeset
84 std::stringstream ErrorStream;
anatofuz
parents:
diff changeset
85 bool HasErrorMessage = false;
anatofuz
parents:
diff changeset
86 while (!Directory.empty()) {
anatofuz
parents:
diff changeset
87 std::string LoadErrorMessage;
anatofuz
parents:
diff changeset
88
anatofuz
parents:
diff changeset
89 if (std::unique_ptr<CompilationDatabase> DB =
anatofuz
parents:
diff changeset
90 CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
anatofuz
parents:
diff changeset
91 return DB;
anatofuz
parents:
diff changeset
92
anatofuz
parents:
diff changeset
93 if (!HasErrorMessage) {
anatofuz
parents:
diff changeset
94 ErrorStream << "No compilation database found in " << Directory.str()
anatofuz
parents:
diff changeset
95 << " or any parent directory\n" << LoadErrorMessage;
anatofuz
parents:
diff changeset
96 HasErrorMessage = true;
anatofuz
parents:
diff changeset
97 }
anatofuz
parents:
diff changeset
98
anatofuz
parents:
diff changeset
99 Directory = llvm::sys::path::parent_path(Directory);
anatofuz
parents:
diff changeset
100 }
anatofuz
parents:
diff changeset
101 ErrorMessage = ErrorStream.str();
anatofuz
parents:
diff changeset
102 return nullptr;
anatofuz
parents:
diff changeset
103 }
anatofuz
parents:
diff changeset
104
anatofuz
parents:
diff changeset
105 std::unique_ptr<CompilationDatabase>
anatofuz
parents:
diff changeset
106 CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
anatofuz
parents:
diff changeset
107 std::string &ErrorMessage) {
anatofuz
parents:
diff changeset
108 SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
anatofuz
parents:
diff changeset
109 StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
anatofuz
parents:
diff changeset
110
anatofuz
parents:
diff changeset
111 std::unique_ptr<CompilationDatabase> DB =
anatofuz
parents:
diff changeset
112 findCompilationDatabaseFromDirectory(Directory, ErrorMessage);
anatofuz
parents:
diff changeset
113
anatofuz
parents:
diff changeset
114 if (!DB)
anatofuz
parents:
diff changeset
115 ErrorMessage = ("Could not auto-detect compilation database for file \"" +
anatofuz
parents:
diff changeset
116 SourceFile + "\"\n" + ErrorMessage).str();
anatofuz
parents:
diff changeset
117 return DB;
anatofuz
parents:
diff changeset
118 }
anatofuz
parents:
diff changeset
119
anatofuz
parents:
diff changeset
120 std::unique_ptr<CompilationDatabase>
anatofuz
parents:
diff changeset
121 CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
anatofuz
parents:
diff changeset
122 std::string &ErrorMessage) {
anatofuz
parents:
diff changeset
123 SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
anatofuz
parents:
diff changeset
124
anatofuz
parents:
diff changeset
125 std::unique_ptr<CompilationDatabase> DB =
anatofuz
parents:
diff changeset
126 findCompilationDatabaseFromDirectory(AbsolutePath, ErrorMessage);
anatofuz
parents:
diff changeset
127
anatofuz
parents:
diff changeset
128 if (!DB)
anatofuz
parents:
diff changeset
129 ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
anatofuz
parents:
diff changeset
130 SourceDir + "\"\n" + ErrorMessage).str();
anatofuz
parents:
diff changeset
131 return DB;
anatofuz
parents:
diff changeset
132 }
anatofuz
parents:
diff changeset
133
anatofuz
parents:
diff changeset
134 std::vector<CompileCommand> CompilationDatabase::getAllCompileCommands() const {
anatofuz
parents:
diff changeset
135 std::vector<CompileCommand> Result;
anatofuz
parents:
diff changeset
136 for (const auto &File : getAllFiles()) {
anatofuz
parents:
diff changeset
137 auto C = getCompileCommands(File);
anatofuz
parents:
diff changeset
138 std::move(C.begin(), C.end(), std::back_inserter(Result));
anatofuz
parents:
diff changeset
139 }
anatofuz
parents:
diff changeset
140 return Result;
anatofuz
parents:
diff changeset
141 }
anatofuz
parents:
diff changeset
142
anatofuz
parents:
diff changeset
143 CompilationDatabasePlugin::~CompilationDatabasePlugin() = default;
anatofuz
parents:
diff changeset
144
anatofuz
parents:
diff changeset
145 namespace {
anatofuz
parents:
diff changeset
146
anatofuz
parents:
diff changeset
147 // Helper for recursively searching through a chain of actions and collecting
anatofuz
parents:
diff changeset
148 // all inputs, direct and indirect, of compile jobs.
anatofuz
parents:
diff changeset
149 struct CompileJobAnalyzer {
anatofuz
parents:
diff changeset
150 SmallVector<std::string, 2> Inputs;
anatofuz
parents:
diff changeset
151
anatofuz
parents:
diff changeset
152 void run(const driver::Action *A) {
anatofuz
parents:
diff changeset
153 runImpl(A, false);
anatofuz
parents:
diff changeset
154 }
anatofuz
parents:
diff changeset
155
anatofuz
parents:
diff changeset
156 private:
anatofuz
parents:
diff changeset
157 void runImpl(const driver::Action *A, bool Collect) {
anatofuz
parents:
diff changeset
158 bool CollectChildren = Collect;
anatofuz
parents:
diff changeset
159 switch (A->getKind()) {
anatofuz
parents:
diff changeset
160 case driver::Action::CompileJobClass:
anatofuz
parents:
diff changeset
161 CollectChildren = true;
anatofuz
parents:
diff changeset
162 break;
anatofuz
parents:
diff changeset
163
anatofuz
parents:
diff changeset
164 case driver::Action::InputClass:
anatofuz
parents:
diff changeset
165 if (Collect) {
anatofuz
parents:
diff changeset
166 const auto *IA = cast<driver::InputAction>(A);
anatofuz
parents:
diff changeset
167 Inputs.push_back(std::string(IA->getInputArg().getSpelling()));
anatofuz
parents:
diff changeset
168 }
anatofuz
parents:
diff changeset
169 break;
anatofuz
parents:
diff changeset
170
anatofuz
parents:
diff changeset
171 default:
anatofuz
parents:
diff changeset
172 // Don't care about others
anatofuz
parents:
diff changeset
173 break;
anatofuz
parents:
diff changeset
174 }
anatofuz
parents:
diff changeset
175
anatofuz
parents:
diff changeset
176 for (const driver::Action *AI : A->inputs())
anatofuz
parents:
diff changeset
177 runImpl(AI, CollectChildren);
anatofuz
parents:
diff changeset
178 }
anatofuz
parents:
diff changeset
179 };
anatofuz
parents:
diff changeset
180
anatofuz
parents:
diff changeset
181 // Special DiagnosticConsumer that looks for warn_drv_input_file_unused
anatofuz
parents:
diff changeset
182 // diagnostics from the driver and collects the option strings for those unused
anatofuz
parents:
diff changeset
183 // options.
anatofuz
parents:
diff changeset
184 class UnusedInputDiagConsumer : public DiagnosticConsumer {
anatofuz
parents:
diff changeset
185 public:
anatofuz
parents:
diff changeset
186 UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {}
anatofuz
parents:
diff changeset
187
anatofuz
parents:
diff changeset
188 void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
anatofuz
parents:
diff changeset
189 const Diagnostic &Info) override {
anatofuz
parents:
diff changeset
190 if (Info.getID() == diag::warn_drv_input_file_unused) {
anatofuz
parents:
diff changeset
191 // Arg 1 for this diagnostic is the option that didn't get used.
anatofuz
parents:
diff changeset
192 UnusedInputs.push_back(Info.getArgStdStr(0));
anatofuz
parents:
diff changeset
193 } else if (DiagLevel >= DiagnosticsEngine::Error) {
anatofuz
parents:
diff changeset
194 // If driver failed to create compilation object, show the diagnostics
anatofuz
parents:
diff changeset
195 // to user.
anatofuz
parents:
diff changeset
196 Other.HandleDiagnostic(DiagLevel, Info);
anatofuz
parents:
diff changeset
197 }
anatofuz
parents:
diff changeset
198 }
anatofuz
parents:
diff changeset
199
anatofuz
parents:
diff changeset
200 DiagnosticConsumer &Other;
anatofuz
parents:
diff changeset
201 SmallVector<std::string, 2> UnusedInputs;
anatofuz
parents:
diff changeset
202 };
anatofuz
parents:
diff changeset
203
anatofuz
parents:
diff changeset
204 // Unary functor for asking "Given a StringRef S1, does there exist a string
anatofuz
parents:
diff changeset
205 // S2 in Arr where S1 == S2?"
anatofuz
parents:
diff changeset
206 struct MatchesAny {
anatofuz
parents:
diff changeset
207 MatchesAny(ArrayRef<std::string> Arr) : Arr(Arr) {}
anatofuz
parents:
diff changeset
208
anatofuz
parents:
diff changeset
209 bool operator() (StringRef S) {
anatofuz
parents:
diff changeset
210 for (const std::string *I = Arr.begin(), *E = Arr.end(); I != E; ++I)
anatofuz
parents:
diff changeset
211 if (*I == S)
anatofuz
parents:
diff changeset
212 return true;
anatofuz
parents:
diff changeset
213 return false;
anatofuz
parents:
diff changeset
214 }
anatofuz
parents:
diff changeset
215
anatofuz
parents:
diff changeset
216 private:
anatofuz
parents:
diff changeset
217 ArrayRef<std::string> Arr;
anatofuz
parents:
diff changeset
218 };
anatofuz
parents:
diff changeset
219
anatofuz
parents:
diff changeset
220 // Filter of tools unused flags such as -no-integrated-as and -Wa,*.
anatofuz
parents:
diff changeset
221 // They are not used for syntax checking, and could confuse targets
anatofuz
parents:
diff changeset
222 // which don't support these options.
anatofuz
parents:
diff changeset
223 struct FilterUnusedFlags {
anatofuz
parents:
diff changeset
224 bool operator() (StringRef S) {
anatofuz
parents:
diff changeset
225 return (S == "-no-integrated-as") || S.startswith("-Wa,");
anatofuz
parents:
diff changeset
226 }
anatofuz
parents:
diff changeset
227 };
anatofuz
parents:
diff changeset
228
anatofuz
parents:
diff changeset
229 std::string GetClangToolCommand() {
anatofuz
parents:
diff changeset
230 static int Dummy;
anatofuz
parents:
diff changeset
231 std::string ClangExecutable =
anatofuz
parents:
diff changeset
232 llvm::sys::fs::getMainExecutable("clang", (void *)&Dummy);
anatofuz
parents:
diff changeset
233 SmallString<128> ClangToolPath;
anatofuz
parents:
diff changeset
234 ClangToolPath = llvm::sys::path::parent_path(ClangExecutable);
anatofuz
parents:
diff changeset
235 llvm::sys::path::append(ClangToolPath, "clang-tool");
anatofuz
parents:
diff changeset
236 return std::string(ClangToolPath.str());
anatofuz
parents:
diff changeset
237 }
anatofuz
parents:
diff changeset
238
anatofuz
parents:
diff changeset
239 } // namespace
anatofuz
parents:
diff changeset
240
anatofuz
parents:
diff changeset
241 /// Strips any positional args and possible argv[0] from a command-line
anatofuz
parents:
diff changeset
242 /// provided by the user to construct a FixedCompilationDatabase.
anatofuz
parents:
diff changeset
243 ///
anatofuz
parents:
diff changeset
244 /// FixedCompilationDatabase requires a command line to be in this format as it
anatofuz
parents:
diff changeset
245 /// constructs the command line for each file by appending the name of the file
anatofuz
parents:
diff changeset
246 /// to be compiled. FixedCompilationDatabase also adds its own argv[0] to the
anatofuz
parents:
diff changeset
247 /// start of the command line although its value is not important as it's just
anatofuz
parents:
diff changeset
248 /// ignored by the Driver invoked by the ClangTool using the
anatofuz
parents:
diff changeset
249 /// FixedCompilationDatabase.
anatofuz
parents:
diff changeset
250 ///
anatofuz
parents:
diff changeset
251 /// FIXME: This functionality should probably be made available by
anatofuz
parents:
diff changeset
252 /// clang::driver::Driver although what the interface should look like is not
anatofuz
parents:
diff changeset
253 /// clear.
anatofuz
parents:
diff changeset
254 ///
anatofuz
parents:
diff changeset
255 /// \param[in] Args Args as provided by the user.
anatofuz
parents:
diff changeset
256 /// \return Resulting stripped command line.
anatofuz
parents:
diff changeset
257 /// \li true if successful.
anatofuz
parents:
diff changeset
258 /// \li false if \c Args cannot be used for compilation jobs (e.g.
anatofuz
parents:
diff changeset
259 /// contains an option like -E or -version).
anatofuz
parents:
diff changeset
260 static bool stripPositionalArgs(std::vector<const char *> Args,
anatofuz
parents:
diff changeset
261 std::vector<std::string> &Result,
anatofuz
parents:
diff changeset
262 std::string &ErrorMsg) {
anatofuz
parents:
diff changeset
263 IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
anatofuz
parents:
diff changeset
264 llvm::raw_string_ostream Output(ErrorMsg);
anatofuz
parents:
diff changeset
265 TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
anatofuz
parents:
diff changeset
266 UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
anatofuz
parents:
diff changeset
267 DiagnosticsEngine Diagnostics(
anatofuz
parents:
diff changeset
268 IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
anatofuz
parents:
diff changeset
269 &*DiagOpts, &DiagClient, false);
anatofuz
parents:
diff changeset
270
anatofuz
parents:
diff changeset
271 // The clang executable path isn't required since the jobs the driver builds
anatofuz
parents:
diff changeset
272 // will not be executed.
anatofuz
parents:
diff changeset
273 std::unique_ptr<driver::Driver> NewDriver(new driver::Driver(
anatofuz
parents:
diff changeset
274 /* ClangExecutable= */ "", llvm::sys::getDefaultTargetTriple(),
anatofuz
parents:
diff changeset
275 Diagnostics));
anatofuz
parents:
diff changeset
276 NewDriver->setCheckInputsExist(false);
anatofuz
parents:
diff changeset
277
anatofuz
parents:
diff changeset
278 // This becomes the new argv[0]. The value is used to detect libc++ include
anatofuz
parents:
diff changeset
279 // dirs on Mac, it isn't used for other platforms.
anatofuz
parents:
diff changeset
280 std::string Argv0 = GetClangToolCommand();
anatofuz
parents:
diff changeset
281 Args.insert(Args.begin(), Argv0.c_str());
anatofuz
parents:
diff changeset
282
anatofuz
parents:
diff changeset
283 // By adding -c, we force the driver to treat compilation as the last phase.
anatofuz
parents:
diff changeset
284 // It will then issue warnings via Diagnostics about un-used options that
anatofuz
parents:
diff changeset
285 // would have been used for linking. If the user provided a compiler name as
anatofuz
parents:
diff changeset
286 // the original argv[0], this will be treated as a linker input thanks to
anatofuz
parents:
diff changeset
287 // insertng a new argv[0] above. All un-used options get collected by
anatofuz
parents:
diff changeset
288 // UnusedInputdiagConsumer and get stripped out later.
anatofuz
parents:
diff changeset
289 Args.push_back("-c");
anatofuz
parents:
diff changeset
290
anatofuz
parents:
diff changeset
291 // Put a dummy C++ file on to ensure there's at least one compile job for the
anatofuz
parents:
diff changeset
292 // driver to construct. If the user specified some other argument that
anatofuz
parents:
diff changeset
293 // prevents compilation, e.g. -E or something like -version, we may still end
anatofuz
parents:
diff changeset
294 // up with no jobs but then this is the user's fault.
anatofuz
parents:
diff changeset
295 Args.push_back("placeholder.cpp");
anatofuz
parents:
diff changeset
296
anatofuz
parents:
diff changeset
297 Args.erase(std::remove_if(Args.begin(), Args.end(), FilterUnusedFlags()),
anatofuz
parents:
diff changeset
298 Args.end());
anatofuz
parents:
diff changeset
299
anatofuz
parents:
diff changeset
300 const std::unique_ptr<driver::Compilation> Compilation(
anatofuz
parents:
diff changeset
301 NewDriver->BuildCompilation(Args));
anatofuz
parents:
diff changeset
302 if (!Compilation)
anatofuz
parents:
diff changeset
303 return false;
anatofuz
parents:
diff changeset
304
anatofuz
parents:
diff changeset
305 const driver::JobList &Jobs = Compilation->getJobs();
anatofuz
parents:
diff changeset
306
anatofuz
parents:
diff changeset
307 CompileJobAnalyzer CompileAnalyzer;
anatofuz
parents:
diff changeset
308
anatofuz
parents:
diff changeset
309 for (const auto &Cmd : Jobs) {
anatofuz
parents:
diff changeset
310 // Collect only for Assemble, Backend, and Compile jobs. If we do all jobs
anatofuz
parents:
diff changeset
311 // we get duplicates since Link jobs point to Assemble jobs as inputs.
anatofuz
parents:
diff changeset
312 // -flto* flags make the BackendJobClass, which still needs analyzer.
anatofuz
parents:
diff changeset
313 if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass ||
anatofuz
parents:
diff changeset
314 Cmd.getSource().getKind() == driver::Action::BackendJobClass ||
anatofuz
parents:
diff changeset
315 Cmd.getSource().getKind() == driver::Action::CompileJobClass) {
anatofuz
parents:
diff changeset
316 CompileAnalyzer.run(&Cmd.getSource());
anatofuz
parents:
diff changeset
317 }
anatofuz
parents:
diff changeset
318 }
anatofuz
parents:
diff changeset
319
anatofuz
parents:
diff changeset
320 if (CompileAnalyzer.Inputs.empty()) {
anatofuz
parents:
diff changeset
321 ErrorMsg = "warning: no compile jobs found\n";
anatofuz
parents:
diff changeset
322 return false;
anatofuz
parents:
diff changeset
323 }
anatofuz
parents:
diff changeset
324
anatofuz
parents:
diff changeset
325 // Remove all compilation input files from the command line. This is
anatofuz
parents:
diff changeset
326 // necessary so that getCompileCommands() can construct a command line for
anatofuz
parents:
diff changeset
327 // each file.
anatofuz
parents:
diff changeset
328 std::vector<const char *>::iterator End = std::remove_if(
anatofuz
parents:
diff changeset
329 Args.begin(), Args.end(), MatchesAny(CompileAnalyzer.Inputs));
anatofuz
parents:
diff changeset
330
anatofuz
parents:
diff changeset
331 // Remove all inputs deemed unused for compilation.
anatofuz
parents:
diff changeset
332 End = std::remove_if(Args.begin(), End, MatchesAny(DiagClient.UnusedInputs));
anatofuz
parents:
diff changeset
333
anatofuz
parents:
diff changeset
334 // Remove the -c add above as well. It will be at the end right now.
anatofuz
parents:
diff changeset
335 assert(strcmp(*(End - 1), "-c") == 0);
anatofuz
parents:
diff changeset
336 --End;
anatofuz
parents:
diff changeset
337
anatofuz
parents:
diff changeset
338 Result = std::vector<std::string>(Args.begin() + 1, End);
anatofuz
parents:
diff changeset
339 return true;
anatofuz
parents:
diff changeset
340 }
anatofuz
parents:
diff changeset
341
anatofuz
parents:
diff changeset
342 std::unique_ptr<FixedCompilationDatabase>
anatofuz
parents:
diff changeset
343 FixedCompilationDatabase::loadFromCommandLine(int &Argc,
anatofuz
parents:
diff changeset
344 const char *const *Argv,
anatofuz
parents:
diff changeset
345 std::string &ErrorMsg,
anatofuz
parents:
diff changeset
346 Twine Directory) {
anatofuz
parents:
diff changeset
347 ErrorMsg.clear();
anatofuz
parents:
diff changeset
348 if (Argc == 0)
anatofuz
parents:
diff changeset
349 return nullptr;
anatofuz
parents:
diff changeset
350 const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
anatofuz
parents:
diff changeset
351 if (DoubleDash == Argv + Argc)
anatofuz
parents:
diff changeset
352 return nullptr;
anatofuz
parents:
diff changeset
353 std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc);
anatofuz
parents:
diff changeset
354 Argc = DoubleDash - Argv;
anatofuz
parents:
diff changeset
355
anatofuz
parents:
diff changeset
356 std::vector<std::string> StrippedArgs;
anatofuz
parents:
diff changeset
357 if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg))
anatofuz
parents:
diff changeset
358 return nullptr;
anatofuz
parents:
diff changeset
359 return std::make_unique<FixedCompilationDatabase>(Directory, StrippedArgs);
anatofuz
parents:
diff changeset
360 }
anatofuz
parents:
diff changeset
361
anatofuz
parents:
diff changeset
362 std::unique_ptr<FixedCompilationDatabase>
anatofuz
parents:
diff changeset
363 FixedCompilationDatabase::loadFromFile(StringRef Path, std::string &ErrorMsg) {
anatofuz
parents:
diff changeset
364 ErrorMsg.clear();
anatofuz
parents:
diff changeset
365 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
anatofuz
parents:
diff changeset
366 llvm::MemoryBuffer::getFile(Path);
anatofuz
parents:
diff changeset
367 if (std::error_code Result = File.getError()) {
anatofuz
parents:
diff changeset
368 ErrorMsg = "Error while opening fixed database: " + Result.message();
anatofuz
parents:
diff changeset
369 return nullptr;
anatofuz
parents:
diff changeset
370 }
173
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
371 std::vector<std::string> Args;
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
372 for (llvm::StringRef Line :
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
373 llvm::make_range(llvm::line_iterator(**File), llvm::line_iterator())) {
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
374 // Stray whitespace is almost certainly unintended.
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
375 Line = Line.trim();
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
376 if (!Line.empty())
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
377 Args.push_back(Line.str());
0572611fdcc8 reorgnization done
Shinji KONO <kono@ie.u-ryukyu.ac.jp>
parents: 150
diff changeset
378 }
150
anatofuz
parents:
diff changeset
379 return std::make_unique<FixedCompilationDatabase>(
anatofuz
parents:
diff changeset
380 llvm::sys::path::parent_path(Path), std::move(Args));
anatofuz
parents:
diff changeset
381 }
anatofuz
parents:
diff changeset
382
anatofuz
parents:
diff changeset
383 FixedCompilationDatabase::
anatofuz
parents:
diff changeset
384 FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) {
anatofuz
parents:
diff changeset
385 std::vector<std::string> ToolCommandLine(1, GetClangToolCommand());
anatofuz
parents:
diff changeset
386 ToolCommandLine.insert(ToolCommandLine.end(),
anatofuz
parents:
diff changeset
387 CommandLine.begin(), CommandLine.end());
anatofuz
parents:
diff changeset
388 CompileCommands.emplace_back(Directory, StringRef(),
anatofuz
parents:
diff changeset
389 std::move(ToolCommandLine),
anatofuz
parents:
diff changeset
390 StringRef());
anatofuz
parents:
diff changeset
391 }
anatofuz
parents:
diff changeset
392
anatofuz
parents:
diff changeset
393 std::vector<CompileCommand>
anatofuz
parents:
diff changeset
394 FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
anatofuz
parents:
diff changeset
395 std::vector<CompileCommand> Result(CompileCommands);
anatofuz
parents:
diff changeset
396 Result[0].CommandLine.push_back(std::string(FilePath));
anatofuz
parents:
diff changeset
397 Result[0].Filename = std::string(FilePath);
anatofuz
parents:
diff changeset
398 return Result;
anatofuz
parents:
diff changeset
399 }
anatofuz
parents:
diff changeset
400
anatofuz
parents:
diff changeset
401 namespace {
anatofuz
parents:
diff changeset
402
anatofuz
parents:
diff changeset
403 class FixedCompilationDatabasePlugin : public CompilationDatabasePlugin {
anatofuz
parents:
diff changeset
404 std::unique_ptr<CompilationDatabase>
anatofuz
parents:
diff changeset
405 loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
anatofuz
parents:
diff changeset
406 SmallString<1024> DatabasePath(Directory);
anatofuz
parents:
diff changeset
407 llvm::sys::path::append(DatabasePath, "compile_flags.txt");
anatofuz
parents:
diff changeset
408 return FixedCompilationDatabase::loadFromFile(DatabasePath, ErrorMessage);
anatofuz
parents:
diff changeset
409 }
anatofuz
parents:
diff changeset
410 };
anatofuz
parents:
diff changeset
411
anatofuz
parents:
diff changeset
412 } // namespace
anatofuz
parents:
diff changeset
413
anatofuz
parents:
diff changeset
414 static CompilationDatabasePluginRegistry::Add<FixedCompilationDatabasePlugin>
anatofuz
parents:
diff changeset
415 X("fixed-compilation-database", "Reads plain-text flags file");
anatofuz
parents:
diff changeset
416
anatofuz
parents:
diff changeset
417 namespace clang {
anatofuz
parents:
diff changeset
418 namespace tooling {
anatofuz
parents:
diff changeset
419
anatofuz
parents:
diff changeset
420 // This anchor is used to force the linker to link in the generated object file
anatofuz
parents:
diff changeset
421 // and thus register the JSONCompilationDatabasePlugin.
anatofuz
parents:
diff changeset
422 extern volatile int JSONAnchorSource;
anatofuz
parents:
diff changeset
423 static int LLVM_ATTRIBUTE_UNUSED JSONAnchorDest = JSONAnchorSource;
anatofuz
parents:
diff changeset
424
anatofuz
parents:
diff changeset
425 } // namespace tooling
anatofuz
parents:
diff changeset
426 } // namespace clang