Index: include/clang/Tooling/JSONCompilationDatabase.h =================================================================== --- include/clang/Tooling/JSONCompilationDatabase.h +++ include/clang/Tooling/JSONCompilationDatabase.h @@ -94,7 +94,7 @@ // Tuple (directory, commandline) where 'commandline' pointing to the // corresponding nodes in the YAML stream. typedef std::pair CompileCommandRef; + std::vector> CompileCommandRef; /// \brief Converts the given array of CompileCommandRefs to CompileCommands. void getCommands(ArrayRef CommandsRef, Index: lib/Tooling/JSONCompilationDatabase.cpp =================================================================== --- lib/Tooling/JSONCompilationDatabase.cpp +++ lib/Tooling/JSONCompilationDatabase.cpp @@ -221,9 +221,8 @@ SmallString<8> DirectoryStorage; SmallString<1024> CommandStorage; Commands.emplace_back( - // FIXME: Escape correctly: - CommandsRef[I].first->getValue(DirectoryStorage), - unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage))); + CommandsRef[I].first->getValue(DirectoryStorage), + CommandsRef[I].second); } } @@ -252,11 +251,20 @@ return false; } llvm::yaml::ScalarNode *Directory = nullptr; - llvm::yaml::ScalarNode *Command = nullptr; + std::vector Args; + bool CommandFound = false; llvm::yaml::ScalarNode *File = nullptr; for (llvm::yaml::MappingNode::iterator KVI = Object->begin(), KVE = Object->end(); KVI != KVE; ++KVI) { + llvm::yaml::ScalarNode *KeyString = + dyn_cast((*KVI).getKey()); + if (!KeyString) { + ErrorMessage = "Expected strings as key."; + return false; + } + SmallString<8> KeyStorage; + StringRef KeyValue = KeyString->getValue(KeyStorage); llvm::yaml::Node *Value = (*KVI).getValue(); if (!Value) { ErrorMessage = "Expected value."; @@ -264,23 +272,42 @@ } llvm::yaml::ScalarNode *ValueString = dyn_cast(Value); - if (!ValueString) { + llvm::yaml::SequenceNode *SequenceString = + dyn_cast(Value); + if (KeyValue == "cmd" && !SequenceString) { + ErrorMessage = "Expected sequence as value."; + return false; + } else if (KeyValue != "cmd" && !ValueString) { ErrorMessage = "Expected string as value."; return false; } - llvm::yaml::ScalarNode *KeyString = - dyn_cast((*KVI).getKey()); - if (!KeyString) { - ErrorMessage = "Expected strings as key."; - return false; - } - SmallString<8> KeyStorage; - if (KeyString->getValue(KeyStorage) == "directory") { + if (KeyValue == "directory") { Directory = ValueString; - } else if (KeyString->getValue(KeyStorage) == "command") { - Command = ValueString; - } else if (KeyString->getValue(KeyStorage) == "file") { + } else if (KeyValue == "command") { + if (CommandFound) { + ErrorMessage = "Multiple command and cmd found"; + return false; + } + SmallString<1024> CommandStorage; + // FIXME: Escape correctly: + Args = unescapeCommandLine(ValueString->getValue(CommandStorage)); + CommandFound = true; + } else if (KeyValue == "file") { File = ValueString; + } else if (KeyValue == "cmd") { + if (CommandFound) { + ErrorMessage = "Multiple command and cmd found"; + return false; + } + for (llvm::yaml::SequenceNode::iterator CI = SequenceString->begin(), + CE = SequenceString->end(); + CI != CE; ++CI) { + SmallString<128> CommandStorage; + auto ValueString = dyn_cast(&*CI); + + Args.push_back(ValueString->getValue(CommandStorage)); + } + CommandFound = true; } else { ErrorMessage = ("Unknown key: \"" + KeyString->getRawValue() + "\"").str(); @@ -291,8 +318,8 @@ ErrorMessage = "Missing key: \"file\"."; return false; } - if (!Command) { - ErrorMessage = "Missing key: \"command\"."; + if (!CommandFound) { + ErrorMessage = "Missing key: \"command\" or \"cmd\"."; return false; } if (!Directory) { @@ -312,7 +339,7 @@ llvm::sys::path::native(FileName, NativeFilePath); } IndexByFile[NativeFilePath].push_back( - CompileCommandRef(Directory, Command)); + CompileCommandRef(Directory, Args)); MatchTrie.insert(NativeFilePath); } return true; Index: unittests/Tooling/CompilationDatabaseTest.cpp =================================================================== --- unittests/Tooling/CompilationDatabaseTest.cpp +++ unittests/Tooling/CompilationDatabaseTest.cpp @@ -36,8 +36,13 @@ expectFailure("[{[]:\"\"}]", "Incorrectly typed entry"); expectFailure("[{}]", "Empty entry"); expectFailure("[{\"directory\":\"\",\"command\":\"\"}]", "Missing file"); - expectFailure("[{\"directory\":\"\",\"file\":\"\"}]", "Missing command"); + expectFailure("[{\"directory\":\"\",\"file\":\"\"}]", "Missing command or cmd"); expectFailure("[{\"command\":\"\",\"file\":\"\"}]", "Missing directory"); + expectFailure("[{\"directory\":\"\",\"cmd\":[]}]", "Missing file"); + expectFailure("[{\"cmd\":\"\",\"file\":\"\"}]", "Missing directory"); + expectFailure("[{\"command\":\"\",\"cmd\":[],\"file\":\"\"}]", "Command and cmd"); + expectFailure("[{\"directory\":\"\",\"cmd\":\"\",\"file\":\"\"}]", "Cmd not array"); + expectFailure("[{\"directory\":\"\",\"command\":[],\"file\":\"\"}]", "Command not string"); } static std::vector getAllFiles(StringRef JSONDatabase,