14ba319b5SDimitry Andric //===- CompilationDatabase.cpp --------------------------------------------===//
2dff0c46cSDimitry Andric //
3dff0c46cSDimitry Andric // The LLVM Compiler Infrastructure
4dff0c46cSDimitry Andric //
5dff0c46cSDimitry Andric // This file is distributed under the University of Illinois Open Source
6dff0c46cSDimitry Andric // License. See LICENSE.TXT for details.
7dff0c46cSDimitry Andric //
8dff0c46cSDimitry Andric //===----------------------------------------------------------------------===//
9dff0c46cSDimitry Andric //
103861d79fSDimitry Andric // This file contains implementations of the CompilationDatabase base class
113861d79fSDimitry Andric // and the FixedCompilationDatabase.
12dff0c46cSDimitry Andric //
139a199699SDimitry Andric // FIXME: Various functions that take a string &ErrorMessage should be upgraded
149a199699SDimitry Andric // to Expected.
159a199699SDimitry Andric //
16dff0c46cSDimitry Andric //===----------------------------------------------------------------------===//
17dff0c46cSDimitry Andric
18dff0c46cSDimitry Andric #include "clang/Tooling/CompilationDatabase.h"
19f785676fSDimitry Andric #include "clang/Basic/Diagnostic.h"
204ba319b5SDimitry Andric #include "clang/Basic/DiagnosticIDs.h"
2159d1ed5bSDimitry Andric #include "clang/Basic/DiagnosticOptions.h"
224ba319b5SDimitry Andric #include "clang/Basic/LLVM.h"
23f785676fSDimitry Andric #include "clang/Driver/Action.h"
2459d1ed5bSDimitry Andric #include "clang/Driver/Compilation.h"
25f785676fSDimitry Andric #include "clang/Driver/Driver.h"
26f785676fSDimitry Andric #include "clang/Driver/DriverDiagnostic.h"
27f785676fSDimitry Andric #include "clang/Driver/Job.h"
28f785676fSDimitry Andric #include "clang/Frontend/TextDiagnosticPrinter.h"
2959d1ed5bSDimitry Andric #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
3059d1ed5bSDimitry Andric #include "clang/Tooling/Tooling.h"
314ba319b5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
324ba319b5SDimitry Andric #include "llvm/ADT/IntrusiveRefCntPtr.h"
334ba319b5SDimitry Andric #include "llvm/ADT/STLExtras.h"
3459d1ed5bSDimitry Andric #include "llvm/ADT/SmallString.h"
354ba319b5SDimitry Andric #include "llvm/ADT/SmallVector.h"
364ba319b5SDimitry Andric #include "llvm/ADT/StringRef.h"
37f785676fSDimitry Andric #include "llvm/Option/Arg.h"
384ba319b5SDimitry Andric #include "llvm/Support/Casting.h"
394ba319b5SDimitry Andric #include "llvm/Support/Compiler.h"
404ba319b5SDimitry Andric #include "llvm/Support/ErrorOr.h"
4159d1ed5bSDimitry Andric #include "llvm/Support/Host.h"
429a199699SDimitry Andric #include "llvm/Support/LineIterator.h"
434ba319b5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
4459d1ed5bSDimitry Andric #include "llvm/Support/Path.h"
45302affcbSDimitry Andric #include "llvm/Support/raw_ostream.h"
464ba319b5SDimitry Andric #include <algorithm>
474ba319b5SDimitry Andric #include <cassert>
484ba319b5SDimitry Andric #include <cstring>
494ba319b5SDimitry Andric #include <iterator>
504ba319b5SDimitry Andric #include <memory>
5159d1ed5bSDimitry Andric #include <sstream>
524ba319b5SDimitry Andric #include <string>
5359d1ed5bSDimitry Andric #include <system_error>
544ba319b5SDimitry Andric #include <utility>
554ba319b5SDimitry Andric #include <vector>
564ba319b5SDimitry Andric
5733956c43SDimitry Andric using namespace clang;
5833956c43SDimitry Andric using namespace tooling;
59dff0c46cSDimitry Andric
6044290647SDimitry Andric LLVM_INSTANTIATE_REGISTRY(CompilationDatabasePluginRegistry)
6144290647SDimitry Andric
624ba319b5SDimitry Andric CompilationDatabase::~CompilationDatabase() = default;
63dff0c46cSDimitry Andric
6439d628a0SDimitry Andric std::unique_ptr<CompilationDatabase>
loadFromDirectory(StringRef BuildDirectory,std::string & ErrorMessage)65dff0c46cSDimitry Andric CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
66dff0c46cSDimitry Andric std::string &ErrorMessage) {
6744290647SDimitry Andric llvm::raw_string_ostream ErrorStream(ErrorMessage);
683861d79fSDimitry Andric for (CompilationDatabasePluginRegistry::iterator
693861d79fSDimitry Andric It = CompilationDatabasePluginRegistry::begin(),
703861d79fSDimitry Andric Ie = CompilationDatabasePluginRegistry::end();
713861d79fSDimitry Andric It != Ie; ++It) {
723861d79fSDimitry Andric std::string DatabaseErrorMessage;
7359d1ed5bSDimitry Andric std::unique_ptr<CompilationDatabasePlugin> Plugin(It->instantiate());
7439d628a0SDimitry Andric if (std::unique_ptr<CompilationDatabase> DB =
753861d79fSDimitry Andric Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
763861d79fSDimitry Andric return DB;
773861d79fSDimitry Andric ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
78dff0c46cSDimitry Andric }
7959d1ed5bSDimitry Andric return nullptr;
80dff0c46cSDimitry Andric }
81dff0c46cSDimitry Andric
8239d628a0SDimitry Andric static std::unique_ptr<CompilationDatabase>
findCompilationDatabaseFromDirectory(StringRef Directory,std::string & ErrorMessage)833861d79fSDimitry Andric findCompilationDatabaseFromDirectory(StringRef Directory,
843861d79fSDimitry Andric std::string &ErrorMessage) {
853861d79fSDimitry Andric std::stringstream ErrorStream;
863861d79fSDimitry Andric bool HasErrorMessage = false;
877ae0e2c9SDimitry Andric while (!Directory.empty()) {
887ae0e2c9SDimitry Andric std::string LoadErrorMessage;
897ae0e2c9SDimitry Andric
9039d628a0SDimitry Andric if (std::unique_ptr<CompilationDatabase> DB =
917ae0e2c9SDimitry Andric CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
927ae0e2c9SDimitry Andric return DB;
937ae0e2c9SDimitry Andric
943861d79fSDimitry Andric if (!HasErrorMessage) {
953861d79fSDimitry Andric ErrorStream << "No compilation database found in " << Directory.str()
963861d79fSDimitry Andric << " or any parent directory\n" << LoadErrorMessage;
973861d79fSDimitry Andric HasErrorMessage = true;
983861d79fSDimitry Andric }
993861d79fSDimitry Andric
1007ae0e2c9SDimitry Andric Directory = llvm::sys::path::parent_path(Directory);
1017ae0e2c9SDimitry Andric }
1023861d79fSDimitry Andric ErrorMessage = ErrorStream.str();
10359d1ed5bSDimitry Andric return nullptr;
1047ae0e2c9SDimitry Andric }
1057ae0e2c9SDimitry Andric
10639d628a0SDimitry Andric std::unique_ptr<CompilationDatabase>
autoDetectFromSource(StringRef SourceFile,std::string & ErrorMessage)1077ae0e2c9SDimitry Andric CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
1087ae0e2c9SDimitry Andric std::string &ErrorMessage) {
109139f7f9bSDimitry Andric SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
1107ae0e2c9SDimitry Andric StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
1117ae0e2c9SDimitry Andric
11239d628a0SDimitry Andric std::unique_ptr<CompilationDatabase> DB =
11339d628a0SDimitry Andric findCompilationDatabaseFromDirectory(Directory, ErrorMessage);
1147ae0e2c9SDimitry Andric
1157ae0e2c9SDimitry Andric if (!DB)
1167ae0e2c9SDimitry Andric ErrorMessage = ("Could not auto-detect compilation database for file \"" +
1173861d79fSDimitry Andric SourceFile + "\"\n" + ErrorMessage).str();
1187ae0e2c9SDimitry Andric return DB;
1197ae0e2c9SDimitry Andric }
1207ae0e2c9SDimitry Andric
12139d628a0SDimitry Andric std::unique_ptr<CompilationDatabase>
autoDetectFromDirectory(StringRef SourceDir,std::string & ErrorMessage)1227ae0e2c9SDimitry Andric CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
1237ae0e2c9SDimitry Andric std::string &ErrorMessage) {
124139f7f9bSDimitry Andric SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
1257ae0e2c9SDimitry Andric
12639d628a0SDimitry Andric std::unique_ptr<CompilationDatabase> DB =
12739d628a0SDimitry Andric findCompilationDatabaseFromDirectory(AbsolutePath, ErrorMessage);
1287ae0e2c9SDimitry Andric
1297ae0e2c9SDimitry Andric if (!DB)
1307ae0e2c9SDimitry Andric ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
1313861d79fSDimitry Andric SourceDir + "\"\n" + ErrorMessage).str();
1327ae0e2c9SDimitry Andric return DB;
1337ae0e2c9SDimitry Andric }
1347ae0e2c9SDimitry Andric
getAllCompileCommands() const1359a199699SDimitry Andric std::vector<CompileCommand> CompilationDatabase::getAllCompileCommands() const {
1369a199699SDimitry Andric std::vector<CompileCommand> Result;
1379a199699SDimitry Andric for (const auto &File : getAllFiles()) {
1389a199699SDimitry Andric auto C = getCompileCommands(File);
1399a199699SDimitry Andric std::move(C.begin(), C.end(), std::back_inserter(Result));
1409a199699SDimitry Andric }
1419a199699SDimitry Andric return Result;
1429a199699SDimitry Andric }
1439a199699SDimitry Andric
1444ba319b5SDimitry Andric CompilationDatabasePlugin::~CompilationDatabasePlugin() = default;
1453861d79fSDimitry Andric
14633956c43SDimitry Andric namespace {
1474ba319b5SDimitry Andric
148f785676fSDimitry Andric // Helper for recursively searching through a chain of actions and collecting
149f785676fSDimitry Andric // all inputs, direct and indirect, of compile jobs.
150f785676fSDimitry Andric struct CompileJobAnalyzer {
1514ba319b5SDimitry Andric SmallVector<std::string, 2> Inputs;
1524ba319b5SDimitry Andric
run__anon43bc6c080111::CompileJobAnalyzer153f785676fSDimitry Andric void run(const driver::Action *A) {
154f785676fSDimitry Andric runImpl(A, false);
155f785676fSDimitry Andric }
156f785676fSDimitry Andric
157f785676fSDimitry Andric private:
runImpl__anon43bc6c080111::CompileJobAnalyzer158f785676fSDimitry Andric void runImpl(const driver::Action *A, bool Collect) {
159f785676fSDimitry Andric bool CollectChildren = Collect;
160f785676fSDimitry Andric switch (A->getKind()) {
161f785676fSDimitry Andric case driver::Action::CompileJobClass:
162f785676fSDimitry Andric CollectChildren = true;
163f785676fSDimitry Andric break;
164f785676fSDimitry Andric
1654ba319b5SDimitry Andric case driver::Action::InputClass:
166f785676fSDimitry Andric if (Collect) {
1674ba319b5SDimitry Andric const auto *IA = cast<driver::InputAction>(A);
168f785676fSDimitry Andric Inputs.push_back(IA->getInputArg().getSpelling());
169f785676fSDimitry Andric }
1704ba319b5SDimitry Andric break;
171f785676fSDimitry Andric
172f785676fSDimitry Andric default:
173f785676fSDimitry Andric // Don't care about others
1744ba319b5SDimitry Andric break;
175f785676fSDimitry Andric }
176f785676fSDimitry Andric
177e7145dcbSDimitry Andric for (const driver::Action *AI : A->inputs())
178e7145dcbSDimitry Andric runImpl(AI, CollectChildren);
179f785676fSDimitry Andric }
180f785676fSDimitry Andric };
181f785676fSDimitry Andric
182f785676fSDimitry Andric // Special DiagnosticConsumer that looks for warn_drv_input_file_unused
183f785676fSDimitry Andric // diagnostics from the driver and collects the option strings for those unused
184f785676fSDimitry Andric // options.
185f785676fSDimitry Andric class UnusedInputDiagConsumer : public DiagnosticConsumer {
186f785676fSDimitry Andric public:
UnusedInputDiagConsumer(DiagnosticConsumer & Other)187302affcbSDimitry Andric UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {}
188f785676fSDimitry Andric
HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,const Diagnostic & Info)18933956c43SDimitry Andric void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
19059d1ed5bSDimitry Andric const Diagnostic &Info) override {
1914ba319b5SDimitry Andric if (Info.getID() == diag::warn_drv_input_file_unused) {
192f785676fSDimitry Andric // Arg 1 for this diagnostic is the option that didn't get used.
193f785676fSDimitry Andric UnusedInputs.push_back(Info.getArgStdStr(0));
194302affcbSDimitry Andric } else if (DiagLevel >= DiagnosticsEngine::Error) {
195302affcbSDimitry Andric // If driver failed to create compilation object, show the diagnostics
196302affcbSDimitry Andric // to user.
197302affcbSDimitry Andric Other.HandleDiagnostic(DiagLevel, Info);
198f785676fSDimitry Andric }
199f785676fSDimitry Andric }
200f785676fSDimitry Andric
201302affcbSDimitry Andric DiagnosticConsumer &Other;
202f785676fSDimitry Andric SmallVector<std::string, 2> UnusedInputs;
203f785676fSDimitry Andric };
204f785676fSDimitry Andric
205f785676fSDimitry Andric // Unary functor for asking "Given a StringRef S1, does there exist a string
206f785676fSDimitry Andric // S2 in Arr where S1 == S2?"
207f785676fSDimitry Andric struct MatchesAny {
MatchesAny__anon43bc6c080111::MatchesAny208f785676fSDimitry Andric MatchesAny(ArrayRef<std::string> Arr) : Arr(Arr) {}
2094ba319b5SDimitry Andric
operator ()__anon43bc6c080111::MatchesAny210f785676fSDimitry Andric bool operator() (StringRef S) {
211f785676fSDimitry Andric for (const std::string *I = Arr.begin(), *E = Arr.end(); I != E; ++I)
212f785676fSDimitry Andric if (*I == S)
213f785676fSDimitry Andric return true;
214f785676fSDimitry Andric return false;
215f785676fSDimitry Andric }
2164ba319b5SDimitry Andric
217f785676fSDimitry Andric private:
218f785676fSDimitry Andric ArrayRef<std::string> Arr;
219f785676fSDimitry Andric };
2204ba319b5SDimitry Andric
221*b5893f02SDimitry Andric // Filter of tools unused flags such as -no-integrated-as and -Wa,*.
222*b5893f02SDimitry Andric // They are not used for syntax checking, and could confuse targets
223*b5893f02SDimitry Andric // which don't support these options.
224*b5893f02SDimitry Andric struct FilterUnusedFlags {
operator ()__anon43bc6c080111::FilterUnusedFlags225*b5893f02SDimitry Andric bool operator() (StringRef S) {
226*b5893f02SDimitry Andric return (S == "-no-integrated-as") || S.startswith("-Wa,");
227*b5893f02SDimitry Andric }
228*b5893f02SDimitry Andric };
229*b5893f02SDimitry Andric
GetClangToolCommand()230*b5893f02SDimitry Andric std::string GetClangToolCommand() {
231*b5893f02SDimitry Andric static int Dummy;
232*b5893f02SDimitry Andric std::string ClangExecutable =
233*b5893f02SDimitry Andric llvm::sys::fs::getMainExecutable("clang", (void *)&Dummy);
234*b5893f02SDimitry Andric SmallString<128> ClangToolPath;
235*b5893f02SDimitry Andric ClangToolPath = llvm::sys::path::parent_path(ClangExecutable);
236*b5893f02SDimitry Andric llvm::sys::path::append(ClangToolPath, "clang-tool");
237*b5893f02SDimitry Andric return ClangToolPath.str();
238*b5893f02SDimitry Andric }
239*b5893f02SDimitry Andric
24033956c43SDimitry Andric } // namespace
241f785676fSDimitry Andric
2424ba319b5SDimitry Andric /// Strips any positional args and possible argv[0] from a command-line
243f785676fSDimitry Andric /// provided by the user to construct a FixedCompilationDatabase.
244f785676fSDimitry Andric ///
245f785676fSDimitry Andric /// FixedCompilationDatabase requires a command line to be in this format as it
246f785676fSDimitry Andric /// constructs the command line for each file by appending the name of the file
247f785676fSDimitry Andric /// to be compiled. FixedCompilationDatabase also adds its own argv[0] to the
248f785676fSDimitry Andric /// start of the command line although its value is not important as it's just
249f785676fSDimitry Andric /// ignored by the Driver invoked by the ClangTool using the
250f785676fSDimitry Andric /// FixedCompilationDatabase.
251f785676fSDimitry Andric ///
252f785676fSDimitry Andric /// FIXME: This functionality should probably be made available by
253f785676fSDimitry Andric /// clang::driver::Driver although what the interface should look like is not
254f785676fSDimitry Andric /// clear.
255f785676fSDimitry Andric ///
256f785676fSDimitry Andric /// \param[in] Args Args as provided by the user.
257f785676fSDimitry Andric /// \return Resulting stripped command line.
258f785676fSDimitry Andric /// \li true if successful.
259f785676fSDimitry Andric /// \li false if \c Args cannot be used for compilation jobs (e.g.
260f785676fSDimitry Andric /// contains an option like -E or -version).
stripPositionalArgs(std::vector<const char * > Args,std::vector<std::string> & Result,std::string & ErrorMsg)26159d1ed5bSDimitry Andric static bool stripPositionalArgs(std::vector<const char *> Args,
262302affcbSDimitry Andric std::vector<std::string> &Result,
263302affcbSDimitry Andric std::string &ErrorMsg) {
264f785676fSDimitry Andric IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
265302affcbSDimitry Andric llvm::raw_string_ostream Output(ErrorMsg);
266302affcbSDimitry Andric TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
267302affcbSDimitry Andric UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
268f785676fSDimitry Andric DiagnosticsEngine Diagnostics(
2694ba319b5SDimitry Andric IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
270f785676fSDimitry Andric &*DiagOpts, &DiagClient, false);
271f785676fSDimitry Andric
27259d1ed5bSDimitry Andric // The clang executable path isn't required since the jobs the driver builds
27359d1ed5bSDimitry Andric // will not be executed.
27459d1ed5bSDimitry Andric std::unique_ptr<driver::Driver> NewDriver(new driver::Driver(
275f785676fSDimitry Andric /* ClangExecutable= */ "", llvm::sys::getDefaultTargetTriple(),
27659d1ed5bSDimitry Andric Diagnostics));
277f785676fSDimitry Andric NewDriver->setCheckInputsExist(false);
278f785676fSDimitry Andric
279*b5893f02SDimitry Andric // This becomes the new argv[0]. The value is used to detect libc++ include
280*b5893f02SDimitry Andric // dirs on Mac, it isn't used for other platforms.
281*b5893f02SDimitry Andric std::string Argv0 = GetClangToolCommand();
282*b5893f02SDimitry Andric Args.insert(Args.begin(), Argv0.c_str());
283f785676fSDimitry Andric
284f785676fSDimitry Andric // By adding -c, we force the driver to treat compilation as the last phase.
285f785676fSDimitry Andric // It will then issue warnings via Diagnostics about un-used options that
286f785676fSDimitry Andric // would have been used for linking. If the user provided a compiler name as
287f785676fSDimitry Andric // the original argv[0], this will be treated as a linker input thanks to
288f785676fSDimitry Andric // insertng a new argv[0] above. All un-used options get collected by
289f785676fSDimitry Andric // UnusedInputdiagConsumer and get stripped out later.
290f785676fSDimitry Andric Args.push_back("-c");
291f785676fSDimitry Andric
292f785676fSDimitry Andric // Put a dummy C++ file on to ensure there's at least one compile job for the
293f785676fSDimitry Andric // driver to construct. If the user specified some other argument that
294f785676fSDimitry Andric // prevents compilation, e.g. -E or something like -version, we may still end
295f785676fSDimitry Andric // up with no jobs but then this is the user's fault.
296f785676fSDimitry Andric Args.push_back("placeholder.cpp");
297f785676fSDimitry Andric
298*b5893f02SDimitry Andric Args.erase(std::remove_if(Args.begin(), Args.end(), FilterUnusedFlags()),
29959d1ed5bSDimitry Andric Args.end());
30059d1ed5bSDimitry Andric
30159d1ed5bSDimitry Andric const std::unique_ptr<driver::Compilation> Compilation(
302f785676fSDimitry Andric NewDriver->BuildCompilation(Args));
303302affcbSDimitry Andric if (!Compilation)
304302affcbSDimitry Andric return false;
305f785676fSDimitry Andric
306f785676fSDimitry Andric const driver::JobList &Jobs = Compilation->getJobs();
307f785676fSDimitry Andric
308f785676fSDimitry Andric CompileJobAnalyzer CompileAnalyzer;
309f785676fSDimitry Andric
3103dac3a9bSDimitry Andric for (const auto &Cmd : Jobs) {
311*b5893f02SDimitry Andric // Collect only for Assemble, Backend, and Compile jobs. If we do all jobs
312*b5893f02SDimitry Andric // we get duplicates since Link jobs point to Assemble jobs as inputs.
313*b5893f02SDimitry Andric // -flto* flags make the BackendJobClass, which still needs analyzer.
314a580b014SDimitry Andric if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass ||
315*b5893f02SDimitry Andric Cmd.getSource().getKind() == driver::Action::BackendJobClass ||
316a580b014SDimitry Andric Cmd.getSource().getKind() == driver::Action::CompileJobClass) {
31739d628a0SDimitry Andric CompileAnalyzer.run(&Cmd.getSource());
318f785676fSDimitry Andric }
319a580b014SDimitry Andric }
320f785676fSDimitry Andric
321f785676fSDimitry Andric if (CompileAnalyzer.Inputs.empty()) {
322302affcbSDimitry Andric ErrorMsg = "warning: no compile jobs found\n";
323f785676fSDimitry Andric return false;
324f785676fSDimitry Andric }
325f785676fSDimitry Andric
326f785676fSDimitry Andric // Remove all compilation input files from the command line. This is
327f785676fSDimitry Andric // necessary so that getCompileCommands() can construct a command line for
328f785676fSDimitry Andric // each file.
329f785676fSDimitry Andric std::vector<const char *>::iterator End = std::remove_if(
330f785676fSDimitry Andric Args.begin(), Args.end(), MatchesAny(CompileAnalyzer.Inputs));
331f785676fSDimitry Andric
332f785676fSDimitry Andric // Remove all inputs deemed unused for compilation.
333f785676fSDimitry Andric End = std::remove_if(Args.begin(), End, MatchesAny(DiagClient.UnusedInputs));
334f785676fSDimitry Andric
335f785676fSDimitry Andric // Remove the -c add above as well. It will be at the end right now.
33659d1ed5bSDimitry Andric assert(strcmp(*(End - 1), "-c") == 0);
337f785676fSDimitry Andric --End;
338f785676fSDimitry Andric
339f785676fSDimitry Andric Result = std::vector<std::string>(Args.begin() + 1, End);
340f785676fSDimitry Andric return true;
341f785676fSDimitry Andric }
342f785676fSDimitry Andric
343302affcbSDimitry Andric std::unique_ptr<FixedCompilationDatabase>
loadFromCommandLine(int & Argc,const char * const * Argv,std::string & ErrorMsg,Twine Directory)344302affcbSDimitry Andric FixedCompilationDatabase::loadFromCommandLine(int &Argc,
345302affcbSDimitry Andric const char *const *Argv,
346302affcbSDimitry Andric std::string &ErrorMsg,
347302affcbSDimitry Andric Twine Directory) {
348302affcbSDimitry Andric ErrorMsg.clear();
349302affcbSDimitry Andric if (Argc == 0)
350302affcbSDimitry Andric return nullptr;
35133956c43SDimitry Andric const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
352cb4dff85SDimitry Andric if (DoubleDash == Argv + Argc)
35359d1ed5bSDimitry Andric return nullptr;
354f785676fSDimitry Andric std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc);
355cb4dff85SDimitry Andric Argc = DoubleDash - Argv;
356f785676fSDimitry Andric
357f785676fSDimitry Andric std::vector<std::string> StrippedArgs;
358302affcbSDimitry Andric if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg))
35959d1ed5bSDimitry Andric return nullptr;
3609a199699SDimitry Andric return llvm::make_unique<FixedCompilationDatabase>(Directory, StrippedArgs);
3619a199699SDimitry Andric }
3629a199699SDimitry Andric
3639a199699SDimitry Andric std::unique_ptr<FixedCompilationDatabase>
loadFromFile(StringRef Path,std::string & ErrorMsg)3649a199699SDimitry Andric FixedCompilationDatabase::loadFromFile(StringRef Path, std::string &ErrorMsg) {
3659a199699SDimitry Andric ErrorMsg.clear();
3669a199699SDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
3679a199699SDimitry Andric llvm::MemoryBuffer::getFile(Path);
3689a199699SDimitry Andric if (std::error_code Result = File.getError()) {
3699a199699SDimitry Andric ErrorMsg = "Error while opening fixed database: " + Result.message();
3709a199699SDimitry Andric return nullptr;
3719a199699SDimitry Andric }
3729a199699SDimitry Andric std::vector<std::string> Args{llvm::line_iterator(**File),
3739a199699SDimitry Andric llvm::line_iterator()};
3749a199699SDimitry Andric return llvm::make_unique<FixedCompilationDatabase>(
3759a199699SDimitry Andric llvm::sys::path::parent_path(Path), std::move(Args));
376cb4dff85SDimitry Andric }
377cb4dff85SDimitry Andric
378cb4dff85SDimitry Andric FixedCompilationDatabase::
FixedCompilationDatabase(Twine Directory,ArrayRef<std::string> CommandLine)379cb4dff85SDimitry Andric FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) {
380*b5893f02SDimitry Andric std::vector<std::string> ToolCommandLine(1, GetClangToolCommand());
381cb4dff85SDimitry Andric ToolCommandLine.insert(ToolCommandLine.end(),
382cb4dff85SDimitry Andric CommandLine.begin(), CommandLine.end());
3830623d748SDimitry Andric CompileCommands.emplace_back(Directory, StringRef(),
38444290647SDimitry Andric std::move(ToolCommandLine),
38544290647SDimitry Andric StringRef());
386cb4dff85SDimitry Andric }
387cb4dff85SDimitry Andric
388cb4dff85SDimitry Andric std::vector<CompileCommand>
getCompileCommands(StringRef FilePath) const389cb4dff85SDimitry Andric FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
390cb4dff85SDimitry Andric std::vector<CompileCommand> Result(CompileCommands);
391cb4dff85SDimitry Andric Result[0].CommandLine.push_back(FilePath);
3920623d748SDimitry Andric Result[0].Filename = FilePath;
393cb4dff85SDimitry Andric return Result;
394cb4dff85SDimitry Andric }
395cb4dff85SDimitry Andric
3969a199699SDimitry Andric namespace {
3977ae0e2c9SDimitry Andric
3989a199699SDimitry Andric class FixedCompilationDatabasePlugin : public CompilationDatabasePlugin {
3999a199699SDimitry Andric std::unique_ptr<CompilationDatabase>
loadFromDirectory(StringRef Directory,std::string & ErrorMessage)4009a199699SDimitry Andric loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
4019a199699SDimitry Andric SmallString<1024> DatabasePath(Directory);
4029a199699SDimitry Andric llvm::sys::path::append(DatabasePath, "compile_flags.txt");
4039a199699SDimitry Andric return FixedCompilationDatabase::loadFromFile(DatabasePath, ErrorMessage);
404139f7f9bSDimitry Andric }
4059a199699SDimitry Andric };
4069a199699SDimitry Andric
4074ba319b5SDimitry Andric } // namespace
4084ba319b5SDimitry Andric
4099a199699SDimitry Andric static CompilationDatabasePluginRegistry::Add<FixedCompilationDatabasePlugin>
4109a199699SDimitry Andric X("fixed-compilation-database", "Reads plain-text flags file");
4119a199699SDimitry Andric
41233956c43SDimitry Andric namespace clang {
41333956c43SDimitry Andric namespace tooling {
41433956c43SDimitry Andric
4153861d79fSDimitry Andric // This anchor is used to force the linker to link in the generated object file
4163861d79fSDimitry Andric // and thus register the JSONCompilationDatabasePlugin.
4173861d79fSDimitry Andric extern volatile int JSONAnchorSource;
4180623d748SDimitry Andric static int LLVM_ATTRIBUTE_UNUSED JSONAnchorDest = JSONAnchorSource;
419dff0c46cSDimitry Andric
4204ba319b5SDimitry Andric } // namespace tooling
4214ba319b5SDimitry Andric } // namespace clang
422