CompilationDatabase.cpp revision 55fc873017f10f6f566b182b70f6fc22aefa3464
1//===--- CompilationDatabase.cpp - ----------------------------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file contains implementations of the CompilationDatabase base class
11//  and the FixedCompilationDatabase.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/Tooling/CompilationDatabase.h"
16#include "clang/Tooling/CompilationDatabasePluginRegistry.h"
17#include "clang/Tooling/Tooling.h"
18#include "llvm/ADT/SmallString.h"
19#include "llvm/Support/Path.h"
20#include "llvm/Support/system_error.h"
21#include <sstream>
22
23namespace clang {
24namespace tooling {
25
26CompilationDatabase::~CompilationDatabase() {}
27
28CompilationDatabase *
29CompilationDatabase::loadFromDirectory(StringRef BuildDirectory,
30                                       std::string &ErrorMessage) {
31  std::stringstream ErrorStream;
32  for (CompilationDatabasePluginRegistry::iterator
33       It = CompilationDatabasePluginRegistry::begin(),
34       Ie = CompilationDatabasePluginRegistry::end();
35       It != Ie; ++It) {
36    std::string DatabaseErrorMessage;
37    OwningPtr<CompilationDatabasePlugin> Plugin(It->instantiate());
38    if (CompilationDatabase *DB =
39        Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage))
40      return DB;
41    else
42      ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n";
43  }
44  ErrorMessage = ErrorStream.str();
45  return NULL;
46}
47
48static CompilationDatabase *
49findCompilationDatabaseFromDirectory(StringRef Directory,
50                                     std::string &ErrorMessage) {
51  std::stringstream ErrorStream;
52  bool HasErrorMessage = false;
53  while (!Directory.empty()) {
54    std::string LoadErrorMessage;
55
56    if (CompilationDatabase *DB =
57           CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage))
58      return DB;
59
60    if (!HasErrorMessage) {
61      ErrorStream << "No compilation database found in " << Directory.str()
62                  << " or any parent directory\n" << LoadErrorMessage;
63      HasErrorMessage = true;
64    }
65
66    Directory = llvm::sys::path::parent_path(Directory);
67  }
68  ErrorMessage = ErrorStream.str();
69  return NULL;
70}
71
72CompilationDatabase *
73CompilationDatabase::autoDetectFromSource(StringRef SourceFile,
74                                          std::string &ErrorMessage) {
75  llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile));
76  StringRef Directory = llvm::sys::path::parent_path(AbsolutePath);
77
78  CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory,
79                                                                 ErrorMessage);
80
81  if (!DB)
82    ErrorMessage = ("Could not auto-detect compilation database for file \"" +
83                   SourceFile + "\"\n" + ErrorMessage).str();
84  return DB;
85}
86
87CompilationDatabase *
88CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir,
89                                             std::string &ErrorMessage) {
90  llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir));
91
92  CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath,
93                                                                 ErrorMessage);
94
95  if (!DB)
96    ErrorMessage = ("Could not auto-detect compilation database from directory \"" +
97                   SourceDir + "\"\n" + ErrorMessage).str();
98  return DB;
99}
100
101CompilationDatabasePlugin::~CompilationDatabasePlugin() {}
102
103FixedCompilationDatabase *
104FixedCompilationDatabase::loadFromCommandLine(int &Argc,
105                                              const char **Argv,
106                                              Twine Directory) {
107  const char **DoubleDash = std::find(Argv, Argv + Argc, StringRef("--"));
108  if (DoubleDash == Argv + Argc)
109    return NULL;
110  std::vector<std::string> CommandLine(DoubleDash + 1, Argv + Argc);
111  Argc = DoubleDash - Argv;
112  return new FixedCompilationDatabase(Directory, CommandLine);
113}
114
115FixedCompilationDatabase::
116FixedCompilationDatabase(Twine Directory, ArrayRef<std::string> CommandLine) {
117  std::vector<std::string> ToolCommandLine(1, "clang-tool");
118  ToolCommandLine.insert(ToolCommandLine.end(),
119                         CommandLine.begin(), CommandLine.end());
120  CompileCommands.push_back(CompileCommand(Directory, ToolCommandLine));
121}
122
123std::vector<CompileCommand>
124FixedCompilationDatabase::getCompileCommands(StringRef FilePath) const {
125  std::vector<CompileCommand> Result(CompileCommands);
126  Result[0].CommandLine.push_back(FilePath);
127  return Result;
128}
129
130std::vector<std::string>
131FixedCompilationDatabase::getAllFiles() const {
132  return std::vector<std::string>();
133}
134
135std::vector<CompileCommand>
136FixedCompilationDatabase::getAllCompileCommands() const {
137  return std::vector<CompileCommand>();
138}
139
140// This anchor is used to force the linker to link in the generated object file
141// and thus register the JSONCompilationDatabasePlugin.
142extern volatile int JSONAnchorSource;
143static int JSONAnchorDest = JSONAnchorSource;
144
145} // end namespace tooling
146} // end namespace clang
147