18 #include "llvm/ADT/SmallString.h"
19 #include "llvm/Support/Path.h"
20 #include <system_error>
31 class CommandLineArgumentParser {
36 std::vector<std::string> parse() {
37 bool HasMoreInput =
true;
38 while (HasMoreInput && nextNonWhitespace()) {
40 HasMoreInput = parseStringInto(Argument);
49 bool parseStringInto(std::string &String) {
52 if (!parseDoubleQuotedStringInto(String))
return false;
54 if (!parseSingleQuotedStringInto(String))
return false;
56 if (!parseFreeStringInto(String))
return false;
62 bool parseDoubleQuotedStringInto(std::string &String) {
63 if (!next())
return false;
65 if (!skipEscapeCharacter())
return false;
67 if (!next())
return false;
72 bool parseSingleQuotedStringInto(std::string &String) {
73 if (!next())
return false;
76 if (!next())
return false;
81 bool parseFreeStringInto(std::string &String) {
83 if (!skipEscapeCharacter())
return false;
85 if (!next())
return false;
90 bool skipEscapeCharacter() {
97 bool nextNonWhitespace() {
99 if (!next())
return false;
114 std::vector<std::string> unescapeCommandLine(
115 StringRef EscapedCommandLine) {
116 CommandLineArgumentParser parser(EscapedCommandLine);
117 return parser.parse();
120 class JSONCompilationDatabasePlugin :
public CompilationDatabasePlugin {
121 std::unique_ptr<CompilationDatabase>
122 loadFromDirectory(StringRef Directory, std::string &ErrorMessage)
override {
123 SmallString<1024> JSONDatabasePath(Directory);
124 llvm::sys::path::append(JSONDatabasePath,
"compile_commands.json");
125 std::unique_ptr<CompilationDatabase> Database(
137 static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
138 X(
"json-compilation-database",
"Reads JSON formatted compilation databases");
144 std::unique_ptr<JSONCompilationDatabase>
146 std::string &ErrorMessage) {
147 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
148 llvm::MemoryBuffer::getFile(FilePath);
149 if (std::error_code
Result = DatabaseBuffer.getError()) {
150 ErrorMessage =
"Error while opening JSON database: " +
Result.message();
153 std::unique_ptr<JSONCompilationDatabase> Database(
155 if (!Database->parse(ErrorMessage))
160 std::unique_ptr<JSONCompilationDatabase>
162 std::string &ErrorMessage) {
163 std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
164 llvm::MemoryBuffer::getMemBuffer(DatabaseString));
165 std::unique_ptr<JSONCompilationDatabase> Database(
167 if (!Database->parse(ErrorMessage))
172 std::vector<CompileCommand>
175 llvm::sys::path::native(FilePath, NativeFilePath);
178 llvm::raw_string_ostream ES(Error);
181 return std::vector<CompileCommand>();
182 llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
183 CommandsRefI = IndexByFile.find(Match);
184 if (CommandsRefI == IndexByFile.end())
185 return std::vector<CompileCommand>();
186 std::vector<CompileCommand> Commands;
187 getCommands(CommandsRefI->getValue(), Commands);
191 std::vector<std::string>
193 std::vector<std::string>
Result;
195 llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
196 CommandsRefI = IndexByFile.begin();
197 const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
198 CommandsRefEnd = IndexByFile.end();
199 for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) {
200 Result.push_back(CommandsRefI->first().str());
206 std::vector<CompileCommand>
208 std::vector<CompileCommand> Commands;
209 getCommands(AllCommands, Commands);
213 static std::vector<std::string>
216 if (Nodes.size() == 1) {
217 return unescapeCommandLine(Nodes[0]->
getValue(Storage));
219 std::vector<std::string> Arguments;
220 for (
auto *
Node : Nodes) {
221 Arguments.push_back(
Node->getValue(Storage));
226 void JSONCompilationDatabase::getCommands(
228 std::vector<CompileCommand> &Commands)
const {
229 for (
int I = 0,
E = CommandsRef.size();
I !=
E; ++
I) {
232 Commands.emplace_back(
233 std::get<0>(CommandsRef[
I])->
getValue(DirectoryStorage),
234 std::get<1>(CommandsRef[I])->
getValue(FilenameStorage),
239 bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
240 llvm::yaml::document_iterator I = YAMLStream.begin();
241 if (I == YAMLStream.end()) {
242 ErrorMessage =
"Error while parsing YAML.";
247 ErrorMessage =
"Error while parsing YAML.";
250 llvm::yaml::SequenceNode *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
252 ErrorMessage =
"Expected array.";
255 for (
auto& NextObject : *Array) {
256 llvm::yaml::MappingNode *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
258 ErrorMessage =
"Expected object.";
261 llvm::yaml::ScalarNode *Directory =
nullptr;
263 llvm::yaml::ScalarNode *File =
nullptr;
264 for (
auto& NextKeyValue : *Object) {
265 llvm::yaml::ScalarNode *KeyString =
266 dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
268 ErrorMessage =
"Expected strings as key.";
271 SmallString<10> KeyStorage;
272 StringRef KeyValue = KeyString->getValue(KeyStorage);
275 ErrorMessage =
"Expected value.";
278 llvm::yaml::ScalarNode *ValueString =
279 dyn_cast<llvm::yaml::ScalarNode>(
Value);
280 llvm::yaml::SequenceNode *SequenceString =
281 dyn_cast<llvm::yaml::SequenceNode>(
Value);
282 if (KeyValue ==
"arguments" && !SequenceString) {
283 ErrorMessage =
"Expected sequence as value.";
285 }
else if (KeyValue !=
"arguments" && !ValueString) {
286 ErrorMessage =
"Expected string as value.";
289 if (KeyValue ==
"directory") {
290 Directory = ValueString;
291 }
else if (KeyValue ==
"arguments") {
292 Command = std::vector<llvm::yaml::ScalarNode *>();
293 for (
auto &Argument : *SequenceString) {
294 auto Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
296 ErrorMessage =
"Only strings are allowed in 'arguments'.";
299 Command->push_back(Scalar);
301 }
else if (KeyValue ==
"command") {
303 Command = std::vector<llvm::yaml::ScalarNode *>(1, ValueString);
304 }
else if (KeyValue ==
"file") {
307 ErrorMessage = (
"Unknown key: \"" +
308 KeyString->getRawValue() +
"\"").str();
313 ErrorMessage =
"Missing key: \"file\".";
317 ErrorMessage =
"Missing key: \"command\" or \"arguments\".";
321 ErrorMessage =
"Missing key: \"directory\".";
324 SmallString<8> FileStorage;
325 StringRef
FileName = File->getValue(FileStorage);
326 SmallString<128> NativeFilePath;
327 if (llvm::sys::path::is_relative(FileName)) {
328 SmallString<8> DirectoryStorage;
329 SmallString<128> AbsolutePath(
330 Directory->getValue(DirectoryStorage));
331 llvm::sys::path::append(AbsolutePath, FileName);
332 llvm::sys::path::native(AbsolutePath, NativeFilePath);
334 llvm::sys::path::native(FileName, NativeFilePath);
336 auto Cmd = CompileCommandRef(Directory, File, *Command);
337 IndexByFile[NativeFilePath].push_back(Cmd);
338 AllCommands.push_back(Cmd);
339 MatchTrie.
insert(NativeFilePath);
BoundNodesTreeBuilder Nodes
detail::InMemoryDirectory::const_iterator I
static SVal getValue(SVal val, SValBuilder &svalBuilder)
The result type of a method or function.
const TemplateArgument * iterator
ast_type_traits::DynTypedNode Node
detail::InMemoryDirectory::const_iterator E
std::vector< std::string > CommandLine
StringRef::iterator Position