JSONCompilationDatabase.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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 <system_error>
  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. CompilationDatabase *loadFromDirectory(StringRef Directory,
  106. std::string &ErrorMessage) override {
  107. SmallString<1024> JSONDatabasePath(Directory);
  108. llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
  109. std::unique_ptr<CompilationDatabase> Database(
  110. JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
  111. if (!Database)
  112. return nullptr;
  113. return Database.release();
  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. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
  128. llvm::MemoryBuffer::getFile(FilePath);
  129. if (std::error_code Result = DatabaseBuffer.getError()) {
  130. ErrorMessage = "Error while opening JSON database: " + Result.message();
  131. return nullptr;
  132. }
  133. std::unique_ptr<JSONCompilationDatabase> Database(
  134. new JSONCompilationDatabase(DatabaseBuffer->release()));
  135. if (!Database->parse(ErrorMessage))
  136. return nullptr;
  137. return Database.release();
  138. }
  139. JSONCompilationDatabase *
  140. JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
  141. std::string &ErrorMessage) {
  142. std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
  143. llvm::MemoryBuffer::getMemBuffer(DatabaseString));
  144. std::unique_ptr<JSONCompilationDatabase> Database(
  145. new JSONCompilationDatabase(DatabaseBuffer.release()));
  146. if (!Database->parse(ErrorMessage))
  147. return nullptr;
  148. return Database.release();
  149. }
  150. std::vector<CompileCommand>
  151. JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
  152. SmallString<128> NativeFilePath;
  153. llvm::sys::path::native(FilePath, NativeFilePath);
  154. std::string Error;
  155. llvm::raw_string_ostream ES(Error);
  156. StringRef Match = MatchTrie.findEquivalent(NativeFilePath.str(), ES);
  157. if (Match.empty())
  158. return std::vector<CompileCommand>();
  159. llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
  160. CommandsRefI = IndexByFile.find(Match);
  161. if (CommandsRefI == IndexByFile.end())
  162. return std::vector<CompileCommand>();
  163. std::vector<CompileCommand> Commands;
  164. getCommands(CommandsRefI->getValue(), Commands);
  165. return Commands;
  166. }
  167. std::vector<std::string>
  168. JSONCompilationDatabase::getAllFiles() const {
  169. std::vector<std::string> Result;
  170. llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
  171. CommandsRefI = IndexByFile.begin();
  172. const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
  173. CommandsRefEnd = IndexByFile.end();
  174. for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
  175. Result.push_back(CommandsRefI->first().str());
  176. }
  177. return Result;
  178. }
  179. std::vector<CompileCommand>
  180. JSONCompilationDatabase::getAllCompileCommands() const {
  181. std::vector<CompileCommand> Commands;
  182. for (llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
  183. CommandsRefI = IndexByFile.begin(), CommandsRefEnd = IndexByFile.end();
  184. CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
  185. getCommands(CommandsRefI->getValue(), Commands);
  186. }
  187. return Commands;
  188. }
  189. void JSONCompilationDatabase::getCommands(
  190. ArrayRef<CompileCommandRef> CommandsRef,
  191. std::vector<CompileCommand> &Commands) const {
  192. for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
  193. SmallString<8> DirectoryStorage;
  194. SmallString<1024> CommandStorage;
  195. Commands.push_back(CompileCommand(
  196. // FIXME: Escape correctly:
  197. CommandsRef[I].first->getValue(DirectoryStorage),
  198. unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))));
  199. }
  200. }
  201. bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
  202. llvm::yaml::document_iterator I = YAMLStream.begin();
  203. if (I == YAMLStream.end()) {
  204. ErrorMessage = "Error while parsing YAML.";
  205. return false;
  206. }
  207. llvm::yaml::Node *Root = I->getRoot();
  208. if (!Root) {
  209. ErrorMessage = "Error while parsing YAML.";
  210. return false;
  211. }
  212. llvm::yaml::SequenceNode *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
  213. if (!Array) {
  214. ErrorMessage = "Expected array.";
  215. return false;
  216. }
  217. for (llvm::yaml::SequenceNode::iterator AI = Array->begin(),
  218. AE = Array->end();
  219. AI != AE; ++AI) {
  220. llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&*AI);
  221. if (!Object) {
  222. ErrorMessage = "Expected object.";
  223. return false;
  224. }
  225. llvm::yaml::ScalarNode *Directory = nullptr;
  226. llvm::yaml::ScalarNode *Command = nullptr;
  227. llvm::yaml::ScalarNode *File = nullptr;
  228. for (llvm::yaml::MappingNode::iterator KVI = Object->begin(),
  229. KVE = Object->end();
  230. KVI != KVE; ++KVI) {
  231. llvm::yaml::Node *Value = (*KVI).getValue();
  232. if (!Value) {
  233. ErrorMessage = "Expected value.";
  234. return false;
  235. }
  236. llvm::yaml::ScalarNode *ValueString =
  237. dyn_cast<llvm::yaml::ScalarNode>(Value);
  238. if (!ValueString) {
  239. ErrorMessage = "Expected string as value.";
  240. return false;
  241. }
  242. llvm::yaml::ScalarNode *KeyString =
  243. dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey());
  244. if (!KeyString) {
  245. ErrorMessage = "Expected strings as key.";
  246. return false;
  247. }
  248. SmallString<8> KeyStorage;
  249. if (KeyString->getValue(KeyStorage) == "directory") {
  250. Directory = ValueString;
  251. } else if (KeyString->getValue(KeyStorage) == "command") {
  252. Command = ValueString;
  253. } else if (KeyString->getValue(KeyStorage) == "file") {
  254. File = ValueString;
  255. } else {
  256. ErrorMessage = ("Unknown key: \"" +
  257. KeyString->getRawValue() + "\"").str();
  258. return false;
  259. }
  260. }
  261. if (!File) {
  262. ErrorMessage = "Missing key: \"file\".";
  263. return false;
  264. }
  265. if (!Command) {
  266. ErrorMessage = "Missing key: \"command\".";
  267. return false;
  268. }
  269. if (!Directory) {
  270. ErrorMessage = "Missing key: \"directory\".";
  271. return false;
  272. }
  273. SmallString<8> FileStorage;
  274. StringRef FileName = File->getValue(FileStorage);
  275. SmallString<128> NativeFilePath;
  276. if (llvm::sys::path::is_relative(FileName)) {
  277. SmallString<8> DirectoryStorage;
  278. SmallString<128> AbsolutePath(
  279. Directory->getValue(DirectoryStorage));
  280. llvm::sys::path::append(AbsolutePath, FileName);
  281. llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
  282. } else {
  283. llvm::sys::path::native(FileName, NativeFilePath);
  284. }
  285. IndexByFile[NativeFilePath].push_back(
  286. CompileCommandRef(Directory, Command));
  287. MatchTrie.insert(NativeFilePath.str());
  288. }
  289. return true;
  290. }
  291. } // end namespace tooling
  292. } // end namespace clang