JSONCompilationDatabase.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. //===--- JSONCompilationDatabase.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 the implementation of the JSONCompilationDatabase.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "clang/Tooling/JSONCompilationDatabase.h"
  14. #include "clang/Tooling/CompilationDatabase.h"
  15. #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
  16. #include "clang/Tooling/Tooling.h"
  17. #include "llvm/ADT/SmallString.h"
  18. #include "llvm/Support/Path.h"
  19. #include "llvm/Support/system_error.h"
  20. namespace clang {
  21. namespace tooling {
  22. namespace {
  23. /// \brief A parser for escaped strings of command line arguments.
  24. ///
  25. /// Assumes \-escaping for quoted arguments (see the documentation of
  26. /// unescapeCommandLine(...)).
  27. class CommandLineArgumentParser {
  28. public:
  29. CommandLineArgumentParser(StringRef CommandLine)
  30. : Input(CommandLine), Position(Input.begin()-1) {}
  31. std::vector<std::string> parse() {
  32. bool HasMoreInput = true;
  33. while (HasMoreInput && nextNonWhitespace()) {
  34. std::string Argument;
  35. HasMoreInput = parseStringInto(Argument);
  36. CommandLine.push_back(Argument);
  37. }
  38. return CommandLine;
  39. }
  40. private:
  41. // All private methods return true if there is more input available.
  42. bool parseStringInto(std::string &String) {
  43. do {
  44. if (*Position == '"') {
  45. if (!parseDoubleQuotedStringInto(String)) return false;
  46. } else if (*Position == '\'') {
  47. if (!parseSingleQuotedStringInto(String)) return false;
  48. } else {
  49. if (!parseFreeStringInto(String)) return false;
  50. }
  51. } while (*Position != ' ');
  52. return true;
  53. }
  54. bool parseDoubleQuotedStringInto(std::string &String) {
  55. if (!next()) return false;
  56. while (*Position != '"') {
  57. if (!skipEscapeCharacter()) return false;
  58. String.push_back(*Position);
  59. if (!next()) return false;
  60. }
  61. return next();
  62. }
  63. bool parseSingleQuotedStringInto(std::string &String) {
  64. if (!next()) return false;
  65. while (*Position != '\'') {
  66. String.push_back(*Position);
  67. if (!next()) return false;
  68. }
  69. return next();
  70. }
  71. bool parseFreeStringInto(std::string &String) {
  72. do {
  73. if (!skipEscapeCharacter()) return false;
  74. String.push_back(*Position);
  75. if (!next()) return false;
  76. } while (*Position != ' ' && *Position != '"' && *Position != '\'');
  77. return true;
  78. }
  79. bool skipEscapeCharacter() {
  80. if (*Position == '\\') {
  81. return next();
  82. }
  83. return true;
  84. }
  85. bool nextNonWhitespace() {
  86. do {
  87. if (!next()) return false;
  88. } while (*Position == ' ');
  89. return true;
  90. }
  91. bool next() {
  92. ++Position;
  93. return Position != Input.end();
  94. }
  95. const StringRef Input;
  96. StringRef::iterator Position;
  97. std::vector<std::string> CommandLine;
  98. };
  99. std::vector<std::string> unescapeCommandLine(
  100. StringRef EscapedCommandLine) {
  101. CommandLineArgumentParser parser(EscapedCommandLine);
  102. return parser.parse();
  103. }
  104. class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
  105. virtual CompilationDatabase *loadFromDirectory(
  106. StringRef Directory, std::string &ErrorMessage) {
  107. SmallString<1024> JSONDatabasePath(Directory);
  108. llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
  109. OwningPtr<CompilationDatabase> Database(
  110. JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
  111. if (!Database)
  112. return NULL;
  113. return Database.take();
  114. }
  115. };
  116. } // end namespace
  117. // Register the JSONCompilationDatabasePlugin with the
  118. // CompilationDatabasePluginRegistry using this statically initialized variable.
  119. static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
  120. X("json-compilation-database", "Reads JSON formatted compilation databases");
  121. // This anchor is used to force the linker to link in the generated object file
  122. // and thus register the JSONCompilationDatabasePlugin.
  123. volatile int JSONAnchorSource = 0;
  124. JSONCompilationDatabase *
  125. JSONCompilationDatabase::loadFromFile(StringRef FilePath,
  126. std::string &ErrorMessage) {
  127. OwningPtr<llvm::MemoryBuffer> DatabaseBuffer;
  128. llvm::error_code Result =
  129. llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer);
  130. if (Result != 0) {
  131. ErrorMessage = "Error while opening JSON database: " + Result.message();
  132. return NULL;
  133. }
  134. OwningPtr<JSONCompilationDatabase> Database(
  135. new JSONCompilationDatabase(DatabaseBuffer.take()));
  136. if (!Database->parse(ErrorMessage))
  137. return NULL;
  138. return Database.take();
  139. }
  140. JSONCompilationDatabase *
  141. JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
  142. std::string &ErrorMessage) {
  143. OwningPtr<llvm::MemoryBuffer> DatabaseBuffer(
  144. llvm::MemoryBuffer::getMemBuffer(DatabaseString));
  145. OwningPtr<JSONCompilationDatabase> Database(
  146. new JSONCompilationDatabase(DatabaseBuffer.take()));
  147. if (!Database->parse(ErrorMessage))
  148. return NULL;
  149. return Database.take();
  150. }
  151. std::vector<CompileCommand>
  152. JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
  153. SmallString<128> NativeFilePath;
  154. llvm::sys::path::native(FilePath, NativeFilePath);
  155. std::string Error;
  156. llvm::raw_string_ostream ES(Error);
  157. StringRef Match = MatchTrie.findEquivalent(NativeFilePath.str(), ES);
  158. if (Match.empty())
  159. return std::vector<CompileCommand>();
  160. llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
  161. CommandsRefI = IndexByFile.find(Match);
  162. if (CommandsRefI == IndexByFile.end())
  163. return std::vector<CompileCommand>();
  164. std::vector<CompileCommand> Commands;
  165. getCommands(CommandsRefI->getValue(), Commands);
  166. return Commands;
  167. }
  168. std::vector<std::string>
  169. JSONCompilationDatabase::getAllFiles() const {
  170. std::vector<std::string> Result;
  171. llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
  172. CommandsRefI = IndexByFile.begin();
  173. const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
  174. CommandsRefEnd = IndexByFile.end();
  175. for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
  176. Result.push_back(CommandsRefI->first().str());
  177. }
  178. return Result;
  179. }
  180. std::vector<CompileCommand>
  181. JSONCompilationDatabase::getAllCompileCommands() const {
  182. std::vector<CompileCommand> Commands;
  183. for (llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
  184. CommandsRefI = IndexByFile.begin(), CommandsRefEnd = IndexByFile.end();
  185. CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
  186. getCommands(CommandsRefI->getValue(), Commands);
  187. }
  188. return Commands;
  189. }
  190. void JSONCompilationDatabase::getCommands(
  191. ArrayRef<CompileCommandRef> CommandsRef,
  192. std::vector<CompileCommand> &Commands) const {
  193. for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
  194. SmallString<8> DirectoryStorage;
  195. SmallString<1024> CommandStorage;
  196. Commands.push_back(CompileCommand(
  197. // FIXME: Escape correctly:
  198. CommandsRef[I].first->getValue(DirectoryStorage),
  199. unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
  200. }
  201. }
  202. bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
  203. llvm::yaml::document_iterator I = YAMLStream.begin();
  204. if (I == YAMLStream.end()) {
  205. ErrorMessage = "Error while parsing YAML.";
  206. return false;
  207. }
  208. llvm::yaml::Node *Root = I->getRoot();
  209. if (Root == NULL) {
  210. ErrorMessage = "Error while parsing YAML.";
  211. return false;
  212. }
  213. llvm::yaml::SequenceNode *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
  214. if (Array == NULL) {
  215. ErrorMessage = "Expected array.";
  216. return false;
  217. }
  218. for (llvm::yaml::SequenceNode::iterator AI = Array->begin(),
  219. AE = Array->end();
  220. AI != AE; ++AI) {
  221. llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&*AI);
  222. if (Object == NULL) {
  223. ErrorMessage = "Expected object.";
  224. return false;
  225. }
  226. llvm::yaml::ScalarNode *Directory = NULL;
  227. llvm::yaml::ScalarNode *Command = NULL;
  228. llvm::yaml::ScalarNode *File = NULL;
  229. for (llvm::yaml::MappingNode::iterator KVI = Object->begin(),
  230. KVE = Object->end();
  231. KVI != KVE; ++KVI) {
  232. llvm::yaml::Node *Value = (*KVI).getValue();
  233. if (Value == NULL) {
  234. ErrorMessage = "Expected value.";
  235. return false;
  236. }
  237. llvm::yaml::ScalarNode *ValueString =
  238. dyn_cast<llvm::yaml::ScalarNode>(Value);
  239. if (ValueString == NULL) {
  240. ErrorMessage = "Expected string as value.";
  241. return false;
  242. }
  243. llvm::yaml::ScalarNode *KeyString =
  244. dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
  245. if (KeyString == NULL) {
  246. ErrorMessage = "Expected strings as key.";
  247. return false;
  248. }
  249. SmallString<8> KeyStorage;
  250. if (KeyString->getValue(KeyStorage) == "directory") {
  251. Directory = ValueString;
  252. } else if (KeyString->getValue(KeyStorage) == "command") {
  253. Command = ValueString;
  254. } else if (KeyString->getValue(KeyStorage) == "file") {
  255. File = ValueString;
  256. } else {
  257. ErrorMessage = ("Unknown key: \"" +
  258. KeyString->getRawValue() + "\"").str();
  259. return false;
  260. }
  261. }
  262. if (!File) {
  263. ErrorMessage = "Missing key: \"file\".";
  264. return false;
  265. }
  266. if (!Command) {
  267. ErrorMessage = "Missing key: \"command\".";
  268. return false;
  269. }
  270. if (!Directory) {
  271. ErrorMessage = "Missing key: \"directory\".";
  272. return false;
  273. }
  274. SmallString<8> FileStorage;
  275. StringRef FileName = File->getValue(FileStorage);
  276. SmallString<128> NativeFilePath;
  277. if (llvm::sys::path::is_relative(FileName)) {
  278. SmallString<8> DirectoryStorage;
  279. SmallString<128> AbsolutePath(
  280. Directory->getValue(DirectoryStorage));
  281. llvm::sys::path::append(AbsolutePath, FileName);
  282. llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
  283. } else {
  284. llvm::sys::path::native(FileName, NativeFilePath);
  285. }
  286. IndexByFile[NativeFilePath].push_back(
  287. CompileCommandRef(Directory, Command));
  288. MatchTrie.insert(NativeFilePath.str());
  289. }
  290. return true;
  291. }
  292. } // end namespace tooling
  293. } // end namespace clang