17330f729Sjoerg //===- CompilationDatabase.cpp --------------------------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file contains implementations of the CompilationDatabase base class
107330f729Sjoerg // and the FixedCompilationDatabase.
117330f729Sjoerg //
127330f729Sjoerg // FIXME: Various functions that take a string &ErrorMessage should be upgraded
137330f729Sjoerg // to Expected.
147330f729Sjoerg //
157330f729Sjoerg //===----------------------------------------------------------------------===//
167330f729Sjoerg
177330f729Sjoerg #include "clang/Tooling/CompilationDatabase.h"
187330f729Sjoerg #include "clang/Basic/Diagnostic.h"
197330f729Sjoerg #include "clang/Basic/DiagnosticIDs.h"
207330f729Sjoerg #include "clang/Basic/DiagnosticOptions.h"
217330f729Sjoerg #include "clang/Basic/LLVM.h"
227330f729Sjoerg #include "clang/Driver/Action.h"
237330f729Sjoerg #include "clang/Driver/Compilation.h"
247330f729Sjoerg #include "clang/Driver/Driver.h"
257330f729Sjoerg #include "clang/Driver/DriverDiagnostic.h"
267330f729Sjoerg #include "clang/Driver/Job.h"
277330f729Sjoerg #include "clang/Frontend/TextDiagnosticPrinter.h"
287330f729Sjoerg #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
297330f729Sjoerg #include "clang/Tooling/Tooling.h"
307330f729Sjoerg #include "llvm/ADT/ArrayRef.h"
317330f729Sjoerg #include "llvm/ADT/IntrusiveRefCntPtr.h"
327330f729Sjoerg #include "llvm/ADT/STLExtras.h"
337330f729Sjoerg #include "llvm/ADT/SmallString.h"
347330f729Sjoerg #include "llvm/ADT/SmallVector.h"
357330f729Sjoerg #include "llvm/ADT/StringRef.h"
367330f729Sjoerg #include "llvm/Option/Arg.h"
377330f729Sjoerg #include "llvm/Support/Casting.h"
387330f729Sjoerg #include "llvm/Support/Compiler.h"
397330f729Sjoerg #include "llvm/Support/ErrorOr.h"
407330f729Sjoerg #include "llvm/Support/Host.h"
417330f729Sjoerg #include "llvm/Support/LineIterator.h"
427330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
437330f729Sjoerg #include "llvm/Support/Path.h"
447330f729Sjoerg #include "llvm/Support/raw_ostream.h"
457330f729Sjoerg #include <algorithm>
467330f729Sjoerg #include <cassert>
477330f729Sjoerg #include <cstring>
487330f729Sjoerg #include <iterator>
497330f729Sjoerg #include <memory>
507330f729Sjoerg #include <sstream>
517330f729Sjoerg #include <string>
527330f729Sjoerg #include <system_error>
537330f729Sjoerg #include <utility>
547330f729Sjoerg #include <vector>
557330f729Sjoerg
567330f729Sjoerg using namespace clang;
577330f729Sjoerg using namespace tooling;
587330f729Sjoerg
597330f729Sjoerg LLVM_INSTANTIATE_REGISTRY(CompilationDatabasePluginRegistry)
607330f729Sjoerg
617330f729Sjoerg CompilationDatabase::~CompilationDatabase() = default;
627330f729Sjoerg
637330f729Sjoerg std::unique_ptr<CompilationDatabase>
loadFromDirectory(StringRef BuildDirectory,std::string & ErrorMessage)647330f729Sjoerg CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
657330f729Sjoerg std::string &ErrorMessage) {
667330f729Sjoerg llvm::raw_string_ostream ErrorStream(ErrorMessage);
67*e038c9c4Sjoerg for (const CompilationDatabasePluginRegistry::entry &Database :
68*e038c9c4Sjoerg CompilationDatabasePluginRegistry::entries()) {
697330f729Sjoerg std::string DatabaseErrorMessage;
70*e038c9c4Sjoerg std::unique_ptr<CompilationDatabasePlugin> Plugin(Database.instantiate());
717330f729Sjoerg if (std::unique_ptr<CompilationDatabase> DB =
727330f729Sjoerg Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
737330f729Sjoerg return DB;
74*e038c9c4Sjoerg ErrorStream << Database.getName() << ": " << DatabaseErrorMessage << "\n";
757330f729Sjoerg }
767330f729Sjoerg return nullptr;
777330f729Sjoerg }
787330f729Sjoerg
797330f729Sjoerg static std::unique_ptr<CompilationDatabase>
findCompilationDatabaseFromDirectory(StringRef Directory,std::string & ErrorMessage)807330f729Sjoerg findCompilationDatabaseFromDirectory(StringRef Directory,
817330f729Sjoerg std::string &ErrorMessage) {
827330f729Sjoerg std::stringstream ErrorStream;
837330f729Sjoerg bool HasErrorMessage = false;
847330f729Sjoerg while (!Directory.empty()) {
857330f729Sjoerg std::string LoadErrorMessage;
867330f729Sjoerg
877330f729Sjoerg if (std::unique_ptr<CompilationDatabase> DB =
887330f729Sjoerg CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
897330f729Sjoerg return DB;
907330f729Sjoerg
917330f729Sjoerg if (!HasErrorMessage) {
927330f729Sjoerg ErrorStream << "No compilation database found in " << Directory.str()
937330f729Sjoerg << " or any parent directory\n" << LoadErrorMessage;
947330f729Sjoerg HasErrorMessage = true;
957330f729Sjoerg }
967330f729Sjoerg
977330f729Sjoerg Directory = llvm::sys::path::parent_path(Directory);
987330f729Sjoerg }
997330f729Sjoerg ErrorMessage = ErrorStream.str();
1007330f729Sjoerg return nullptr;
1017330f729Sjoerg }
1027330f729Sjoerg
1037330f729Sjoerg std::unique_ptr<CompilationDatabase>
autoDetectFromSource(StringRef SourceFile,std::string & ErrorMessage)1047330f729Sjoerg CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
1057330f729Sjoerg std::string &ErrorMessage) {
1067330f729Sjoerg SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
1077330f729Sjoerg StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
1087330f729Sjoerg
1097330f729Sjoerg std::unique_ptr<CompilationDatabase> DB =
1107330f729Sjoerg findCompilationDatabaseFromDirectory(Directory, ErrorMessage);
1117330f729Sjoerg
1127330f729Sjoerg if (!DB)
1137330f729Sjoerg ErrorMessage = ("Could not auto-detect compilation database for file \"" +
1147330f729Sjoerg SourceFile + "\"\n" + ErrorMessage).str();
1157330f729Sjoerg return DB;
1167330f729Sjoerg }
1177330f729Sjoerg
1187330f729Sjoerg std::unique_ptr<CompilationDatabase>
autoDetectFromDirectory(StringRef SourceDir,std::string & ErrorMessage)1197330f729Sjoerg CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
1207330f729Sjoerg std::string &ErrorMessage) {
1217330f729Sjoerg SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
1227330f729Sjoerg
1237330f729Sjoerg std::unique_ptr<CompilationDatabase> DB =
1247330f729Sjoerg findCompilationDatabaseFromDirectory(AbsolutePath, ErrorMessage);
1257330f729Sjoerg
1267330f729Sjoerg if (!DB)
1277330f729Sjoerg ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
1287330f729Sjoerg SourceDir + "\"\n" + ErrorMessage).str();
1297330f729Sjoerg return DB;
1307330f729Sjoerg }
1317330f729Sjoerg
getAllCompileCommands() const1327330f729Sjoerg std::vector<CompileCommand> CompilationDatabase::getAllCompileCommands() const {
1337330f729Sjoerg std::vector<CompileCommand> Result;
1347330f729Sjoerg for (const auto &File : getAllFiles()) {
1357330f729Sjoerg auto C = getCompileCommands(File);
1367330f729Sjoerg std::move(C.begin(), C.end(), std::back_inserter(Result));
1377330f729Sjoerg }
1387330f729Sjoerg return Result;
1397330f729Sjoerg }
1407330f729Sjoerg
1417330f729Sjoerg CompilationDatabasePlugin::~CompilationDatabasePlugin() = default;
1427330f729Sjoerg
1437330f729Sjoerg namespace {
1447330f729Sjoerg
1457330f729Sjoerg // Helper for recursively searching through a chain of actions and collecting
1467330f729Sjoerg // all inputs, direct and indirect, of compile jobs.
1477330f729Sjoerg struct CompileJobAnalyzer {
1487330f729Sjoerg SmallVector<std::string, 2> Inputs;
1497330f729Sjoerg
run__anon3b6be8040111::CompileJobAnalyzer1507330f729Sjoerg void run(const driver::Action *A) {
1517330f729Sjoerg runImpl(A, false);
1527330f729Sjoerg }
1537330f729Sjoerg
1547330f729Sjoerg private:
runImpl__anon3b6be8040111::CompileJobAnalyzer1557330f729Sjoerg void runImpl(const driver::Action *A, bool Collect) {
1567330f729Sjoerg bool CollectChildren = Collect;
1577330f729Sjoerg switch (A->getKind()) {
1587330f729Sjoerg case driver::Action::CompileJobClass:
1597330f729Sjoerg CollectChildren = true;
1607330f729Sjoerg break;
1617330f729Sjoerg
1627330f729Sjoerg case driver::Action::InputClass:
1637330f729Sjoerg if (Collect) {
1647330f729Sjoerg const auto *IA = cast<driver::InputAction>(A);
165*e038c9c4Sjoerg Inputs.push_back(std::string(IA->getInputArg().getSpelling()));
1667330f729Sjoerg }
1677330f729Sjoerg break;
1687330f729Sjoerg
1697330f729Sjoerg default:
1707330f729Sjoerg // Don't care about others
1717330f729Sjoerg break;
1727330f729Sjoerg }
1737330f729Sjoerg
1747330f729Sjoerg for (const driver::Action *AI : A->inputs())
1757330f729Sjoerg runImpl(AI, CollectChildren);
1767330f729Sjoerg }
1777330f729Sjoerg };
1787330f729Sjoerg
1797330f729Sjoerg // Special DiagnosticConsumer that looks for warn_drv_input_file_unused
1807330f729Sjoerg // diagnostics from the driver and collects the option strings for those unused
1817330f729Sjoerg // options.
1827330f729Sjoerg class UnusedInputDiagConsumer : public DiagnosticConsumer {
1837330f729Sjoerg public:
UnusedInputDiagConsumer(DiagnosticConsumer & Other)1847330f729Sjoerg UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {}
1857330f729Sjoerg
HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,const Diagnostic & Info)1867330f729Sjoerg void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
1877330f729Sjoerg const Diagnostic &Info) override {
1887330f729Sjoerg if (Info.getID() == diag::warn_drv_input_file_unused) {
1897330f729Sjoerg // Arg 1 for this diagnostic is the option that didn't get used.
1907330f729Sjoerg UnusedInputs.push_back(Info.getArgStdStr(0));
1917330f729Sjoerg } else if (DiagLevel >= DiagnosticsEngine::Error) {
1927330f729Sjoerg // If driver failed to create compilation object, show the diagnostics
1937330f729Sjoerg // to user.
1947330f729Sjoerg Other.HandleDiagnostic(DiagLevel, Info);
1957330f729Sjoerg }
1967330f729Sjoerg }
1977330f729Sjoerg
1987330f729Sjoerg DiagnosticConsumer &Other;
1997330f729Sjoerg SmallVector<std::string, 2> UnusedInputs;
2007330f729Sjoerg };
2017330f729Sjoerg
2027330f729Sjoerg // Filter of tools unused flags such as -no-integrated-as and -Wa,*.
2037330f729Sjoerg // They are not used for syntax checking, and could confuse targets
2047330f729Sjoerg // which don't support these options.
2057330f729Sjoerg struct FilterUnusedFlags {
operator ()__anon3b6be8040111::FilterUnusedFlags2067330f729Sjoerg bool operator() (StringRef S) {
2077330f729Sjoerg return (S == "-no-integrated-as") || S.startswith("-Wa,");
2087330f729Sjoerg }
2097330f729Sjoerg };
2107330f729Sjoerg
GetClangToolCommand()2117330f729Sjoerg std::string GetClangToolCommand() {
2127330f729Sjoerg static int Dummy;
2137330f729Sjoerg std::string ClangExecutable =
2147330f729Sjoerg llvm::sys::fs::getMainExecutable("clang", (void *)&Dummy);
2157330f729Sjoerg SmallString<128> ClangToolPath;
2167330f729Sjoerg ClangToolPath = llvm::sys::path::parent_path(ClangExecutable);
2177330f729Sjoerg llvm::sys::path::append(ClangToolPath, "clang-tool");
218*e038c9c4Sjoerg return std::string(ClangToolPath.str());
2197330f729Sjoerg }
2207330f729Sjoerg
2217330f729Sjoerg } // namespace
2227330f729Sjoerg
2237330f729Sjoerg /// Strips any positional args and possible argv[0] from a command-line
2247330f729Sjoerg /// provided by the user to construct a FixedCompilationDatabase.
2257330f729Sjoerg ///
2267330f729Sjoerg /// FixedCompilationDatabase requires a command line to be in this format as it
2277330f729Sjoerg /// constructs the command line for each file by appending the name of the file
2287330f729Sjoerg /// to be compiled. FixedCompilationDatabase also adds its own argv[0] to the
2297330f729Sjoerg /// start of the command line although its value is not important as it's just
2307330f729Sjoerg /// ignored by the Driver invoked by the ClangTool using the
2317330f729Sjoerg /// FixedCompilationDatabase.
2327330f729Sjoerg ///
2337330f729Sjoerg /// FIXME: This functionality should probably be made available by
2347330f729Sjoerg /// clang::driver::Driver although what the interface should look like is not
2357330f729Sjoerg /// clear.
2367330f729Sjoerg ///
2377330f729Sjoerg /// \param[in] Args Args as provided by the user.
2387330f729Sjoerg /// \return Resulting stripped command line.
2397330f729Sjoerg /// \li true if successful.
2407330f729Sjoerg /// \li false if \c Args cannot be used for compilation jobs (e.g.
2417330f729Sjoerg /// contains an option like -E or -version).
stripPositionalArgs(std::vector<const char * > Args,std::vector<std::string> & Result,std::string & ErrorMsg)2427330f729Sjoerg static bool stripPositionalArgs(std::vector<const char *> Args,
2437330f729Sjoerg std::vector<std::string> &Result,
2447330f729Sjoerg std::string &ErrorMsg) {
2457330f729Sjoerg IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
2467330f729Sjoerg llvm::raw_string_ostream Output(ErrorMsg);
2477330f729Sjoerg TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
2487330f729Sjoerg UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
2497330f729Sjoerg DiagnosticsEngine Diagnostics(
2507330f729Sjoerg IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
2517330f729Sjoerg &*DiagOpts, &DiagClient, false);
2527330f729Sjoerg
2537330f729Sjoerg // The clang executable path isn't required since the jobs the driver builds
2547330f729Sjoerg // will not be executed.
2557330f729Sjoerg std::unique_ptr<driver::Driver> NewDriver(new driver::Driver(
2567330f729Sjoerg /* ClangExecutable= */ "", llvm::sys::getDefaultTargetTriple(),
2577330f729Sjoerg Diagnostics));
2587330f729Sjoerg NewDriver->setCheckInputsExist(false);
2597330f729Sjoerg
2607330f729Sjoerg // This becomes the new argv[0]. The value is used to detect libc++ include
2617330f729Sjoerg // dirs on Mac, it isn't used for other platforms.
2627330f729Sjoerg std::string Argv0 = GetClangToolCommand();
2637330f729Sjoerg Args.insert(Args.begin(), Argv0.c_str());
2647330f729Sjoerg
2657330f729Sjoerg // By adding -c, we force the driver to treat compilation as the last phase.
2667330f729Sjoerg // It will then issue warnings via Diagnostics about un-used options that
2677330f729Sjoerg // would have been used for linking. If the user provided a compiler name as
2687330f729Sjoerg // the original argv[0], this will be treated as a linker input thanks to
2697330f729Sjoerg // insertng a new argv[0] above. All un-used options get collected by
2707330f729Sjoerg // UnusedInputdiagConsumer and get stripped out later.
2717330f729Sjoerg Args.push_back("-c");
2727330f729Sjoerg
2737330f729Sjoerg // Put a dummy C++ file on to ensure there's at least one compile job for the
2747330f729Sjoerg // driver to construct. If the user specified some other argument that
2757330f729Sjoerg // prevents compilation, e.g. -E or something like -version, we may still end
2767330f729Sjoerg // up with no jobs but then this is the user's fault.
2777330f729Sjoerg Args.push_back("placeholder.cpp");
2787330f729Sjoerg
279*e038c9c4Sjoerg llvm::erase_if(Args, FilterUnusedFlags());
2807330f729Sjoerg
2817330f729Sjoerg const std::unique_ptr<driver::Compilation> Compilation(
2827330f729Sjoerg NewDriver->BuildCompilation(Args));
2837330f729Sjoerg if (!Compilation)
2847330f729Sjoerg return false;
2857330f729Sjoerg
2867330f729Sjoerg const driver::JobList &Jobs = Compilation->getJobs();
2877330f729Sjoerg
2887330f729Sjoerg CompileJobAnalyzer CompileAnalyzer;
2897330f729Sjoerg
2907330f729Sjoerg for (const auto &Cmd : Jobs) {
2917330f729Sjoerg // Collect only for Assemble, Backend, and Compile jobs. If we do all jobs
2927330f729Sjoerg // we get duplicates since Link jobs point to Assemble jobs as inputs.
2937330f729Sjoerg // -flto* flags make the BackendJobClass, which still needs analyzer.
2947330f729Sjoerg if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass ||
2957330f729Sjoerg Cmd.getSource().getKind() == driver::Action::BackendJobClass ||
2967330f729Sjoerg Cmd.getSource().getKind() == driver::Action::CompileJobClass) {
2977330f729Sjoerg CompileAnalyzer.run(&Cmd.getSource());
2987330f729Sjoerg }
2997330f729Sjoerg }
3007330f729Sjoerg
3017330f729Sjoerg if (CompileAnalyzer.Inputs.empty()) {
3027330f729Sjoerg ErrorMsg = "warning: no compile jobs found\n";
3037330f729Sjoerg return false;
3047330f729Sjoerg }
3057330f729Sjoerg
306*e038c9c4Sjoerg // Remove all compilation input files from the command line and inputs deemed
307*e038c9c4Sjoerg // unused for compilation. This is necessary so that getCompileCommands() can
308*e038c9c4Sjoerg // construct a command line for each file.
309*e038c9c4Sjoerg std::vector<const char *>::iterator End =
310*e038c9c4Sjoerg llvm::remove_if(Args, [&](StringRef S) {
311*e038c9c4Sjoerg return llvm::is_contained(CompileAnalyzer.Inputs, S) ||
312*e038c9c4Sjoerg llvm::is_contained(DiagClient.UnusedInputs, S);
313*e038c9c4Sjoerg });
3147330f729Sjoerg // Remove the -c add above as well. It will be at the end right now.
3157330f729Sjoerg assert(strcmp(*(End - 1), "-c") == 0);
3167330f729Sjoerg --End;
3177330f729Sjoerg
3187330f729Sjoerg Result = std::vector<std::string>(Args.begin() + 1, End);
3197330f729Sjoerg return true;
3207330f729Sjoerg }
3217330f729Sjoerg
3227330f729Sjoerg std::unique_ptr<FixedCompilationDatabase>
loadFromCommandLine(int & Argc,const char * const * Argv,std::string & ErrorMsg,const Twine & Directory)3237330f729Sjoerg FixedCompilationDatabase::loadFromCommandLine(int &Argc,
3247330f729Sjoerg const char *const *Argv,
3257330f729Sjoerg std::string &ErrorMsg,
326*e038c9c4Sjoerg const Twine &Directory) {
3277330f729Sjoerg ErrorMsg.clear();
3287330f729Sjoerg if (Argc == 0)
3297330f729Sjoerg return nullptr;
3307330f729Sjoerg const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
3317330f729Sjoerg if (DoubleDash == Argv + Argc)
3327330f729Sjoerg return nullptr;
3337330f729Sjoerg std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc);
3347330f729Sjoerg Argc = DoubleDash - Argv;
3357330f729Sjoerg
3367330f729Sjoerg std::vector<std::string> StrippedArgs;
3377330f729Sjoerg if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg))
3387330f729Sjoerg return nullptr;
3397330f729Sjoerg return std::make_unique<FixedCompilationDatabase>(Directory, StrippedArgs);
3407330f729Sjoerg }
3417330f729Sjoerg
3427330f729Sjoerg std::unique_ptr<FixedCompilationDatabase>
loadFromFile(StringRef Path,std::string & ErrorMsg)3437330f729Sjoerg FixedCompilationDatabase::loadFromFile(StringRef Path, std::string &ErrorMsg) {
3447330f729Sjoerg ErrorMsg.clear();
3457330f729Sjoerg llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
3467330f729Sjoerg llvm::MemoryBuffer::getFile(Path);
3477330f729Sjoerg if (std::error_code Result = File.getError()) {
3487330f729Sjoerg ErrorMsg = "Error while opening fixed database: " + Result.message();
3497330f729Sjoerg return nullptr;
3507330f729Sjoerg }
351*e038c9c4Sjoerg return loadFromBuffer(llvm::sys::path::parent_path(Path),
352*e038c9c4Sjoerg (*File)->getBuffer(), ErrorMsg);
3537330f729Sjoerg }
3547330f729Sjoerg
355*e038c9c4Sjoerg std::unique_ptr<FixedCompilationDatabase>
loadFromBuffer(StringRef Directory,StringRef Data,std::string & ErrorMsg)356*e038c9c4Sjoerg FixedCompilationDatabase::loadFromBuffer(StringRef Directory, StringRef Data,
357*e038c9c4Sjoerg std::string &ErrorMsg) {
358*e038c9c4Sjoerg ErrorMsg.clear();
359*e038c9c4Sjoerg std::vector<std::string> Args;
360*e038c9c4Sjoerg StringRef Line;
361*e038c9c4Sjoerg while (!Data.empty()) {
362*e038c9c4Sjoerg std::tie(Line, Data) = Data.split('\n');
363*e038c9c4Sjoerg // Stray whitespace is almost certainly unintended.
364*e038c9c4Sjoerg Line = Line.trim();
365*e038c9c4Sjoerg if (!Line.empty())
366*e038c9c4Sjoerg Args.push_back(Line.str());
367*e038c9c4Sjoerg }
368*e038c9c4Sjoerg return std::make_unique<FixedCompilationDatabase>(Directory, std::move(Args));
369*e038c9c4Sjoerg }
370*e038c9c4Sjoerg
FixedCompilationDatabase(const Twine & Directory,ArrayRef<std::string> CommandLine)371*e038c9c4Sjoerg FixedCompilationDatabase::FixedCompilationDatabase(
372*e038c9c4Sjoerg const Twine &Directory, ArrayRef<std::string> CommandLine) {
3737330f729Sjoerg std::vector<std::string> ToolCommandLine(1, GetClangToolCommand());
3747330f729Sjoerg ToolCommandLine.insert(ToolCommandLine.end(),
3757330f729Sjoerg CommandLine.begin(), CommandLine.end());
3767330f729Sjoerg CompileCommands.emplace_back(Directory, StringRef(),
3777330f729Sjoerg std::move(ToolCommandLine),
3787330f729Sjoerg StringRef());
3797330f729Sjoerg }
3807330f729Sjoerg
3817330f729Sjoerg std::vector<CompileCommand>
getCompileCommands(StringRef FilePath) const3827330f729Sjoerg FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
3837330f729Sjoerg std::vector<CompileCommand> Result(CompileCommands);
384*e038c9c4Sjoerg Result[0].CommandLine.push_back(std::string(FilePath));
385*e038c9c4Sjoerg Result[0].Filename = std::string(FilePath);
3867330f729Sjoerg return Result;
3877330f729Sjoerg }
3887330f729Sjoerg
3897330f729Sjoerg namespace {
3907330f729Sjoerg
3917330f729Sjoerg class FixedCompilationDatabasePlugin : public CompilationDatabasePlugin {
3927330f729Sjoerg std::unique_ptr<CompilationDatabase>
loadFromDirectory(StringRef Directory,std::string & ErrorMessage)3937330f729Sjoerg loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
3947330f729Sjoerg SmallString<1024> DatabasePath(Directory);
3957330f729Sjoerg llvm::sys::path::append(DatabasePath, "compile_flags.txt");
3967330f729Sjoerg return FixedCompilationDatabase::loadFromFile(DatabasePath, ErrorMessage);
3977330f729Sjoerg }
3987330f729Sjoerg };
3997330f729Sjoerg
4007330f729Sjoerg } // namespace
4017330f729Sjoerg
4027330f729Sjoerg static CompilationDatabasePluginRegistry::Add<FixedCompilationDatabasePlugin>
4037330f729Sjoerg X("fixed-compilation-database", "Reads plain-text flags file");
4047330f729Sjoerg
4057330f729Sjoerg namespace clang {
4067330f729Sjoerg namespace tooling {
4077330f729Sjoerg
4087330f729Sjoerg // This anchor is used to force the linker to link in the generated object file
4097330f729Sjoerg // and thus register the JSONCompilationDatabasePlugin.
4107330f729Sjoerg extern volatile int JSONAnchorSource;
4117330f729Sjoerg static int LLVM_ATTRIBUTE_UNUSED JSONAnchorDest = JSONAnchorSource;
4127330f729Sjoerg
4137330f729Sjoerg } // namespace tooling
4147330f729Sjoerg } // namespace clang
415