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