1234287Sdim//===--- CompilationDatabase.cpp - ----------------------------------------===// 2234287Sdim// 3234287Sdim// The LLVM Compiler Infrastructure 4234287Sdim// 5234287Sdim// This file is distributed under the University of Illinois Open Source 6234287Sdim// License. See LICENSE.TXT for details. 7234287Sdim// 8234287Sdim//===----------------------------------------------------------------------===// 9234287Sdim// 10245431Sdim// This file contains implementations of the CompilationDatabase base class 11245431Sdim// and the FixedCompilationDatabase. 12234287Sdim// 13234287Sdim//===----------------------------------------------------------------------===// 14234287Sdim 15234287Sdim#include "clang/Tooling/CompilationDatabase.h" 16245431Sdim#include "clang/Tooling/CompilationDatabasePluginRegistry.h" 17245431Sdim#include "clang/Tooling/Tooling.h" 18234287Sdim#include "llvm/ADT/SmallString.h" 19234287Sdim#include "llvm/Support/Path.h" 20234287Sdim#include "llvm/Support/system_error.h" 21252723Sdim#include <sstream> 22234287Sdim 23263509Sdim#include "clang/Basic/Diagnostic.h" 24263509Sdim#include "clang/Driver/Action.h" 25263509Sdim#include "clang/Driver/Driver.h" 26263509Sdim#include "clang/Driver/DriverDiagnostic.h" 27263509Sdim#include "clang/Driver/Job.h" 28263509Sdim#include "clang/Driver/Compilation.h" 29263509Sdim#include "clang/Frontend/TextDiagnosticPrinter.h" 30263509Sdim#include "llvm/Support/Host.h" 31263509Sdim#include "llvm/Option/Arg.h" 32263509Sdim 33234287Sdimnamespace clang { 34234287Sdimnamespace tooling { 35234287Sdim 36245431SdimCompilationDatabase::~CompilationDatabase() {} 37234287Sdim 38245431SdimCompilationDatabase * 39245431SdimCompilationDatabase::loadFromDirectory(StringRef BuildDirectory, 40245431Sdim std::string &ErrorMessage) { 41245431Sdim std::stringstream ErrorStream; 42245431Sdim for (CompilationDatabasePluginRegistry::iterator 43245431Sdim It = CompilationDatabasePluginRegistry::begin(), 44245431Sdim Ie = CompilationDatabasePluginRegistry::end(); 45245431Sdim It != Ie; ++It) { 46245431Sdim std::string DatabaseErrorMessage; 47245431Sdim OwningPtr<CompilationDatabasePlugin> Plugin(It->instantiate()); 48245431Sdim if (CompilationDatabase *DB = 49245431Sdim Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage)) 50245431Sdim return DB; 51245431Sdim else 52245431Sdim ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n"; 53234287Sdim } 54245431Sdim ErrorMessage = ErrorStream.str(); 55245431Sdim return NULL; 56245431Sdim} 57234287Sdim 58245431Sdimstatic CompilationDatabase * 59245431SdimfindCompilationDatabaseFromDirectory(StringRef Directory, 60245431Sdim std::string &ErrorMessage) { 61245431Sdim std::stringstream ErrorStream; 62245431Sdim bool HasErrorMessage = false; 63245431Sdim while (!Directory.empty()) { 64245431Sdim std::string LoadErrorMessage; 65234287Sdim 66245431Sdim if (CompilationDatabase *DB = 67245431Sdim CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage)) 68245431Sdim return DB; 69234287Sdim 70245431Sdim if (!HasErrorMessage) { 71245431Sdim ErrorStream << "No compilation database found in " << Directory.str() 72245431Sdim << " or any parent directory\n" << LoadErrorMessage; 73245431Sdim HasErrorMessage = true; 74234287Sdim } 75234287Sdim 76245431Sdim Directory = llvm::sys::path::parent_path(Directory); 77234287Sdim } 78245431Sdim ErrorMessage = ErrorStream.str(); 79245431Sdim return NULL; 80245431Sdim} 81234287Sdim 82245431SdimCompilationDatabase * 83245431SdimCompilationDatabase::autoDetectFromSource(StringRef SourceFile, 84245431Sdim std::string &ErrorMessage) { 85252723Sdim SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile)); 86245431Sdim StringRef Directory = llvm::sys::path::parent_path(AbsolutePath); 87234287Sdim 88245431Sdim CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory, 89245431Sdim ErrorMessage); 90234287Sdim 91245431Sdim if (!DB) 92245431Sdim ErrorMessage = ("Could not auto-detect compilation database for file \"" + 93245431Sdim SourceFile + "\"\n" + ErrorMessage).str(); 94245431Sdim return DB; 95234287Sdim} 96234287Sdim 97245431SdimCompilationDatabase * 98245431SdimCompilationDatabase::autoDetectFromDirectory(StringRef SourceDir, 99245431Sdim std::string &ErrorMessage) { 100252723Sdim SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir)); 101234287Sdim 102245431Sdim CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath, 103245431Sdim ErrorMessage); 104234287Sdim 105245431Sdim if (!DB) 106245431Sdim ErrorMessage = ("Could not auto-detect compilation database from directory \"" + 107245431Sdim SourceDir + "\"\n" + ErrorMessage).str(); 108245431Sdim return DB; 109234287Sdim} 110234287Sdim 111245431SdimCompilationDatabasePlugin::~CompilationDatabasePlugin() {} 112245431Sdim 113263509Sdim// Helper for recursively searching through a chain of actions and collecting 114263509Sdim// all inputs, direct and indirect, of compile jobs. 115263509Sdimstruct CompileJobAnalyzer { 116263509Sdim void run(const driver::Action *A) { 117263509Sdim runImpl(A, false); 118263509Sdim } 119263509Sdim 120263509Sdim SmallVector<std::string, 2> Inputs; 121263509Sdim 122263509Sdimprivate: 123263509Sdim 124263509Sdim void runImpl(const driver::Action *A, bool Collect) { 125263509Sdim bool CollectChildren = Collect; 126263509Sdim switch (A->getKind()) { 127263509Sdim case driver::Action::CompileJobClass: 128263509Sdim CollectChildren = true; 129263509Sdim break; 130263509Sdim 131263509Sdim case driver::Action::InputClass: { 132263509Sdim if (Collect) { 133263509Sdim const driver::InputAction *IA = cast<driver::InputAction>(A); 134263509Sdim Inputs.push_back(IA->getInputArg().getSpelling()); 135263509Sdim } 136263509Sdim } break; 137263509Sdim 138263509Sdim default: 139263509Sdim // Don't care about others 140263509Sdim ; 141263509Sdim } 142263509Sdim 143263509Sdim for (driver::ActionList::const_iterator I = A->begin(), E = A->end(); 144263509Sdim I != E; ++I) 145263509Sdim runImpl(*I, CollectChildren); 146263509Sdim } 147263509Sdim}; 148263509Sdim 149263509Sdim// Special DiagnosticConsumer that looks for warn_drv_input_file_unused 150263509Sdim// diagnostics from the driver and collects the option strings for those unused 151263509Sdim// options. 152263509Sdimclass UnusedInputDiagConsumer : public DiagnosticConsumer { 153263509Sdimpublic: 154263509Sdim UnusedInputDiagConsumer() : Other(0) {} 155263509Sdim 156263509Sdim // Useful for debugging, chain diagnostics to another consumer after 157263509Sdim // recording for our own purposes. 158263509Sdim UnusedInputDiagConsumer(DiagnosticConsumer *Other) : Other(Other) {} 159263509Sdim 160263509Sdim virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, 161263509Sdim const Diagnostic &Info) LLVM_OVERRIDE { 162263509Sdim if (Info.getID() == clang::diag::warn_drv_input_file_unused) { 163263509Sdim // Arg 1 for this diagnostic is the option that didn't get used. 164263509Sdim UnusedInputs.push_back(Info.getArgStdStr(0)); 165263509Sdim } 166263509Sdim if (Other) 167263509Sdim Other->HandleDiagnostic(DiagLevel, Info); 168263509Sdim } 169263509Sdim 170263509Sdim DiagnosticConsumer *Other; 171263509Sdim SmallVector<std::string, 2> UnusedInputs; 172263509Sdim}; 173263509Sdim 174263509Sdim// Unary functor for asking "Given a StringRef S1, does there exist a string 175263509Sdim// S2 in Arr where S1 == S2?" 176263509Sdimstruct MatchesAny { 177263509Sdim MatchesAny(ArrayRef<std::string> Arr) : Arr(Arr) {} 178263509Sdim bool operator() (StringRef S) { 179263509Sdim for (const std::string *I = Arr.begin(), *E = Arr.end(); I != E; ++I) 180263509Sdim if (*I == S) 181263509Sdim return true; 182263509Sdim return false; 183263509Sdim } 184263509Sdimprivate: 185263509Sdim ArrayRef<std::string> Arr; 186263509Sdim}; 187263509Sdim 188263509Sdim/// \brief Strips any positional args and possible argv[0] from a command-line 189263509Sdim/// provided by the user to construct a FixedCompilationDatabase. 190263509Sdim/// 191263509Sdim/// FixedCompilationDatabase requires a command line to be in this format as it 192263509Sdim/// constructs the command line for each file by appending the name of the file 193263509Sdim/// to be compiled. FixedCompilationDatabase also adds its own argv[0] to the 194263509Sdim/// start of the command line although its value is not important as it's just 195263509Sdim/// ignored by the Driver invoked by the ClangTool using the 196263509Sdim/// FixedCompilationDatabase. 197263509Sdim/// 198263509Sdim/// FIXME: This functionality should probably be made available by 199263509Sdim/// clang::driver::Driver although what the interface should look like is not 200263509Sdim/// clear. 201263509Sdim/// 202263509Sdim/// \param[in] Args Args as provided by the user. 203263509Sdim/// \return Resulting stripped command line. 204263509Sdim/// \li true if successful. 205263509Sdim/// \li false if \c Args cannot be used for compilation jobs (e.g. 206263509Sdim/// contains an option like -E or -version). 207263509Sdimbool stripPositionalArgs(std::vector<const char *> Args, 208263509Sdim std::vector<std::string> &Result) { 209263509Sdim IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); 210263509Sdim UnusedInputDiagConsumer DiagClient; 211263509Sdim DiagnosticsEngine Diagnostics( 212263509Sdim IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), 213263509Sdim &*DiagOpts, &DiagClient, false); 214263509Sdim 215263509Sdim // Neither clang executable nor default image name are required since the 216263509Sdim // jobs the driver builds will not be executed. 217263509Sdim OwningPtr<driver::Driver> NewDriver(new driver::Driver( 218263509Sdim /* ClangExecutable= */ "", llvm::sys::getDefaultTargetTriple(), 219263509Sdim /* DefaultImageName= */ "", Diagnostics)); 220263509Sdim NewDriver->setCheckInputsExist(false); 221263509Sdim 222263509Sdim // This becomes the new argv[0]. The value is actually not important as it 223263509Sdim // isn't used for invoking Tools. 224263509Sdim Args.insert(Args.begin(), "clang-tool"); 225263509Sdim 226263509Sdim // By adding -c, we force the driver to treat compilation as the last phase. 227263509Sdim // It will then issue warnings via Diagnostics about un-used options that 228263509Sdim // would have been used for linking. If the user provided a compiler name as 229263509Sdim // the original argv[0], this will be treated as a linker input thanks to 230263509Sdim // insertng a new argv[0] above. All un-used options get collected by 231263509Sdim // UnusedInputdiagConsumer and get stripped out later. 232263509Sdim Args.push_back("-c"); 233263509Sdim 234263509Sdim // Put a dummy C++ file on to ensure there's at least one compile job for the 235263509Sdim // driver to construct. If the user specified some other argument that 236263509Sdim // prevents compilation, e.g. -E or something like -version, we may still end 237263509Sdim // up with no jobs but then this is the user's fault. 238263509Sdim Args.push_back("placeholder.cpp"); 239263509Sdim 240263509Sdim const OwningPtr<driver::Compilation> Compilation( 241263509Sdim NewDriver->BuildCompilation(Args)); 242263509Sdim 243263509Sdim const driver::JobList &Jobs = Compilation->getJobs(); 244263509Sdim 245263509Sdim CompileJobAnalyzer CompileAnalyzer; 246263509Sdim 247263509Sdim for (driver::JobList::const_iterator I = Jobs.begin(), E = Jobs.end(); I != E; 248263509Sdim ++I) { 249263509Sdim if ((*I)->getKind() == driver::Job::CommandClass) { 250263509Sdim const driver::Command *Cmd = cast<driver::Command>(*I); 251263509Sdim // Collect only for Assemble jobs. If we do all jobs we get duplicates 252263509Sdim // since Link jobs point to Assemble jobs as inputs. 253263509Sdim if (Cmd->getSource().getKind() == driver::Action::AssembleJobClass) 254263509Sdim CompileAnalyzer.run(&Cmd->getSource()); 255263509Sdim } 256263509Sdim } 257263509Sdim 258263509Sdim if (CompileAnalyzer.Inputs.empty()) { 259263509Sdim // No compile jobs found. 260263509Sdim // FIXME: Emit a warning of some kind? 261263509Sdim return false; 262263509Sdim } 263263509Sdim 264263509Sdim // Remove all compilation input files from the command line. This is 265263509Sdim // necessary so that getCompileCommands() can construct a command line for 266263509Sdim // each file. 267263509Sdim std::vector<const char *>::iterator End = std::remove_if( 268263509Sdim Args.begin(), Args.end(), MatchesAny(CompileAnalyzer.Inputs)); 269263509Sdim 270263509Sdim // Remove all inputs deemed unused for compilation. 271263509Sdim End = std::remove_if(Args.begin(), End, MatchesAny(DiagClient.UnusedInputs)); 272263509Sdim 273263509Sdim // Remove the -c add above as well. It will be at the end right now. 274263509Sdim --End; 275263509Sdim 276263509Sdim Result = std::vector<std::string>(Args.begin() + 1, End); 277263509Sdim return true; 278263509Sdim} 279263509Sdim 280235633SdimFixedCompilationDatabase * 281235633SdimFixedCompilationDatabase::loadFromCommandLine(int &Argc, 282235633Sdim const char **Argv, 283235633Sdim Twine Directory) { 284235633Sdim const char **DoubleDash = std::find(Argv, Argv + Argc, StringRef("--")); 285235633Sdim if (DoubleDash == Argv + Argc) 286235633Sdim return NULL; 287263509Sdim std::vector<const char *> CommandLine(DoubleDash + 1, Argv + Argc); 288235633Sdim Argc = DoubleDash - Argv; 289263509Sdim 290263509Sdim std::vector<std::string> StrippedArgs; 291263509Sdim if (!stripPositionalArgs(CommandLine, StrippedArgs)) 292263509Sdim return 0; 293263509Sdim return new FixedCompilationDatabase(Directory, StrippedArgs); 294235633Sdim} 295235633Sdim 296235633SdimFixedCompilationDatabase:: 297235633SdimFixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) { 298235633Sdim std::vector<std::string> ToolCommandLine(1, "clang-tool"); 299235633Sdim ToolCommandLine.insert(ToolCommandLine.end(), 300235633Sdim CommandLine.begin(), CommandLine.end()); 301235633Sdim CompileCommands.push_back(CompileCommand(Directory, ToolCommandLine)); 302235633Sdim} 303235633Sdim 304235633Sdimstd::vector<CompileCommand> 305235633SdimFixedCompilationDatabase::getCompileCommands(StringRef FilePath) const { 306235633Sdim std::vector<CompileCommand> Result(CompileCommands); 307235633Sdim Result[0].CommandLine.push_back(FilePath); 308235633Sdim return Result; 309235633Sdim} 310235633Sdim 311245431Sdimstd::vector<std::string> 312245431SdimFixedCompilationDatabase::getAllFiles() const { 313245431Sdim return std::vector<std::string>(); 314234287Sdim} 315234287Sdim 316252723Sdimstd::vector<CompileCommand> 317252723SdimFixedCompilationDatabase::getAllCompileCommands() const { 318252723Sdim return std::vector<CompileCommand>(); 319252723Sdim} 320252723Sdim 321245431Sdim// This anchor is used to force the linker to link in the generated object file 322245431Sdim// and thus register the JSONCompilationDatabasePlugin. 323245431Sdimextern volatile int JSONAnchorSource; 324245431Sdimstatic int JSONAnchorDest = JSONAnchorSource; 325234287Sdim 326234287Sdim} // end namespace tooling 327234287Sdim} // end namespace clang 328