147c245a5SManuel Klimek //===--- 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 // 1347c245a5SManuel Klimek //===----------------------------------------------------------------------===// 1447c245a5SManuel Klimek 1547c245a5SManuel Klimek #include "clang/Tooling/CompilationDatabase.h" 166ed1f85cSDaniel Jasper #include "clang/Tooling/CompilationDatabasePluginRegistry.h" 1765fd0e1fSManuel Klimek #include "clang/Tooling/Tooling.h" 1847c245a5SManuel Klimek #include "llvm/ADT/SmallString.h" 1947c245a5SManuel Klimek #include "llvm/Support/Path.h" 2047c245a5SManuel Klimek #include "llvm/Support/system_error.h" 213a02247dSChandler Carruth #include <sstream> 2247c245a5SManuel Klimek 23*eb56f4feSEdwin Vane #include "clang/Basic/Diagnostic.h" 24*eb56f4feSEdwin Vane #include "clang/Driver/Action.h" 25*eb56f4feSEdwin Vane #include "clang/Driver/Driver.h" 26*eb56f4feSEdwin Vane #include "clang/Driver/DriverDiagnostic.h" 27*eb56f4feSEdwin Vane #include "clang/Driver/Job.h" 28*eb56f4feSEdwin Vane #include "clang/Driver/Compilation.h" 29*eb56f4feSEdwin Vane #include "clang/Frontend/TextDiagnosticPrinter.h" 30*eb56f4feSEdwin Vane #include "llvm/Support/Host.h" 31*eb56f4feSEdwin Vane #include "llvm/Option/Arg.h" 32*eb56f4feSEdwin Vane 3347c245a5SManuel Klimek namespace clang { 3447c245a5SManuel Klimek namespace tooling { 3547c245a5SManuel Klimek 3647c245a5SManuel Klimek CompilationDatabase::~CompilationDatabase() {} 3747c245a5SManuel Klimek 3847c245a5SManuel Klimek CompilationDatabase * 3947c245a5SManuel Klimek CompilationDatabase::loadFromDirectory(StringRef BuildDirectory, 4047c245a5SManuel Klimek std::string &ErrorMessage) { 416ed1f85cSDaniel Jasper std::stringstream ErrorStream; 426ed1f85cSDaniel Jasper for (CompilationDatabasePluginRegistry::iterator 436ed1f85cSDaniel Jasper It = CompilationDatabasePluginRegistry::begin(), 446ed1f85cSDaniel Jasper Ie = CompilationDatabasePluginRegistry::end(); 456ed1f85cSDaniel Jasper It != Ie; ++It) { 466ed1f85cSDaniel Jasper std::string DatabaseErrorMessage; 476ed1f85cSDaniel Jasper OwningPtr<CompilationDatabasePlugin> Plugin(It->instantiate()); 486ed1f85cSDaniel Jasper if (CompilationDatabase *DB = 496ed1f85cSDaniel Jasper Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage)) 506ed1f85cSDaniel Jasper return DB; 516ed1f85cSDaniel Jasper else 526ed1f85cSDaniel Jasper ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n"; 5347c245a5SManuel Klimek } 546ed1f85cSDaniel Jasper ErrorMessage = ErrorStream.str(); 556ed1f85cSDaniel Jasper return NULL; 5647c245a5SManuel Klimek } 5747c245a5SManuel Klimek 58617f5269SArnaud A. de Grandmaison static CompilationDatabase * 596ed1f85cSDaniel Jasper findCompilationDatabaseFromDirectory(StringRef Directory, 606ed1f85cSDaniel Jasper std::string &ErrorMessage) { 616ed1f85cSDaniel Jasper std::stringstream ErrorStream; 6274351ff4SDaniel Jasper bool HasErrorMessage = false; 63617f5269SArnaud A. de Grandmaison while (!Directory.empty()) { 64617f5269SArnaud A. de Grandmaison std::string LoadErrorMessage; 65617f5269SArnaud A. de Grandmaison 66617f5269SArnaud A. de Grandmaison if (CompilationDatabase *DB = 67617f5269SArnaud A. de Grandmaison CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage)) 68617f5269SArnaud A. de Grandmaison return DB; 6974351ff4SDaniel Jasper 7074351ff4SDaniel Jasper if (!HasErrorMessage) { 716ed1f85cSDaniel Jasper ErrorStream << "No compilation database found in " << Directory.str() 7274351ff4SDaniel Jasper << " or any parent directory\n" << LoadErrorMessage; 7374351ff4SDaniel Jasper HasErrorMessage = true; 7474351ff4SDaniel Jasper } 75617f5269SArnaud A. de Grandmaison 76617f5269SArnaud A. de Grandmaison Directory = llvm::sys::path::parent_path(Directory); 77617f5269SArnaud A. de Grandmaison } 786ed1f85cSDaniel Jasper ErrorMessage = ErrorStream.str(); 79617f5269SArnaud A. de Grandmaison return NULL; 80617f5269SArnaud A. de Grandmaison } 81617f5269SArnaud A. de Grandmaison 8265fd0e1fSManuel Klimek CompilationDatabase * 8365fd0e1fSManuel Klimek CompilationDatabase::autoDetectFromSource(StringRef SourceFile, 8465fd0e1fSManuel Klimek std::string &ErrorMessage) { 85f857950dSDmitri Gribenko SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile)); 8665fd0e1fSManuel Klimek StringRef Directory = llvm::sys::path::parent_path(AbsolutePath); 87617f5269SArnaud A. de Grandmaison 886ed1f85cSDaniel Jasper CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory, 896ed1f85cSDaniel Jasper ErrorMessage); 90617f5269SArnaud A. de Grandmaison 91617f5269SArnaud A. de Grandmaison if (!DB) 9265fd0e1fSManuel Klimek ErrorMessage = ("Could not auto-detect compilation database for file \"" + 936ed1f85cSDaniel Jasper SourceFile + "\"\n" + ErrorMessage).str(); 94617f5269SArnaud A. de Grandmaison return DB; 95617f5269SArnaud A. de Grandmaison } 96617f5269SArnaud A. de Grandmaison 97617f5269SArnaud A. de Grandmaison CompilationDatabase * 98617f5269SArnaud A. de Grandmaison CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir, 99617f5269SArnaud A. de Grandmaison std::string &ErrorMessage) { 100f857950dSDmitri Gribenko SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir)); 101617f5269SArnaud A. de Grandmaison 1026ed1f85cSDaniel Jasper CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath, 1036ed1f85cSDaniel Jasper ErrorMessage); 104617f5269SArnaud A. de Grandmaison 105617f5269SArnaud A. de Grandmaison if (!DB) 106617f5269SArnaud A. de Grandmaison ErrorMessage = ("Could not auto-detect compilation database from directory \"" + 1076ed1f85cSDaniel Jasper SourceDir + "\"\n" + ErrorMessage).str(); 108617f5269SArnaud A. de Grandmaison return DB; 10965fd0e1fSManuel Klimek } 11065fd0e1fSManuel Klimek 1116ed1f85cSDaniel Jasper CompilationDatabasePlugin::~CompilationDatabasePlugin() {} 1126ed1f85cSDaniel Jasper 113*eb56f4feSEdwin Vane // Helper for recursively searching through a chain of actions and collecting 114*eb56f4feSEdwin Vane // all inputs, direct and indirect, of compile jobs. 115*eb56f4feSEdwin Vane struct CompileJobAnalyzer { 116*eb56f4feSEdwin Vane void run(const driver::Action *A) { 117*eb56f4feSEdwin Vane runImpl(A, false); 118*eb56f4feSEdwin Vane } 119*eb56f4feSEdwin Vane 120*eb56f4feSEdwin Vane SmallVector<std::string, 2> Inputs; 121*eb56f4feSEdwin Vane 122*eb56f4feSEdwin Vane private: 123*eb56f4feSEdwin Vane 124*eb56f4feSEdwin Vane void runImpl(const driver::Action *A, bool Collect) { 125*eb56f4feSEdwin Vane bool CollectChildren = Collect; 126*eb56f4feSEdwin Vane switch (A->getKind()) { 127*eb56f4feSEdwin Vane case driver::Action::CompileJobClass: 128*eb56f4feSEdwin Vane CollectChildren = true; 129*eb56f4feSEdwin Vane break; 130*eb56f4feSEdwin Vane 131*eb56f4feSEdwin Vane case driver::Action::InputClass: { 132*eb56f4feSEdwin Vane if (Collect) { 133*eb56f4feSEdwin Vane const driver::InputAction *IA = cast<driver::InputAction>(A); 134*eb56f4feSEdwin Vane Inputs.push_back(IA->getInputArg().getSpelling()); 135*eb56f4feSEdwin Vane } 136*eb56f4feSEdwin Vane } break; 137*eb56f4feSEdwin Vane 138*eb56f4feSEdwin Vane default: 139*eb56f4feSEdwin Vane // Don't care about others 140*eb56f4feSEdwin Vane ; 141*eb56f4feSEdwin Vane } 142*eb56f4feSEdwin Vane 143*eb56f4feSEdwin Vane for (driver::ActionList::const_iterator I = A->begin(), E = A->end(); 144*eb56f4feSEdwin Vane I != E; ++I) 145*eb56f4feSEdwin Vane runImpl(*I, CollectChildren); 146*eb56f4feSEdwin Vane } 147*eb56f4feSEdwin Vane }; 148*eb56f4feSEdwin Vane 149*eb56f4feSEdwin Vane // Special DiagnosticConsumer that looks for warn_drv_input_file_unused 150*eb56f4feSEdwin Vane // diagnostics from the driver and collects the option strings for those unused 151*eb56f4feSEdwin Vane // options. 152*eb56f4feSEdwin Vane class UnusedInputDiagConsumer : public DiagnosticConsumer { 153*eb56f4feSEdwin Vane public: 154*eb56f4feSEdwin Vane UnusedInputDiagConsumer() : Other(0) {} 155*eb56f4feSEdwin Vane 156*eb56f4feSEdwin Vane // Useful for debugging, chain diagnostics to another consumer after 157*eb56f4feSEdwin Vane // recording for our own purposes. 158*eb56f4feSEdwin Vane UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {} 159*eb56f4feSEdwin Vane 160*eb56f4feSEdwin Vane virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 161*eb56f4feSEdwin Vane const Diagnostic &Info) LLVM_OVERRIDE { 162*eb56f4feSEdwin Vane if (Info.getID() == clang::diag::warn_drv_input_file_unused) { 163*eb56f4feSEdwin Vane // Arg 1 for this diagnostic is the option that didn't get used. 164*eb56f4feSEdwin Vane UnusedInputs.push_back(Info.getArgStdStr(0)); 165*eb56f4feSEdwin Vane } 166*eb56f4feSEdwin Vane if (Other) 167*eb56f4feSEdwin Vane Other->HandleDiagnostic(DiagLevel, Info); 168*eb56f4feSEdwin Vane } 169*eb56f4feSEdwin Vane 170*eb56f4feSEdwin Vane DiagnosticConsumer *Other; 171*eb56f4feSEdwin Vane SmallVector<std::string, 2> UnusedInputs; 172*eb56f4feSEdwin Vane }; 173*eb56f4feSEdwin Vane 174*eb56f4feSEdwin Vane // Unary functor for asking "Given a StringRef S1, does there exist a string 175*eb56f4feSEdwin Vane // S2 in Arr where S1 == S2?" 176*eb56f4feSEdwin Vane struct MatchesAny { 177*eb56f4feSEdwin Vane MatchesAny(ArrayRef<std::string> Arr) : Arr(Arr) {} 178*eb56f4feSEdwin Vane bool operator() (StringRef S) { 179*eb56f4feSEdwin Vane for (const std::string *I = Arr.begin(), *E = Arr.end(); I != E; ++I) 180*eb56f4feSEdwin Vane if (*I == S) 181*eb56f4feSEdwin Vane return true; 182*eb56f4feSEdwin Vane return false; 183*eb56f4feSEdwin Vane } 184*eb56f4feSEdwin Vane private: 185*eb56f4feSEdwin Vane ArrayRef<std::string> Arr; 186*eb56f4feSEdwin Vane }; 187*eb56f4feSEdwin Vane 188*eb56f4feSEdwin Vane /// \brief Strips any positional args and possible argv[0] from a command-line 189*eb56f4feSEdwin Vane /// provided by the user to construct a FixedCompilationDatabase. 190*eb56f4feSEdwin Vane /// 191*eb56f4feSEdwin Vane /// FixedCompilationDatabase requires a command line to be in this format as it 192*eb56f4feSEdwin Vane /// constructs the command line for each file by appending the name of the file 193*eb56f4feSEdwin Vane /// to be compiled. FixedCompilationDatabase also adds its own argv[0] to the 194*eb56f4feSEdwin Vane /// start of the command line although its value is not important as it's just 195*eb56f4feSEdwin Vane /// ignored by the Driver invoked by the ClangTool using the 196*eb56f4feSEdwin Vane /// FixedCompilationDatabase. 197*eb56f4feSEdwin Vane /// 198*eb56f4feSEdwin Vane /// FIXME: This functionality should probably be made available by 199*eb56f4feSEdwin Vane /// clang::driver::Driver although what the interface should look like is not 200*eb56f4feSEdwin Vane /// clear. 201*eb56f4feSEdwin Vane /// 202*eb56f4feSEdwin Vane /// \param[in] Args Args as provided by the user. 203*eb56f4feSEdwin Vane /// \param[out] Resulting stripped command line. 204*eb56f4feSEdwin Vane /// 205*eb56f4feSEdwin Vane /// \returns \li true if successful. 206*eb56f4feSEdwin Vane /// \li false if \c Args cannot be used for compilation jobs (e.g. 207*eb56f4feSEdwin Vane /// contains an option like -E or -version). 208*eb56f4feSEdwin Vane bool stripPositionalArgs(std::vector<const char *> Args, 209*eb56f4feSEdwin Vane std::vector<std::string> &Result) { 210*eb56f4feSEdwin Vane IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 211*eb56f4feSEdwin Vane UnusedInputDiagConsumer DiagClient; 212*eb56f4feSEdwin Vane DiagnosticsEngine Diagnostics( 213*eb56f4feSEdwin Vane IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), 214*eb56f4feSEdwin Vane &*DiagOpts, &DiagClient, false); 215*eb56f4feSEdwin Vane 216*eb56f4feSEdwin Vane // Neither clang executable nor default image name are required since the 217*eb56f4feSEdwin Vane // jobs the driver builds will not be executed. 218*eb56f4feSEdwin Vane OwningPtr<driver::Driver> NewDriver(new driver::Driver( 219*eb56f4feSEdwin Vane /* ClangExecutable= */ "", llvm::sys::getDefaultTargetTriple(), 220*eb56f4feSEdwin Vane /* DefaultImageName= */ "", Diagnostics)); 221*eb56f4feSEdwin Vane NewDriver->setCheckInputsExist(false); 222*eb56f4feSEdwin Vane 223*eb56f4feSEdwin Vane // This becomes the new argv[0]. The value is actually not important as it 224*eb56f4feSEdwin Vane // isn't used for invoking Tools. 225*eb56f4feSEdwin Vane Args.insert(Args.begin(), "clang-tool"); 226*eb56f4feSEdwin Vane 227*eb56f4feSEdwin Vane // By adding -c, we force the driver to treat compilation as the last phase. 228*eb56f4feSEdwin Vane // It will then issue warnings via Diagnostics about un-used options that 229*eb56f4feSEdwin Vane // would have been used for linking. If the user provided a compiler name as 230*eb56f4feSEdwin Vane // the original argv[0], this will be treated as a linker input thanks to 231*eb56f4feSEdwin Vane // insertng a new argv[0] above. All un-used options get collected by 232*eb56f4feSEdwin Vane // UnusedInputdiagConsumer and get stripped out later. 233*eb56f4feSEdwin Vane Args.push_back("-c"); 234*eb56f4feSEdwin Vane 235*eb56f4feSEdwin Vane // Put a dummy C++ file on to ensure there's at least one compile job for the 236*eb56f4feSEdwin Vane // driver to construct. If the user specified some other argument that 237*eb56f4feSEdwin Vane // prevents compilation, e.g. -E or something like -version, we may still end 238*eb56f4feSEdwin Vane // up with no jobs but then this is the user's fault. 239*eb56f4feSEdwin Vane Args.push_back("placeholder.cpp"); 240*eb56f4feSEdwin Vane 241*eb56f4feSEdwin Vane const OwningPtr<driver::Compilation> Compilation( 242*eb56f4feSEdwin Vane NewDriver->BuildCompilation(Args)); 243*eb56f4feSEdwin Vane 244*eb56f4feSEdwin Vane const driver::JobList &Jobs = Compilation->getJobs(); 245*eb56f4feSEdwin Vane 246*eb56f4feSEdwin Vane CompileJobAnalyzer CompileAnalyzer; 247*eb56f4feSEdwin Vane 248*eb56f4feSEdwin Vane for (driver::JobList::const_iterator I = Jobs.begin(), E = Jobs.end(); I != E; 249*eb56f4feSEdwin Vane ++I) { 250*eb56f4feSEdwin Vane if ((*I)->getKind() == driver::Job::CommandClass) { 251*eb56f4feSEdwin Vane const driver::Command *Cmd = cast<driver::Command>(*I); 252*eb56f4feSEdwin Vane // Collect only for Assemble jobs. If we do all jobs we get duplicates 253*eb56f4feSEdwin Vane // since Link jobs point to Assemble jobs as inputs. 254*eb56f4feSEdwin Vane if (Cmd->getSource().getKind() == driver::Action::AssembleJobClass) 255*eb56f4feSEdwin Vane CompileAnalyzer.run(&Cmd->getSource()); 256*eb56f4feSEdwin Vane } 257*eb56f4feSEdwin Vane } 258*eb56f4feSEdwin Vane 259*eb56f4feSEdwin Vane if (CompileAnalyzer.Inputs.empty()) { 260*eb56f4feSEdwin Vane // No compile jobs found. 261*eb56f4feSEdwin Vane // FIXME: Emit a warning of some kind? 262*eb56f4feSEdwin Vane return false; 263*eb56f4feSEdwin Vane } 264*eb56f4feSEdwin Vane 265*eb56f4feSEdwin Vane // Remove all compilation input files from the command line. This is 266*eb56f4feSEdwin Vane // necessary so that getCompileCommands() can construct a command line for 267*eb56f4feSEdwin Vane // each file. 268*eb56f4feSEdwin Vane std::vector<const char *>::iterator End = std::remove_if( 269*eb56f4feSEdwin Vane Args.begin(), Args.end(), MatchesAny(CompileAnalyzer.Inputs)); 270*eb56f4feSEdwin Vane 271*eb56f4feSEdwin Vane // Remove all inputs deemed unused for compilation. 272*eb56f4feSEdwin Vane End = std::remove_if(Args.begin(), End, MatchesAny(DiagClient.UnusedInputs)); 273*eb56f4feSEdwin Vane 274*eb56f4feSEdwin Vane // Remove the -c add above as well. It will be at the end right now. 275*eb56f4feSEdwin Vane assert(*(End - 1) == "-c"); 276*eb56f4feSEdwin Vane --End; 277*eb56f4feSEdwin Vane 278*eb56f4feSEdwin Vane Result = std::vector<std::string>(Args.begin() + 1, End); 279*eb56f4feSEdwin Vane return true; 280*eb56f4feSEdwin Vane } 281*eb56f4feSEdwin Vane 282ff26efceSManuel Klimek FixedCompilationDatabase * 283ff26efceSManuel Klimek FixedCompilationDatabase::loadFromCommandLine(int &Argc, 284ff26efceSManuel Klimek const char **Argv, 285ff26efceSManuel Klimek Twine Directory) { 286ff26efceSManuel Klimek const char **DoubleDash = std::find(Argv, Argv + Argc, StringRef("--")); 287ff26efceSManuel Klimek if (DoubleDash == Argv + Argc) 288ff26efceSManuel Klimek return NULL; 289*eb56f4feSEdwin Vane std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc); 290ff26efceSManuel Klimek Argc = DoubleDash - Argv; 291*eb56f4feSEdwin Vane 292*eb56f4feSEdwin Vane std::vector<std::string> StrippedArgs; 293*eb56f4feSEdwin Vane if (!stripPositionalArgs(CommandLine, StrippedArgs)) 294*eb56f4feSEdwin Vane return 0; 295*eb56f4feSEdwin Vane return new FixedCompilationDatabase(Directory, StrippedArgs); 296ff26efceSManuel Klimek } 297ff26efceSManuel Klimek 298ff26efceSManuel Klimek FixedCompilationDatabase:: 299ff26efceSManuel Klimek FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) { 300ff26efceSManuel Klimek std::vector<std::string> ToolCommandLine(1, "clang-tool"); 301ff26efceSManuel Klimek ToolCommandLine.insert(ToolCommandLine.end(), 302ff26efceSManuel Klimek CommandLine.begin(), CommandLine.end()); 303ff26efceSManuel Klimek CompileCommands.push_back(CompileCommand(Directory, ToolCommandLine)); 304ff26efceSManuel Klimek } 305ff26efceSManuel Klimek 306ff26efceSManuel Klimek std::vector<CompileCommand> 307ff26efceSManuel Klimek FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const { 308ff26efceSManuel Klimek std::vector<CompileCommand> Result(CompileCommands); 309ff26efceSManuel Klimek Result[0].CommandLine.push_back(FilePath); 310ff26efceSManuel Klimek return Result; 311ff26efceSManuel Klimek } 312ff26efceSManuel Klimek 31360b80161SManuel Klimek std::vector<std::string> 31460b80161SManuel Klimek FixedCompilationDatabase::getAllFiles() const { 31560b80161SManuel Klimek return std::vector<std::string>(); 31660b80161SManuel Klimek } 31760b80161SManuel Klimek 318251ad5e0SArgyrios Kyrtzidis std::vector<CompileCommand> 319251ad5e0SArgyrios Kyrtzidis FixedCompilationDatabase::getAllCompileCommands() const { 320251ad5e0SArgyrios Kyrtzidis return std::vector<CompileCommand>(); 321251ad5e0SArgyrios Kyrtzidis } 322251ad5e0SArgyrios Kyrtzidis 3236ed1f85cSDaniel Jasper // This anchor is used to force the linker to link in the generated object file 3246ed1f85cSDaniel Jasper // and thus register the JSONCompilationDatabasePlugin. 3256ed1f85cSDaniel Jasper extern volatile int JSONAnchorSource; 3266ed1f85cSDaniel Jasper static int JSONAnchorDest = JSONAnchorSource; 32747c245a5SManuel Klimek 32847c245a5SManuel Klimek } // end namespace tooling 32947c245a5SManuel Klimek } // end namespace clang 330