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