xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Tooling/CompilationDatabase.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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