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"
21*3a02247dSChandler Carruth #include <sstream>
2247c245a5SManuel Klimek 
2347c245a5SManuel Klimek namespace clang {
2447c245a5SManuel Klimek namespace tooling {
2547c245a5SManuel Klimek 
2647c245a5SManuel Klimek CompilationDatabase::~CompilationDatabase() {}
2747c245a5SManuel Klimek 
2847c245a5SManuel Klimek CompilationDatabase *
2947c245a5SManuel Klimek CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
3047c245a5SManuel Klimek                                        std::string &ErrorMessage) {
316ed1f85cSDaniel Jasper   std::stringstream ErrorStream;
326ed1f85cSDaniel Jasper   for (CompilationDatabasePluginRegistry::iterator
336ed1f85cSDaniel Jasper        It = CompilationDatabasePluginRegistry::begin(),
346ed1f85cSDaniel Jasper        Ie = CompilationDatabasePluginRegistry::end();
356ed1f85cSDaniel Jasper        It != Ie; ++It) {
366ed1f85cSDaniel Jasper     std::string DatabaseErrorMessage;
376ed1f85cSDaniel Jasper     OwningPtr<CompilationDatabasePlugin> Plugin(It->instantiate());
386ed1f85cSDaniel Jasper     if (CompilationDatabase *DB =
396ed1f85cSDaniel Jasper         Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
406ed1f85cSDaniel Jasper       return DB;
416ed1f85cSDaniel Jasper     else
426ed1f85cSDaniel Jasper       ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
4347c245a5SManuel Klimek   }
446ed1f85cSDaniel Jasper   ErrorMessage = ErrorStream.str();
456ed1f85cSDaniel Jasper   return NULL;
4647c245a5SManuel Klimek }
4747c245a5SManuel Klimek 
48617f5269SArnaud A. de Grandmaison static CompilationDatabase *
496ed1f85cSDaniel Jasper findCompilationDatabaseFromDirectory(StringRef Directory,
506ed1f85cSDaniel Jasper                                      std::string &ErrorMessage) {
516ed1f85cSDaniel Jasper   std::stringstream ErrorStream;
5274351ff4SDaniel Jasper   bool HasErrorMessage = false;
53617f5269SArnaud A. de Grandmaison   while (!Directory.empty()) {
54617f5269SArnaud A. de Grandmaison     std::string LoadErrorMessage;
55617f5269SArnaud A. de Grandmaison 
56617f5269SArnaud A. de Grandmaison     if (CompilationDatabase *DB =
57617f5269SArnaud A. de Grandmaison            CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
58617f5269SArnaud A. de Grandmaison       return DB;
5974351ff4SDaniel Jasper 
6074351ff4SDaniel Jasper     if (!HasErrorMessage) {
616ed1f85cSDaniel Jasper       ErrorStream << "No compilation database found in " << Directory.str()
6274351ff4SDaniel Jasper                   << " or any parent directory\n" << LoadErrorMessage;
6374351ff4SDaniel Jasper       HasErrorMessage = true;
6474351ff4SDaniel Jasper     }
65617f5269SArnaud A. de Grandmaison 
66617f5269SArnaud A. de Grandmaison     Directory = llvm::sys::path::parent_path(Directory);
67617f5269SArnaud A. de Grandmaison   }
686ed1f85cSDaniel Jasper   ErrorMessage = ErrorStream.str();
69617f5269SArnaud A. de Grandmaison   return NULL;
70617f5269SArnaud A. de Grandmaison }
71617f5269SArnaud A. de Grandmaison 
7265fd0e1fSManuel Klimek CompilationDatabase *
7365fd0e1fSManuel Klimek CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
7465fd0e1fSManuel Klimek                                           std::string &ErrorMessage) {
7565fd0e1fSManuel Klimek   llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
7665fd0e1fSManuel Klimek   StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
77617f5269SArnaud A. de Grandmaison 
786ed1f85cSDaniel Jasper   CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory,
796ed1f85cSDaniel Jasper                                                                  ErrorMessage);
80617f5269SArnaud A. de Grandmaison 
81617f5269SArnaud A. de Grandmaison   if (!DB)
8265fd0e1fSManuel Klimek     ErrorMessage = ("Could not auto-detect compilation database for file \"" +
836ed1f85cSDaniel Jasper                    SourceFile + "\"\n" + ErrorMessage).str();
84617f5269SArnaud A. de Grandmaison   return DB;
85617f5269SArnaud A. de Grandmaison }
86617f5269SArnaud A. de Grandmaison 
87617f5269SArnaud A. de Grandmaison CompilationDatabase *
88617f5269SArnaud A. de Grandmaison CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
89617f5269SArnaud A. de Grandmaison                                              std::string &ErrorMessage) {
90617f5269SArnaud A. de Grandmaison   llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
91617f5269SArnaud A. de Grandmaison 
926ed1f85cSDaniel Jasper   CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath,
936ed1f85cSDaniel Jasper                                                                  ErrorMessage);
94617f5269SArnaud A. de Grandmaison 
95617f5269SArnaud A. de Grandmaison   if (!DB)
96617f5269SArnaud A. de Grandmaison     ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
976ed1f85cSDaniel Jasper                    SourceDir + "\"\n" + ErrorMessage).str();
98617f5269SArnaud A. de Grandmaison   return DB;
9965fd0e1fSManuel Klimek }
10065fd0e1fSManuel Klimek 
1016ed1f85cSDaniel Jasper CompilationDatabasePlugin::~CompilationDatabasePlugin() {}
1026ed1f85cSDaniel Jasper 
103ff26efceSManuel Klimek FixedCompilationDatabase *
104ff26efceSManuel Klimek FixedCompilationDatabase::loadFromCommandLine(int &Argc,
105ff26efceSManuel Klimek                                               const char **Argv,
106ff26efceSManuel Klimek                                               Twine Directory) {
107ff26efceSManuel Klimek   const char **DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
108ff26efceSManuel Klimek   if (DoubleDash == Argv + Argc)
109ff26efceSManuel Klimek     return NULL;
110ff26efceSManuel Klimek   std::vector<std::string> CommandLine(DoubleDash + 1, Argv + Argc);
111ff26efceSManuel Klimek   Argc = DoubleDash - Argv;
112ff26efceSManuel Klimek   return new FixedCompilationDatabase(Directory, CommandLine);
113ff26efceSManuel Klimek }
114ff26efceSManuel Klimek 
115ff26efceSManuel Klimek FixedCompilationDatabase::
116ff26efceSManuel Klimek FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) {
117ff26efceSManuel Klimek   std::vector<std::string> ToolCommandLine(1, "clang-tool");
118ff26efceSManuel Klimek   ToolCommandLine.insert(ToolCommandLine.end(),
119ff26efceSManuel Klimek                          CommandLine.begin(), CommandLine.end());
120ff26efceSManuel Klimek   CompileCommands.push_back(CompileCommand(Directory, ToolCommandLine));
121ff26efceSManuel Klimek }
122ff26efceSManuel Klimek 
123ff26efceSManuel Klimek std::vector<CompileCommand>
124ff26efceSManuel Klimek FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
125ff26efceSManuel Klimek   std::vector<CompileCommand> Result(CompileCommands);
126ff26efceSManuel Klimek   Result[0].CommandLine.push_back(FilePath);
127ff26efceSManuel Klimek   return Result;
128ff26efceSManuel Klimek }
129ff26efceSManuel Klimek 
13060b80161SManuel Klimek std::vector<std::string>
13160b80161SManuel Klimek FixedCompilationDatabase::getAllFiles() const {
13260b80161SManuel Klimek   return std::vector<std::string>();
13360b80161SManuel Klimek }
13460b80161SManuel Klimek 
135251ad5e0SArgyrios Kyrtzidis std::vector<CompileCommand>
136251ad5e0SArgyrios Kyrtzidis FixedCompilationDatabase::getAllCompileCommands() const {
137251ad5e0SArgyrios Kyrtzidis   return std::vector<CompileCommand>();
138251ad5e0SArgyrios Kyrtzidis }
139251ad5e0SArgyrios Kyrtzidis 
1406ed1f85cSDaniel Jasper // This anchor is used to force the linker to link in the generated object file
1416ed1f85cSDaniel Jasper // and thus register the JSONCompilationDatabasePlugin.
1426ed1f85cSDaniel Jasper extern volatile int JSONAnchorSource;
1436ed1f85cSDaniel Jasper static int JSONAnchorDest = JSONAnchorSource;
14447c245a5SManuel Klimek 
14547c245a5SManuel Klimek } // end namespace tooling
14647c245a5SManuel Klimek } // end namespace clang
147