1*6366efedSEugene Zelenko //===- CompilationDatabase.cpp --------------------------------------------===//
247c245a5SManuel Klimek //
347c245a5SManuel Klimek //                     The LLVM Compiler Infrastructure
447c245a5SManuel Klimek //
547c245a5SManuel Klimek // This file is distributed under the University of Illinois Open Source
647c245a5SManuel Klimek // License. See LICENSE.TXT for details.
747c245a5SManuel Klimek //
847c245a5SManuel Klimek //===----------------------------------------------------------------------===//
947c245a5SManuel Klimek //
106ed1f85cSDaniel Jasper //  This file contains implementations of the CompilationDatabase base class
116ed1f85cSDaniel Jasper //  and the FixedCompilationDatabase.
1247c245a5SManuel Klimek //
1360d74e45SSam McCall //  FIXME: Various functions that take a string &ErrorMessage should be upgraded
1460d74e45SSam McCall //  to Expected.
1560d74e45SSam McCall //
1647c245a5SManuel Klimek //===----------------------------------------------------------------------===//
1747c245a5SManuel Klimek 
1847c245a5SManuel Klimek #include "clang/Tooling/CompilationDatabase.h"
19eb56f4feSEdwin Vane #include "clang/Basic/Diagnostic.h"
20*6366efedSEugene Zelenko #include "clang/Basic/DiagnosticIDs.h"
21f3ca2698SBenjamin Kramer #include "clang/Basic/DiagnosticOptions.h"
22*6366efedSEugene Zelenko #include "clang/Basic/LLVM.h"
23eb56f4feSEdwin Vane #include "clang/Driver/Action.h"
245553d0d4SChandler Carruth #include "clang/Driver/Compilation.h"
25eb56f4feSEdwin Vane #include "clang/Driver/Driver.h"
26eb56f4feSEdwin Vane #include "clang/Driver/DriverDiagnostic.h"
27eb56f4feSEdwin Vane #include "clang/Driver/Job.h"
28eb56f4feSEdwin Vane #include "clang/Frontend/TextDiagnosticPrinter.h"
295553d0d4SChandler Carruth #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
305553d0d4SChandler Carruth #include "clang/Tooling/Tooling.h"
31*6366efedSEugene Zelenko #include "llvm/ADT/ArrayRef.h"
32*6366efedSEugene Zelenko #include "llvm/ADT/IntrusiveRefCntPtr.h"
33*6366efedSEugene Zelenko #include "llvm/ADT/STLExtras.h"
345553d0d4SChandler Carruth #include "llvm/ADT/SmallString.h"
35*6366efedSEugene Zelenko #include "llvm/ADT/SmallVector.h"
36*6366efedSEugene Zelenko #include "llvm/ADT/StringRef.h"
37eb56f4feSEdwin Vane #include "llvm/Option/Arg.h"
38*6366efedSEugene Zelenko #include "llvm/Support/Casting.h"
39*6366efedSEugene Zelenko #include "llvm/Support/Compiler.h"
40*6366efedSEugene Zelenko #include "llvm/Support/ErrorOr.h"
415553d0d4SChandler Carruth #include "llvm/Support/Host.h"
4260d74e45SSam McCall #include "llvm/Support/LineIterator.h"
43*6366efedSEugene Zelenko #include "llvm/Support/MemoryBuffer.h"
445553d0d4SChandler Carruth #include "llvm/Support/Path.h"
45c46064c2SSerge Pavlov #include "llvm/Support/raw_ostream.h"
46*6366efedSEugene Zelenko #include <algorithm>
47*6366efedSEugene Zelenko #include <cassert>
48*6366efedSEugene Zelenko #include <cstring>
49*6366efedSEugene Zelenko #include <iterator>
50*6366efedSEugene Zelenko #include <memory>
515553d0d4SChandler Carruth #include <sstream>
52*6366efedSEugene Zelenko #include <string>
538a8e554aSRafael Espindola #include <system_error>
54*6366efedSEugene Zelenko #include <utility>
55*6366efedSEugene Zelenko #include <vector>
56*6366efedSEugene Zelenko 
576a1457e6SBenjamin Kramer using namespace clang;
586a1457e6SBenjamin Kramer using namespace tooling;
5947c245a5SManuel Klimek 
604d79ec7fSJohn Brawn LLVM_INSTANTIATE_REGISTRY(CompilationDatabasePluginRegistry)
614d79ec7fSJohn Brawn 
62*6366efedSEugene Zelenko CompilationDatabase::~CompilationDatabase() = default;
6347c245a5SManuel Klimek 
64cdba84c0SDavid Blaikie std::unique_ptr<CompilationDatabase>
6547c245a5SManuel Klimek CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
6647c245a5SManuel Klimek                                        std::string &ErrorMessage) {
672d487db0SMehdi Amini   llvm::raw_string_ostream ErrorStream(ErrorMessage);
686ed1f85cSDaniel Jasper   for (CompilationDatabasePluginRegistry::iterator
696ed1f85cSDaniel Jasper        It = CompilationDatabasePluginRegistry::begin(),
706ed1f85cSDaniel Jasper        Ie = CompilationDatabasePluginRegistry::end();
716ed1f85cSDaniel Jasper        It != Ie; ++It) {
726ed1f85cSDaniel Jasper     std::string DatabaseErrorMessage;
73b8984329SAhmed Charles     std::unique_ptr<CompilationDatabasePlugin> Plugin(It->instantiate());
74cdba84c0SDavid Blaikie     if (std::unique_ptr<CompilationDatabase> DB =
756ed1f85cSDaniel Jasper             Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
766ed1f85cSDaniel Jasper       return DB;
772d487db0SMehdi Amini     ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
7847c245a5SManuel Klimek   }
79ccbc35edSCraig Topper   return nullptr;
8047c245a5SManuel Klimek }
8147c245a5SManuel Klimek 
82cdba84c0SDavid Blaikie static std::unique_ptr<CompilationDatabase>
836ed1f85cSDaniel Jasper findCompilationDatabaseFromDirectory(StringRef Directory,
846ed1f85cSDaniel Jasper                                      std::string &ErrorMessage) {
856ed1f85cSDaniel Jasper   std::stringstream ErrorStream;
8674351ff4SDaniel Jasper   bool HasErrorMessage = false;
87617f5269SArnaud A. de Grandmaison   while (!Directory.empty()) {
88617f5269SArnaud A. de Grandmaison     std::string LoadErrorMessage;
89617f5269SArnaud A. de Grandmaison 
90cdba84c0SDavid Blaikie     if (std::unique_ptr<CompilationDatabase> DB =
91617f5269SArnaud A. de Grandmaison             CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
92617f5269SArnaud A. de Grandmaison       return DB;
9374351ff4SDaniel Jasper 
9474351ff4SDaniel Jasper     if (!HasErrorMessage) {
956ed1f85cSDaniel Jasper       ErrorStream << "No compilation database found in " << Directory.str()
9674351ff4SDaniel Jasper                   << " or any parent directory\n" << LoadErrorMessage;
9774351ff4SDaniel Jasper       HasErrorMessage = true;
9874351ff4SDaniel Jasper     }
99617f5269SArnaud A. de Grandmaison 
100617f5269SArnaud A. de Grandmaison     Directory = llvm::sys::path::parent_path(Directory);
101617f5269SArnaud A. de Grandmaison   }
1026ed1f85cSDaniel Jasper   ErrorMessage = ErrorStream.str();
103ccbc35edSCraig Topper   return nullptr;
104617f5269SArnaud A. de Grandmaison }
105617f5269SArnaud A. de Grandmaison 
106cdba84c0SDavid Blaikie std::unique_ptr<CompilationDatabase>
10765fd0e1fSManuel Klimek CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
10865fd0e1fSManuel Klimek                                           std::string &ErrorMessage) {
109f857950dSDmitri Gribenko   SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
11065fd0e1fSManuel Klimek   StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
111617f5269SArnaud A. de Grandmaison 
112cdba84c0SDavid Blaikie   std::unique_ptr<CompilationDatabase> DB =
113cdba84c0SDavid Blaikie       findCompilationDatabaseFromDirectory(Directory, ErrorMessage);
114617f5269SArnaud A. de Grandmaison 
115617f5269SArnaud A. de Grandmaison   if (!DB)
11665fd0e1fSManuel Klimek     ErrorMessage = ("Could not auto-detect compilation database for file \"" +
1176ed1f85cSDaniel Jasper                    SourceFile + "\"\n" + ErrorMessage).str();
118617f5269SArnaud A. de Grandmaison   return DB;
119617f5269SArnaud A. de Grandmaison }
120617f5269SArnaud A. de Grandmaison 
121cdba84c0SDavid Blaikie std::unique_ptr<CompilationDatabase>
122617f5269SArnaud A. de Grandmaison CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
123617f5269SArnaud A. de Grandmaison                                              std::string &ErrorMessage) {
124f857950dSDmitri Gribenko   SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
125617f5269SArnaud A. de Grandmaison 
126cdba84c0SDavid Blaikie   std::unique_ptr<CompilationDatabase> DB =
127cdba84c0SDavid Blaikie       findCompilationDatabaseFromDirectory(AbsolutePath, ErrorMessage);
128617f5269SArnaud A. de Grandmaison 
129617f5269SArnaud A. de Grandmaison   if (!DB)
130617f5269SArnaud A. de Grandmaison     ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
1316ed1f85cSDaniel Jasper                    SourceDir + "\"\n" + ErrorMessage).str();
132617f5269SArnaud A. de Grandmaison   return DB;
13365fd0e1fSManuel Klimek }
13465fd0e1fSManuel Klimek 
135b50a36c8SSam McCall std::vector<CompileCommand> CompilationDatabase::getAllCompileCommands() const {
136b50a36c8SSam McCall   std::vector<CompileCommand> Result;
137b50a36c8SSam McCall   for (const auto &File : getAllFiles()) {
138b50a36c8SSam McCall     auto C = getCompileCommands(File);
139b50a36c8SSam McCall     std::move(C.begin(), C.end(), std::back_inserter(Result));
140b50a36c8SSam McCall   }
141b50a36c8SSam McCall   return Result;
142b50a36c8SSam McCall }
143b50a36c8SSam McCall 
144*6366efedSEugene Zelenko CompilationDatabasePlugin::~CompilationDatabasePlugin() = default;
1456ed1f85cSDaniel Jasper 
1466a1457e6SBenjamin Kramer namespace {
147*6366efedSEugene Zelenko 
148eb56f4feSEdwin Vane // Helper for recursively searching through a chain of actions and collecting
149eb56f4feSEdwin Vane // all inputs, direct and indirect, of compile jobs.
150eb56f4feSEdwin Vane struct CompileJobAnalyzer {
151*6366efedSEugene Zelenko   SmallVector<std::string, 2> Inputs;
152*6366efedSEugene Zelenko 
153eb56f4feSEdwin Vane   void run(const driver::Action *A) {
154eb56f4feSEdwin Vane     runImpl(A, false);
155eb56f4feSEdwin Vane   }
156eb56f4feSEdwin Vane 
157eb56f4feSEdwin Vane private:
158eb56f4feSEdwin Vane   void runImpl(const driver::Action *A, bool Collect) {
159eb56f4feSEdwin Vane     bool CollectChildren = Collect;
160eb56f4feSEdwin Vane     switch (A->getKind()) {
161eb56f4feSEdwin Vane     case driver::Action::CompileJobClass:
162eb56f4feSEdwin Vane       CollectChildren = true;
163eb56f4feSEdwin Vane       break;
164eb56f4feSEdwin Vane 
165*6366efedSEugene Zelenko     case driver::Action::InputClass:
166eb56f4feSEdwin Vane       if (Collect) {
167*6366efedSEugene Zelenko         const auto *IA = cast<driver::InputAction>(A);
168eb56f4feSEdwin Vane         Inputs.push_back(IA->getInputArg().getSpelling());
169eb56f4feSEdwin Vane       }
170*6366efedSEugene Zelenko       break;
171eb56f4feSEdwin Vane 
172eb56f4feSEdwin Vane     default:
173eb56f4feSEdwin Vane       // Don't care about others
174*6366efedSEugene Zelenko       break;
175eb56f4feSEdwin Vane     }
176eb56f4feSEdwin Vane 
1775a459f82SNico Weber     for (const driver::Action *AI : A->inputs())
1785a459f82SNico Weber       runImpl(AI, CollectChildren);
179eb56f4feSEdwin Vane   }
180eb56f4feSEdwin Vane };
181eb56f4feSEdwin Vane 
182eb56f4feSEdwin Vane // Special DiagnosticConsumer that looks for warn_drv_input_file_unused
183eb56f4feSEdwin Vane // diagnostics from the driver and collects the option strings for those unused
184eb56f4feSEdwin Vane // options.
185eb56f4feSEdwin Vane class UnusedInputDiagConsumer : public DiagnosticConsumer {
186eb56f4feSEdwin Vane public:
187c46064c2SSerge Pavlov   UnusedInputDiagConsumer(DiagnosticConsumer &Other) : Other(Other) {}
188eb56f4feSEdwin Vane 
18934eb2072SAlexander Kornienko   void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
190a798a9dbSCraig Topper                         const Diagnostic &Info) override {
191*6366efedSEugene Zelenko     if (Info.getID() == diag::warn_drv_input_file_unused) {
192eb56f4feSEdwin Vane       // Arg 1 for this diagnostic is the option that didn't get used.
193eb56f4feSEdwin Vane       UnusedInputs.push_back(Info.getArgStdStr(0));
194c46064c2SSerge Pavlov     } else if (DiagLevel >= DiagnosticsEngine::Error) {
195c46064c2SSerge Pavlov       // If driver failed to create compilation object, show the diagnostics
196c46064c2SSerge Pavlov       // to user.
197c46064c2SSerge Pavlov       Other.HandleDiagnostic(DiagLevel, Info);
198eb56f4feSEdwin Vane     }
199eb56f4feSEdwin Vane   }
200eb56f4feSEdwin Vane 
201c46064c2SSerge Pavlov   DiagnosticConsumer &Other;
202eb56f4feSEdwin Vane   SmallVector<std::string, 2> UnusedInputs;
203eb56f4feSEdwin Vane };
204eb56f4feSEdwin Vane 
205eb56f4feSEdwin Vane // Unary functor for asking "Given a StringRef S1, does there exist a string
206eb56f4feSEdwin Vane // S2 in Arr where S1 == S2?"
207eb56f4feSEdwin Vane struct MatchesAny {
208eb56f4feSEdwin Vane   MatchesAny(ArrayRef<std::string> Arr) : Arr(Arr) {}
209*6366efedSEugene Zelenko 
210eb56f4feSEdwin Vane   bool operator() (StringRef S) {
211eb56f4feSEdwin Vane     for (const std::string *I = Arr.begin(), *E = Arr.end(); I != E; ++I)
212eb56f4feSEdwin Vane       if (*I == S)
213eb56f4feSEdwin Vane         return true;
214eb56f4feSEdwin Vane     return false;
215eb56f4feSEdwin Vane   }
216*6366efedSEugene Zelenko 
217eb56f4feSEdwin Vane private:
218eb56f4feSEdwin Vane   ArrayRef<std::string> Arr;
219eb56f4feSEdwin Vane };
220*6366efedSEugene Zelenko 
2216a1457e6SBenjamin Kramer } // namespace
222eb56f4feSEdwin Vane 
223eb56f4feSEdwin Vane /// \brief Strips any positional args and possible argv[0] from a command-line
224eb56f4feSEdwin Vane /// provided by the user to construct a FixedCompilationDatabase.
225eb56f4feSEdwin Vane ///
226eb56f4feSEdwin Vane /// FixedCompilationDatabase requires a command line to be in this format as it
227eb56f4feSEdwin Vane /// constructs the command line for each file by appending the name of the file
228eb56f4feSEdwin Vane /// to be compiled. FixedCompilationDatabase also adds its own argv[0] to the
229eb56f4feSEdwin Vane /// start of the command line although its value is not important as it's just
230eb56f4feSEdwin Vane /// ignored by the Driver invoked by the ClangTool using the
231eb56f4feSEdwin Vane /// FixedCompilationDatabase.
232eb56f4feSEdwin Vane ///
233eb56f4feSEdwin Vane /// FIXME: This functionality should probably be made available by
234eb56f4feSEdwin Vane /// clang::driver::Driver although what the interface should look like is not
235eb56f4feSEdwin Vane /// clear.
236eb56f4feSEdwin Vane ///
237eb56f4feSEdwin Vane /// \param[in] Args Args as provided by the user.
2385335cf33SNAKAMURA Takumi /// \return Resulting stripped command line.
2395335cf33SNAKAMURA Takumi ///          \li true if successful.
240eb56f4feSEdwin Vane ///          \li false if \c Args cannot be used for compilation jobs (e.g.
241eb56f4feSEdwin Vane ///          contains an option like -E or -version).
2423a4fe369SArtyom Skrobov static bool stripPositionalArgs(std::vector<const char *> Args,
243c46064c2SSerge Pavlov                                 std::vector<std::string> &Result,
244c46064c2SSerge Pavlov                                 std::string &ErrorMsg) {
245eb56f4feSEdwin Vane   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
246c46064c2SSerge Pavlov   llvm::raw_string_ostream Output(ErrorMsg);
247c46064c2SSerge Pavlov   TextDiagnosticPrinter DiagnosticPrinter(Output, &*DiagOpts);
248c46064c2SSerge Pavlov   UnusedInputDiagConsumer DiagClient(DiagnosticPrinter);
249eb56f4feSEdwin Vane   DiagnosticsEngine Diagnostics(
250*6366efedSEugene Zelenko       IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
251eb56f4feSEdwin Vane       &*DiagOpts, &DiagClient, false);
252eb56f4feSEdwin Vane 
2531761f118SAlp Toker   // The clang executable path isn't required since the jobs the driver builds
2541761f118SAlp Toker   // will not be executed.
255b8984329SAhmed Charles   std::unique_ptr<driver::Driver> NewDriver(new driver::Driver(
256eb56f4feSEdwin Vane       /* ClangExecutable= */ "", llvm::sys::getDefaultTargetTriple(),
2571761f118SAlp Toker       Diagnostics));
258eb56f4feSEdwin Vane   NewDriver->setCheckInputsExist(false);
259eb56f4feSEdwin Vane 
260eb56f4feSEdwin Vane   // This becomes the new argv[0]. The value is actually not important as it
261eb56f4feSEdwin Vane   // isn't used for invoking Tools.
262eb56f4feSEdwin Vane   Args.insert(Args.begin(), "clang-tool");
263eb56f4feSEdwin Vane 
264eb56f4feSEdwin Vane   // By adding -c, we force the driver to treat compilation as the last phase.
265eb56f4feSEdwin Vane   // It will then issue warnings via Diagnostics about un-used options that
266eb56f4feSEdwin Vane   // would have been used for linking. If the user provided a compiler name as
267eb56f4feSEdwin Vane   // the original argv[0], this will be treated as a linker input thanks to
268eb56f4feSEdwin Vane   // insertng a new argv[0] above. All un-used options get collected by
269eb56f4feSEdwin Vane   // UnusedInputdiagConsumer and get stripped out later.
270eb56f4feSEdwin Vane   Args.push_back("-c");
271eb56f4feSEdwin Vane 
272eb56f4feSEdwin Vane   // Put a dummy C++ file on to ensure there's at least one compile job for the
273eb56f4feSEdwin Vane   // driver to construct. If the user specified some other argument that
274eb56f4feSEdwin Vane   // prevents compilation, e.g. -E or something like -version, we may still end
275eb56f4feSEdwin Vane   // up with no jobs but then this is the user's fault.
276eb56f4feSEdwin Vane   Args.push_back("placeholder.cpp");
277eb56f4feSEdwin Vane 
2783a4fe369SArtyom Skrobov   // Remove -no-integrated-as; it's not used for syntax checking,
2793a4fe369SArtyom Skrobov   // and it confuses targets which don't support this option.
280e1265143SArnaud A. de Grandmaison   Args.erase(std::remove_if(Args.begin(), Args.end(),
281e1265143SArnaud A. de Grandmaison                             MatchesAny(std::string("-no-integrated-as"))),
282e1265143SArnaud A. de Grandmaison              Args.end());
2833a4fe369SArtyom Skrobov 
284b8984329SAhmed Charles   const std::unique_ptr<driver::Compilation> Compilation(
285eb56f4feSEdwin Vane       NewDriver->BuildCompilation(Args));
286c46064c2SSerge Pavlov   if (!Compilation)
287c46064c2SSerge Pavlov     return false;
288eb56f4feSEdwin Vane 
289eb56f4feSEdwin Vane   const driver::JobList &Jobs = Compilation->getJobs();
290eb56f4feSEdwin Vane 
291eb56f4feSEdwin Vane   CompileJobAnalyzer CompileAnalyzer;
292eb56f4feSEdwin Vane 
2930cd9248dSJustin Bogner   for (const auto &Cmd : Jobs) {
294e2863ecaSAlex Lorenz     // Collect only for Assemble and Compile jobs. If we do all jobs we get
295e2863ecaSAlex Lorenz     // duplicates since Link jobs point to Assemble jobs as inputs.
296e2863ecaSAlex Lorenz     if (Cmd.getSource().getKind() == driver::Action::AssembleJobClass ||
297e2863ecaSAlex Lorenz         Cmd.getSource().getKind() == driver::Action::CompileJobClass) {
298c11bf802SDavid Blaikie       CompileAnalyzer.run(&Cmd.getSource());
299eb56f4feSEdwin Vane     }
300e2863ecaSAlex Lorenz   }
301eb56f4feSEdwin Vane 
302eb56f4feSEdwin Vane   if (CompileAnalyzer.Inputs.empty()) {
303c46064c2SSerge Pavlov     ErrorMsg = "warning: no compile jobs found\n";
304eb56f4feSEdwin Vane     return false;
305eb56f4feSEdwin Vane   }
306eb56f4feSEdwin Vane 
307eb56f4feSEdwin Vane   // Remove all compilation input files from the command line. This is
308eb56f4feSEdwin Vane   // necessary so that getCompileCommands() can construct a command line for
309eb56f4feSEdwin Vane   // each file.
310eb56f4feSEdwin Vane   std::vector<const char *>::iterator End = std::remove_if(
311eb56f4feSEdwin Vane       Args.begin(), Args.end(), MatchesAny(CompileAnalyzer.Inputs));
312eb56f4feSEdwin Vane 
313eb56f4feSEdwin Vane   // Remove all inputs deemed unused for compilation.
314eb56f4feSEdwin Vane   End = std::remove_if(Args.begin(), End, MatchesAny(DiagClient.UnusedInputs));
315eb56f4feSEdwin Vane 
316eb56f4feSEdwin Vane   // Remove the -c add above as well. It will be at the end right now.
317e99bb4b2SRichard Trieu   assert(strcmp(*(End - 1), "-c") == 0);
318eb56f4feSEdwin Vane   --End;
319eb56f4feSEdwin Vane 
320eb56f4feSEdwin Vane   Result = std::vector<std::string>(Args.begin() + 1, End);
321eb56f4feSEdwin Vane   return true;
322eb56f4feSEdwin Vane }
323eb56f4feSEdwin Vane 
324c46064c2SSerge Pavlov std::unique_ptr<FixedCompilationDatabase>
325c46064c2SSerge Pavlov FixedCompilationDatabase::loadFromCommandLine(int &Argc,
326c46064c2SSerge Pavlov                                               const char *const *Argv,
327c46064c2SSerge Pavlov                                               std::string &ErrorMsg,
32841a9ee98SZachary Turner                                               Twine Directory) {
329c46064c2SSerge Pavlov   ErrorMsg.clear();
330c46064c2SSerge Pavlov   if (Argc == 0)
331c46064c2SSerge Pavlov     return nullptr;
332ab8f7d58SDavid Blaikie   const char *const *DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
333ff26efceSManuel Klimek   if (DoubleDash == Argv + Argc)
334ccbc35edSCraig Topper     return nullptr;
335eb56f4feSEdwin Vane   std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc);
336ff26efceSManuel Klimek   Argc = DoubleDash - Argv;
337eb56f4feSEdwin Vane 
338eb56f4feSEdwin Vane   std::vector<std::string> StrippedArgs;
339c46064c2SSerge Pavlov   if (!stripPositionalArgs(CommandLine, StrippedArgs, ErrorMsg))
340ccbc35edSCraig Topper     return nullptr;
34160d74e45SSam McCall   return llvm::make_unique<FixedCompilationDatabase>(Directory, StrippedArgs);
34260d74e45SSam McCall }
34360d74e45SSam McCall 
34460d74e45SSam McCall std::unique_ptr<FixedCompilationDatabase>
34560d74e45SSam McCall FixedCompilationDatabase::loadFromFile(StringRef Path, std::string &ErrorMsg) {
34660d74e45SSam McCall   ErrorMsg.clear();
34760d74e45SSam McCall   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
34860d74e45SSam McCall       llvm::MemoryBuffer::getFile(Path);
34960d74e45SSam McCall   if (std::error_code Result = File.getError()) {
35060d74e45SSam McCall     ErrorMsg = "Error while opening fixed database: " + Result.message();
35160d74e45SSam McCall     return nullptr;
35260d74e45SSam McCall   }
35360d74e45SSam McCall   std::vector<std::string> Args{llvm::line_iterator(**File),
35460d74e45SSam McCall                                 llvm::line_iterator()};
35560d74e45SSam McCall   return llvm::make_unique<FixedCompilationDatabase>(
35660d74e45SSam McCall       llvm::sys::path::parent_path(Path), std::move(Args));
357ff26efceSManuel Klimek }
358ff26efceSManuel Klimek 
35941a9ee98SZachary Turner FixedCompilationDatabase::
36041a9ee98SZachary Turner FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) {
361ff26efceSManuel Klimek   std::vector<std::string> ToolCommandLine(1, "clang-tool");
362ff26efceSManuel Klimek   ToolCommandLine.insert(ToolCommandLine.end(),
363ff26efceSManuel Klimek                          CommandLine.begin(), CommandLine.end());
36474bcd21eSArgyrios Kyrtzidis   CompileCommands.emplace_back(Directory, StringRef(),
365399aea30SJoerg Sonnenberger                                std::move(ToolCommandLine),
366399aea30SJoerg Sonnenberger                                StringRef());
367ff26efceSManuel Klimek }
368ff26efceSManuel Klimek 
369ff26efceSManuel Klimek std::vector<CompileCommand>
370ff26efceSManuel Klimek FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
371ff26efceSManuel Klimek   std::vector<CompileCommand> Result(CompileCommands);
372ff26efceSManuel Klimek   Result[0].CommandLine.push_back(FilePath);
37374bcd21eSArgyrios Kyrtzidis   Result[0].Filename = FilePath;
374ff26efceSManuel Klimek   return Result;
375ff26efceSManuel Klimek }
376ff26efceSManuel Klimek 
37760d74e45SSam McCall namespace {
37860d74e45SSam McCall 
37960d74e45SSam McCall class FixedCompilationDatabasePlugin : public CompilationDatabasePlugin {
38060d74e45SSam McCall   std::unique_ptr<CompilationDatabase>
38160d74e45SSam McCall   loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
38260d74e45SSam McCall     SmallString<1024> DatabasePath(Directory);
38360d74e45SSam McCall     llvm::sys::path::append(DatabasePath, "compile_flags.txt");
38460d74e45SSam McCall     return FixedCompilationDatabase::loadFromFile(DatabasePath, ErrorMessage);
38560d74e45SSam McCall   }
38660d74e45SSam McCall };
38760d74e45SSam McCall 
388*6366efedSEugene Zelenko } // namespace
389*6366efedSEugene Zelenko 
39060d74e45SSam McCall static CompilationDatabasePluginRegistry::Add<FixedCompilationDatabasePlugin>
39160d74e45SSam McCall X("fixed-compilation-database", "Reads plain-text flags file");
39260d74e45SSam McCall 
3936a1457e6SBenjamin Kramer namespace clang {
3946a1457e6SBenjamin Kramer namespace tooling {
3956a1457e6SBenjamin Kramer 
3966ed1f85cSDaniel Jasper // This anchor is used to force the linker to link in the generated object file
3976ed1f85cSDaniel Jasper // and thus register the JSONCompilationDatabasePlugin.
3986ed1f85cSDaniel Jasper extern volatile int JSONAnchorSource;
399b7e8c7c7SYaron Keren static int LLVM_ATTRIBUTE_UNUSED JSONAnchorDest = JSONAnchorSource;
40047c245a5SManuel Klimek 
401*6366efedSEugene Zelenko } // namespace tooling
402*6366efedSEugene Zelenko } // namespace clang
403