1*67e74705SXin Li //===--- JSONCompilationDatabase.cpp - ------------------------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // This file contains the implementation of the JSONCompilationDatabase.
11*67e74705SXin Li //
12*67e74705SXin Li //===----------------------------------------------------------------------===//
13*67e74705SXin Li
14*67e74705SXin Li #include "clang/Tooling/JSONCompilationDatabase.h"
15*67e74705SXin Li #include "clang/Tooling/CompilationDatabase.h"
16*67e74705SXin Li #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
17*67e74705SXin Li #include "clang/Tooling/Tooling.h"
18*67e74705SXin Li #include "llvm/ADT/SmallString.h"
19*67e74705SXin Li #include "llvm/Support/Path.h"
20*67e74705SXin Li #include <system_error>
21*67e74705SXin Li
22*67e74705SXin Li namespace clang {
23*67e74705SXin Li namespace tooling {
24*67e74705SXin Li
25*67e74705SXin Li namespace {
26*67e74705SXin Li
27*67e74705SXin Li /// \brief A parser for escaped strings of command line arguments.
28*67e74705SXin Li ///
29*67e74705SXin Li /// Assumes \-escaping for quoted arguments (see the documentation of
30*67e74705SXin Li /// unescapeCommandLine(...)).
31*67e74705SXin Li class CommandLineArgumentParser {
32*67e74705SXin Li public:
CommandLineArgumentParser(StringRef CommandLine)33*67e74705SXin Li CommandLineArgumentParser(StringRef CommandLine)
34*67e74705SXin Li : Input(CommandLine), Position(Input.begin()-1) {}
35*67e74705SXin Li
parse()36*67e74705SXin Li std::vector<std::string> parse() {
37*67e74705SXin Li bool HasMoreInput = true;
38*67e74705SXin Li while (HasMoreInput && nextNonWhitespace()) {
39*67e74705SXin Li std::string Argument;
40*67e74705SXin Li HasMoreInput = parseStringInto(Argument);
41*67e74705SXin Li CommandLine.push_back(Argument);
42*67e74705SXin Li }
43*67e74705SXin Li return CommandLine;
44*67e74705SXin Li }
45*67e74705SXin Li
46*67e74705SXin Li private:
47*67e74705SXin Li // All private methods return true if there is more input available.
48*67e74705SXin Li
parseStringInto(std::string & String)49*67e74705SXin Li bool parseStringInto(std::string &String) {
50*67e74705SXin Li do {
51*67e74705SXin Li if (*Position == '"') {
52*67e74705SXin Li if (!parseDoubleQuotedStringInto(String)) return false;
53*67e74705SXin Li } else if (*Position == '\'') {
54*67e74705SXin Li if (!parseSingleQuotedStringInto(String)) return false;
55*67e74705SXin Li } else {
56*67e74705SXin Li if (!parseFreeStringInto(String)) return false;
57*67e74705SXin Li }
58*67e74705SXin Li } while (*Position != ' ');
59*67e74705SXin Li return true;
60*67e74705SXin Li }
61*67e74705SXin Li
parseDoubleQuotedStringInto(std::string & String)62*67e74705SXin Li bool parseDoubleQuotedStringInto(std::string &String) {
63*67e74705SXin Li if (!next()) return false;
64*67e74705SXin Li while (*Position != '"') {
65*67e74705SXin Li if (!skipEscapeCharacter()) return false;
66*67e74705SXin Li String.push_back(*Position);
67*67e74705SXin Li if (!next()) return false;
68*67e74705SXin Li }
69*67e74705SXin Li return next();
70*67e74705SXin Li }
71*67e74705SXin Li
parseSingleQuotedStringInto(std::string & String)72*67e74705SXin Li bool parseSingleQuotedStringInto(std::string &String) {
73*67e74705SXin Li if (!next()) return false;
74*67e74705SXin Li while (*Position != '\'') {
75*67e74705SXin Li String.push_back(*Position);
76*67e74705SXin Li if (!next()) return false;
77*67e74705SXin Li }
78*67e74705SXin Li return next();
79*67e74705SXin Li }
80*67e74705SXin Li
parseFreeStringInto(std::string & String)81*67e74705SXin Li bool parseFreeStringInto(std::string &String) {
82*67e74705SXin Li do {
83*67e74705SXin Li if (!skipEscapeCharacter()) return false;
84*67e74705SXin Li String.push_back(*Position);
85*67e74705SXin Li if (!next()) return false;
86*67e74705SXin Li } while (*Position != ' ' && *Position != '"' && *Position != '\'');
87*67e74705SXin Li return true;
88*67e74705SXin Li }
89*67e74705SXin Li
skipEscapeCharacter()90*67e74705SXin Li bool skipEscapeCharacter() {
91*67e74705SXin Li if (*Position == '\\') {
92*67e74705SXin Li return next();
93*67e74705SXin Li }
94*67e74705SXin Li return true;
95*67e74705SXin Li }
96*67e74705SXin Li
nextNonWhitespace()97*67e74705SXin Li bool nextNonWhitespace() {
98*67e74705SXin Li do {
99*67e74705SXin Li if (!next()) return false;
100*67e74705SXin Li } while (*Position == ' ');
101*67e74705SXin Li return true;
102*67e74705SXin Li }
103*67e74705SXin Li
next()104*67e74705SXin Li bool next() {
105*67e74705SXin Li ++Position;
106*67e74705SXin Li return Position != Input.end();
107*67e74705SXin Li }
108*67e74705SXin Li
109*67e74705SXin Li const StringRef Input;
110*67e74705SXin Li StringRef::iterator Position;
111*67e74705SXin Li std::vector<std::string> CommandLine;
112*67e74705SXin Li };
113*67e74705SXin Li
unescapeCommandLine(StringRef EscapedCommandLine)114*67e74705SXin Li std::vector<std::string> unescapeCommandLine(
115*67e74705SXin Li StringRef EscapedCommandLine) {
116*67e74705SXin Li CommandLineArgumentParser parser(EscapedCommandLine);
117*67e74705SXin Li return parser.parse();
118*67e74705SXin Li }
119*67e74705SXin Li
120*67e74705SXin Li class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
121*67e74705SXin Li std::unique_ptr<CompilationDatabase>
loadFromDirectory(StringRef Directory,std::string & ErrorMessage)122*67e74705SXin Li loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
123*67e74705SXin Li SmallString<1024> JSONDatabasePath(Directory);
124*67e74705SXin Li llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
125*67e74705SXin Li std::unique_ptr<CompilationDatabase> Database(
126*67e74705SXin Li JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage));
127*67e74705SXin Li if (!Database)
128*67e74705SXin Li return nullptr;
129*67e74705SXin Li return Database;
130*67e74705SXin Li }
131*67e74705SXin Li };
132*67e74705SXin Li
133*67e74705SXin Li } // end namespace
134*67e74705SXin Li
135*67e74705SXin Li // Register the JSONCompilationDatabasePlugin with the
136*67e74705SXin Li // CompilationDatabasePluginRegistry using this statically initialized variable.
137*67e74705SXin Li static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
138*67e74705SXin Li X("json-compilation-database", "Reads JSON formatted compilation databases");
139*67e74705SXin Li
140*67e74705SXin Li // This anchor is used to force the linker to link in the generated object file
141*67e74705SXin Li // and thus register the JSONCompilationDatabasePlugin.
142*67e74705SXin Li volatile int JSONAnchorSource = 0;
143*67e74705SXin Li
144*67e74705SXin Li std::unique_ptr<JSONCompilationDatabase>
loadFromFile(StringRef FilePath,std::string & ErrorMessage)145*67e74705SXin Li JSONCompilationDatabase::loadFromFile(StringRef FilePath,
146*67e74705SXin Li std::string &ErrorMessage) {
147*67e74705SXin Li llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
148*67e74705SXin Li llvm::MemoryBuffer::getFile(FilePath);
149*67e74705SXin Li if (std::error_code Result = DatabaseBuffer.getError()) {
150*67e74705SXin Li ErrorMessage = "Error while opening JSON database: " + Result.message();
151*67e74705SXin Li return nullptr;
152*67e74705SXin Li }
153*67e74705SXin Li std::unique_ptr<JSONCompilationDatabase> Database(
154*67e74705SXin Li new JSONCompilationDatabase(std::move(*DatabaseBuffer)));
155*67e74705SXin Li if (!Database->parse(ErrorMessage))
156*67e74705SXin Li return nullptr;
157*67e74705SXin Li return Database;
158*67e74705SXin Li }
159*67e74705SXin Li
160*67e74705SXin Li std::unique_ptr<JSONCompilationDatabase>
loadFromBuffer(StringRef DatabaseString,std::string & ErrorMessage)161*67e74705SXin Li JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
162*67e74705SXin Li std::string &ErrorMessage) {
163*67e74705SXin Li std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
164*67e74705SXin Li llvm::MemoryBuffer::getMemBuffer(DatabaseString));
165*67e74705SXin Li std::unique_ptr<JSONCompilationDatabase> Database(
166*67e74705SXin Li new JSONCompilationDatabase(std::move(DatabaseBuffer)));
167*67e74705SXin Li if (!Database->parse(ErrorMessage))
168*67e74705SXin Li return nullptr;
169*67e74705SXin Li return Database;
170*67e74705SXin Li }
171*67e74705SXin Li
172*67e74705SXin Li std::vector<CompileCommand>
getCompileCommands(StringRef FilePath) const173*67e74705SXin Li JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
174*67e74705SXin Li SmallString<128> NativeFilePath;
175*67e74705SXin Li llvm::sys::path::native(FilePath, NativeFilePath);
176*67e74705SXin Li
177*67e74705SXin Li std::string Error;
178*67e74705SXin Li llvm::raw_string_ostream ES(Error);
179*67e74705SXin Li StringRef Match = MatchTrie.findEquivalent(NativeFilePath, ES);
180*67e74705SXin Li if (Match.empty())
181*67e74705SXin Li return std::vector<CompileCommand>();
182*67e74705SXin Li llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
183*67e74705SXin Li CommandsRefI = IndexByFile.find(Match);
184*67e74705SXin Li if (CommandsRefI == IndexByFile.end())
185*67e74705SXin Li return std::vector<CompileCommand>();
186*67e74705SXin Li std::vector<CompileCommand> Commands;
187*67e74705SXin Li getCommands(CommandsRefI->getValue(), Commands);
188*67e74705SXin Li return Commands;
189*67e74705SXin Li }
190*67e74705SXin Li
191*67e74705SXin Li std::vector<std::string>
getAllFiles() const192*67e74705SXin Li JSONCompilationDatabase::getAllFiles() const {
193*67e74705SXin Li std::vector<std::string> Result;
194*67e74705SXin Li
195*67e74705SXin Li llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
196*67e74705SXin Li CommandsRefI = IndexByFile.begin();
197*67e74705SXin Li const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
198*67e74705SXin Li CommandsRefEnd = IndexByFile.end();
199*67e74705SXin Li for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
200*67e74705SXin Li Result.push_back(CommandsRefI->first().str());
201*67e74705SXin Li }
202*67e74705SXin Li
203*67e74705SXin Li return Result;
204*67e74705SXin Li }
205*67e74705SXin Li
206*67e74705SXin Li std::vector<CompileCommand>
getAllCompileCommands() const207*67e74705SXin Li JSONCompilationDatabase::getAllCompileCommands() const {
208*67e74705SXin Li std::vector<CompileCommand> Commands;
209*67e74705SXin Li getCommands(AllCommands, Commands);
210*67e74705SXin Li return Commands;
211*67e74705SXin Li }
212*67e74705SXin Li
213*67e74705SXin Li static std::vector<std::string>
nodeToCommandLine(const std::vector<llvm::yaml::ScalarNode * > & Nodes)214*67e74705SXin Li nodeToCommandLine(const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
215*67e74705SXin Li SmallString<1024> Storage;
216*67e74705SXin Li if (Nodes.size() == 1) {
217*67e74705SXin Li return unescapeCommandLine(Nodes[0]->getValue(Storage));
218*67e74705SXin Li }
219*67e74705SXin Li std::vector<std::string> Arguments;
220*67e74705SXin Li for (auto *Node : Nodes) {
221*67e74705SXin Li Arguments.push_back(Node->getValue(Storage));
222*67e74705SXin Li }
223*67e74705SXin Li return Arguments;
224*67e74705SXin Li }
225*67e74705SXin Li
getCommands(ArrayRef<CompileCommandRef> CommandsRef,std::vector<CompileCommand> & Commands) const226*67e74705SXin Li void JSONCompilationDatabase::getCommands(
227*67e74705SXin Li ArrayRef<CompileCommandRef> CommandsRef,
228*67e74705SXin Li std::vector<CompileCommand> &Commands) const {
229*67e74705SXin Li for (int I = 0, E = CommandsRef.size(); I != E; ++I) {
230*67e74705SXin Li SmallString<8> DirectoryStorage;
231*67e74705SXin Li SmallString<32> FilenameStorage;
232*67e74705SXin Li Commands.emplace_back(
233*67e74705SXin Li std::get<0>(CommandsRef[I])->getValue(DirectoryStorage),
234*67e74705SXin Li std::get<1>(CommandsRef[I])->getValue(FilenameStorage),
235*67e74705SXin Li nodeToCommandLine(std::get<2>(CommandsRef[I])));
236*67e74705SXin Li }
237*67e74705SXin Li }
238*67e74705SXin Li
parse(std::string & ErrorMessage)239*67e74705SXin Li bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
240*67e74705SXin Li llvm::yaml::document_iterator I = YAMLStream.begin();
241*67e74705SXin Li if (I == YAMLStream.end()) {
242*67e74705SXin Li ErrorMessage = "Error while parsing YAML.";
243*67e74705SXin Li return false;
244*67e74705SXin Li }
245*67e74705SXin Li llvm::yaml::Node *Root = I->getRoot();
246*67e74705SXin Li if (!Root) {
247*67e74705SXin Li ErrorMessage = "Error while parsing YAML.";
248*67e74705SXin Li return false;
249*67e74705SXin Li }
250*67e74705SXin Li llvm::yaml::SequenceNode *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
251*67e74705SXin Li if (!Array) {
252*67e74705SXin Li ErrorMessage = "Expected array.";
253*67e74705SXin Li return false;
254*67e74705SXin Li }
255*67e74705SXin Li for (auto& NextObject : *Array) {
256*67e74705SXin Li llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
257*67e74705SXin Li if (!Object) {
258*67e74705SXin Li ErrorMessage = "Expected object.";
259*67e74705SXin Li return false;
260*67e74705SXin Li }
261*67e74705SXin Li llvm::yaml::ScalarNode *Directory = nullptr;
262*67e74705SXin Li llvm::Optional<std::vector<llvm::yaml::ScalarNode *>> Command;
263*67e74705SXin Li llvm::yaml::ScalarNode *File = nullptr;
264*67e74705SXin Li for (auto& NextKeyValue : *Object) {
265*67e74705SXin Li llvm::yaml::ScalarNode *KeyString =
266*67e74705SXin Li dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
267*67e74705SXin Li if (!KeyString) {
268*67e74705SXin Li ErrorMessage = "Expected strings as key.";
269*67e74705SXin Li return false;
270*67e74705SXin Li }
271*67e74705SXin Li SmallString<10> KeyStorage;
272*67e74705SXin Li StringRef KeyValue = KeyString->getValue(KeyStorage);
273*67e74705SXin Li llvm::yaml::Node *Value = NextKeyValue.getValue();
274*67e74705SXin Li if (!Value) {
275*67e74705SXin Li ErrorMessage = "Expected value.";
276*67e74705SXin Li return false;
277*67e74705SXin Li }
278*67e74705SXin Li llvm::yaml::ScalarNode *ValueString =
279*67e74705SXin Li dyn_cast<llvm::yaml::ScalarNode>(Value);
280*67e74705SXin Li llvm::yaml::SequenceNode *SequenceString =
281*67e74705SXin Li dyn_cast<llvm::yaml::SequenceNode>(Value);
282*67e74705SXin Li if (KeyValue == "arguments" && !SequenceString) {
283*67e74705SXin Li ErrorMessage = "Expected sequence as value.";
284*67e74705SXin Li return false;
285*67e74705SXin Li } else if (KeyValue != "arguments" && !ValueString) {
286*67e74705SXin Li ErrorMessage = "Expected string as value.";
287*67e74705SXin Li return false;
288*67e74705SXin Li }
289*67e74705SXin Li if (KeyValue == "directory") {
290*67e74705SXin Li Directory = ValueString;
291*67e74705SXin Li } else if (KeyValue == "arguments") {
292*67e74705SXin Li Command = std::vector<llvm::yaml::ScalarNode *>();
293*67e74705SXin Li for (auto &Argument : *SequenceString) {
294*67e74705SXin Li auto Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
295*67e74705SXin Li if (!Scalar) {
296*67e74705SXin Li ErrorMessage = "Only strings are allowed in 'arguments'.";
297*67e74705SXin Li return false;
298*67e74705SXin Li }
299*67e74705SXin Li Command->push_back(Scalar);
300*67e74705SXin Li }
301*67e74705SXin Li } else if (KeyValue == "command") {
302*67e74705SXin Li if (!Command)
303*67e74705SXin Li Command = std::vector<llvm::yaml::ScalarNode *>(1, ValueString);
304*67e74705SXin Li } else if (KeyValue == "file") {
305*67e74705SXin Li File = ValueString;
306*67e74705SXin Li } else {
307*67e74705SXin Li ErrorMessage = ("Unknown key: \"" +
308*67e74705SXin Li KeyString->getRawValue() + "\"").str();
309*67e74705SXin Li return false;
310*67e74705SXin Li }
311*67e74705SXin Li }
312*67e74705SXin Li if (!File) {
313*67e74705SXin Li ErrorMessage = "Missing key: \"file\".";
314*67e74705SXin Li return false;
315*67e74705SXin Li }
316*67e74705SXin Li if (!Command) {
317*67e74705SXin Li ErrorMessage = "Missing key: \"command\" or \"arguments\".";
318*67e74705SXin Li return false;
319*67e74705SXin Li }
320*67e74705SXin Li if (!Directory) {
321*67e74705SXin Li ErrorMessage = "Missing key: \"directory\".";
322*67e74705SXin Li return false;
323*67e74705SXin Li }
324*67e74705SXin Li SmallString<8> FileStorage;
325*67e74705SXin Li StringRef FileName = File->getValue(FileStorage);
326*67e74705SXin Li SmallString<128> NativeFilePath;
327*67e74705SXin Li if (llvm::sys::path::is_relative(FileName)) {
328*67e74705SXin Li SmallString<8> DirectoryStorage;
329*67e74705SXin Li SmallString<128> AbsolutePath(
330*67e74705SXin Li Directory->getValue(DirectoryStorage));
331*67e74705SXin Li llvm::sys::path::append(AbsolutePath, FileName);
332*67e74705SXin Li llvm::sys::path::native(AbsolutePath, NativeFilePath);
333*67e74705SXin Li } else {
334*67e74705SXin Li llvm::sys::path::native(FileName, NativeFilePath);
335*67e74705SXin Li }
336*67e74705SXin Li auto Cmd = CompileCommandRef(Directory, File, *Command);
337*67e74705SXin Li IndexByFile[NativeFilePath].push_back(Cmd);
338*67e74705SXin Li AllCommands.push_back(Cmd);
339*67e74705SXin Li MatchTrie.insert(NativeFilePath);
340*67e74705SXin Li }
341*67e74705SXin Li return true;
342*67e74705SXin Li }
343*67e74705SXin Li
344*67e74705SXin Li } // end namespace tooling
345*67e74705SXin Li } // end namespace clang
346