14ba319b5SDimitry Andric //===- JSONCompilationDatabase.cpp ----------------------------------------===//
23861d79fSDimitry Andric //
33861d79fSDimitry Andric // The LLVM Compiler Infrastructure
43861d79fSDimitry Andric //
53861d79fSDimitry Andric // This file is distributed under the University of Illinois Open Source
63861d79fSDimitry Andric // License. See LICENSE.TXT for details.
73861d79fSDimitry Andric //
83861d79fSDimitry Andric //===----------------------------------------------------------------------===//
93861d79fSDimitry Andric //
103861d79fSDimitry Andric // This file contains the implementation of the JSONCompilationDatabase.
113861d79fSDimitry Andric //
123861d79fSDimitry Andric //===----------------------------------------------------------------------===//
133861d79fSDimitry Andric
143861d79fSDimitry Andric #include "clang/Tooling/JSONCompilationDatabase.h"
154ba319b5SDimitry Andric #include "clang/Basic/LLVM.h"
163861d79fSDimitry Andric #include "clang/Tooling/CompilationDatabase.h"
173861d79fSDimitry Andric #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
184ba319b5SDimitry Andric #include "llvm/ADT/Optional.h"
193861d79fSDimitry Andric #include "llvm/ADT/SmallString.h"
204ba319b5SDimitry Andric #include "llvm/ADT/SmallVector.h"
214ba319b5SDimitry Andric #include "llvm/ADT/StringRef.h"
224ba319b5SDimitry Andric #include "llvm/ADT/Triple.h"
2344290647SDimitry Andric #include "llvm/Support/Allocator.h"
244ba319b5SDimitry Andric #include "llvm/Support/Casting.h"
2544290647SDimitry Andric #include "llvm/Support/CommandLine.h"
264ba319b5SDimitry Andric #include "llvm/Support/ErrorOr.h"
274ba319b5SDimitry Andric #include "llvm/Support/Host.h"
284ba319b5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
293861d79fSDimitry Andric #include "llvm/Support/Path.h"
3044290647SDimitry Andric #include "llvm/Support/StringSaver.h"
314ba319b5SDimitry Andric #include "llvm/Support/YAMLParser.h"
324ba319b5SDimitry Andric #include "llvm/Support/raw_ostream.h"
334ba319b5SDimitry Andric #include <cassert>
344ba319b5SDimitry Andric #include <memory>
354ba319b5SDimitry Andric #include <string>
3659d1ed5bSDimitry Andric #include <system_error>
374ba319b5SDimitry Andric #include <tuple>
384ba319b5SDimitry Andric #include <utility>
394ba319b5SDimitry Andric #include <vector>
403861d79fSDimitry Andric
414ba319b5SDimitry Andric using namespace clang;
424ba319b5SDimitry Andric using namespace tooling;
433861d79fSDimitry Andric
443861d79fSDimitry Andric namespace {
453861d79fSDimitry Andric
464ba319b5SDimitry Andric /// A parser for escaped strings of command line arguments.
473861d79fSDimitry Andric ///
483861d79fSDimitry Andric /// Assumes \-escaping for quoted arguments (see the documentation of
493861d79fSDimitry Andric /// unescapeCommandLine(...)).
503861d79fSDimitry Andric class CommandLineArgumentParser {
513861d79fSDimitry Andric public:
CommandLineArgumentParser(StringRef CommandLine)523861d79fSDimitry Andric CommandLineArgumentParser(StringRef CommandLine)
533861d79fSDimitry Andric : Input(CommandLine), Position(Input.begin()-1) {}
543861d79fSDimitry Andric
parse()553861d79fSDimitry Andric std::vector<std::string> parse() {
563861d79fSDimitry Andric bool HasMoreInput = true;
573861d79fSDimitry Andric while (HasMoreInput && nextNonWhitespace()) {
583861d79fSDimitry Andric std::string Argument;
593861d79fSDimitry Andric HasMoreInput = parseStringInto(Argument);
603861d79fSDimitry Andric CommandLine.push_back(Argument);
613861d79fSDimitry Andric }
623861d79fSDimitry Andric return CommandLine;
633861d79fSDimitry Andric }
643861d79fSDimitry Andric
653861d79fSDimitry Andric private:
663861d79fSDimitry Andric // All private methods return true if there is more input available.
673861d79fSDimitry Andric
parseStringInto(std::string & String)683861d79fSDimitry Andric bool parseStringInto(std::string &String) {
693861d79fSDimitry Andric do {
703861d79fSDimitry Andric if (*Position == '"') {
71139f7f9bSDimitry Andric if (!parseDoubleQuotedStringInto(String)) return false;
72139f7f9bSDimitry Andric } else if (*Position == '\'') {
73139f7f9bSDimitry Andric if (!parseSingleQuotedStringInto(String)) return false;
743861d79fSDimitry Andric } else {
753861d79fSDimitry Andric if (!parseFreeStringInto(String)) return false;
763861d79fSDimitry Andric }
773861d79fSDimitry Andric } while (*Position != ' ');
783861d79fSDimitry Andric return true;
793861d79fSDimitry Andric }
803861d79fSDimitry Andric
parseDoubleQuotedStringInto(std::string & String)81139f7f9bSDimitry Andric bool parseDoubleQuotedStringInto(std::string &String) {
823861d79fSDimitry Andric if (!next()) return false;
833861d79fSDimitry Andric while (*Position != '"') {
843861d79fSDimitry Andric if (!skipEscapeCharacter()) return false;
853861d79fSDimitry Andric String.push_back(*Position);
863861d79fSDimitry Andric if (!next()) return false;
873861d79fSDimitry Andric }
883861d79fSDimitry Andric return next();
893861d79fSDimitry Andric }
903861d79fSDimitry Andric
parseSingleQuotedStringInto(std::string & String)91139f7f9bSDimitry Andric bool parseSingleQuotedStringInto(std::string &String) {
92139f7f9bSDimitry Andric if (!next()) return false;
93139f7f9bSDimitry Andric while (*Position != '\'') {
94139f7f9bSDimitry Andric String.push_back(*Position);
95139f7f9bSDimitry Andric if (!next()) return false;
96139f7f9bSDimitry Andric }
97139f7f9bSDimitry Andric return next();
98139f7f9bSDimitry Andric }
99139f7f9bSDimitry Andric
parseFreeStringInto(std::string & String)1003861d79fSDimitry Andric bool parseFreeStringInto(std::string &String) {
1013861d79fSDimitry Andric do {
1023861d79fSDimitry Andric if (!skipEscapeCharacter()) return false;
1033861d79fSDimitry Andric String.push_back(*Position);
1043861d79fSDimitry Andric if (!next()) return false;
105139f7f9bSDimitry Andric } while (*Position != ' ' && *Position != '"' && *Position != '\'');
1063861d79fSDimitry Andric return true;
1073861d79fSDimitry Andric }
1083861d79fSDimitry Andric
skipEscapeCharacter()1093861d79fSDimitry Andric bool skipEscapeCharacter() {
1103861d79fSDimitry Andric if (*Position == '\\') {
1113861d79fSDimitry Andric return next();
1123861d79fSDimitry Andric }
1133861d79fSDimitry Andric return true;
1143861d79fSDimitry Andric }
1153861d79fSDimitry Andric
nextNonWhitespace()1163861d79fSDimitry Andric bool nextNonWhitespace() {
1173861d79fSDimitry Andric do {
1183861d79fSDimitry Andric if (!next()) return false;
1193861d79fSDimitry Andric } while (*Position == ' ');
1203861d79fSDimitry Andric return true;
1213861d79fSDimitry Andric }
1223861d79fSDimitry Andric
next()1233861d79fSDimitry Andric bool next() {
1243861d79fSDimitry Andric ++Position;
1253861d79fSDimitry Andric return Position != Input.end();
1263861d79fSDimitry Andric }
1273861d79fSDimitry Andric
1283861d79fSDimitry Andric const StringRef Input;
1293861d79fSDimitry Andric StringRef::iterator Position;
1303861d79fSDimitry Andric std::vector<std::string> CommandLine;
1313861d79fSDimitry Andric };
1323861d79fSDimitry Andric
unescapeCommandLine(JSONCommandLineSyntax Syntax,StringRef EscapedCommandLine)13344290647SDimitry Andric std::vector<std::string> unescapeCommandLine(JSONCommandLineSyntax Syntax,
1343861d79fSDimitry Andric StringRef EscapedCommandLine) {
13544290647SDimitry Andric if (Syntax == JSONCommandLineSyntax::AutoDetect) {
13644290647SDimitry Andric Syntax = JSONCommandLineSyntax::Gnu;
13744290647SDimitry Andric llvm::Triple Triple(llvm::sys::getProcessTriple());
13844290647SDimitry Andric if (Triple.getOS() == llvm::Triple::OSType::Win32) {
13944290647SDimitry Andric // Assume Windows command line parsing on Win32 unless the triple
14044290647SDimitry Andric // explicitly tells us otherwise.
14144290647SDimitry Andric if (!Triple.hasEnvironment() ||
14244290647SDimitry Andric Triple.getEnvironment() == llvm::Triple::EnvironmentType::MSVC)
14344290647SDimitry Andric Syntax = JSONCommandLineSyntax::Windows;
14444290647SDimitry Andric }
14544290647SDimitry Andric }
14644290647SDimitry Andric
14744290647SDimitry Andric if (Syntax == JSONCommandLineSyntax::Windows) {
14844290647SDimitry Andric llvm::BumpPtrAllocator Alloc;
14944290647SDimitry Andric llvm::StringSaver Saver(Alloc);
15044290647SDimitry Andric llvm::SmallVector<const char *, 64> T;
15144290647SDimitry Andric llvm::cl::TokenizeWindowsCommandLine(EscapedCommandLine, Saver, T);
15244290647SDimitry Andric std::vector<std::string> Result(T.begin(), T.end());
15344290647SDimitry Andric return Result;
15444290647SDimitry Andric }
15544290647SDimitry Andric assert(Syntax == JSONCommandLineSyntax::Gnu);
1563861d79fSDimitry Andric CommandLineArgumentParser parser(EscapedCommandLine);
1573861d79fSDimitry Andric return parser.parse();
1583861d79fSDimitry Andric }
1593861d79fSDimitry Andric
160*b5893f02SDimitry Andric // This plugin locates a nearby compile_command.json file, and also infers
161*b5893f02SDimitry Andric // compile commands for files not present in the database.
1623861d79fSDimitry Andric class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
16339d628a0SDimitry Andric std::unique_ptr<CompilationDatabase>
loadFromDirectory(StringRef Directory,std::string & ErrorMessage)16439d628a0SDimitry Andric loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
165139f7f9bSDimitry Andric SmallString<1024> JSONDatabasePath(Directory);
1663861d79fSDimitry Andric llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
167*b5893f02SDimitry Andric auto Base = JSONCompilationDatabase::loadFromFile(
1680f5676f4SDimitry Andric JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect);
169*b5893f02SDimitry Andric return Base ? inferMissingCompileCommands(std::move(Base)) : nullptr;
1703861d79fSDimitry Andric }
1713861d79fSDimitry Andric };
1723861d79fSDimitry Andric
1734ba319b5SDimitry Andric } // namespace
174f785676fSDimitry Andric
1753861d79fSDimitry Andric // Register the JSONCompilationDatabasePlugin with the
1763861d79fSDimitry Andric // CompilationDatabasePluginRegistry using this statically initialized variable.
1773861d79fSDimitry Andric static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
1783861d79fSDimitry Andric X("json-compilation-database", "Reads JSON formatted compilation databases");
1793861d79fSDimitry Andric
1804ba319b5SDimitry Andric namespace clang {
1814ba319b5SDimitry Andric namespace tooling {
1824ba319b5SDimitry Andric
1833861d79fSDimitry Andric // This anchor is used to force the linker to link in the generated object file
1843861d79fSDimitry Andric // and thus register the JSONCompilationDatabasePlugin.
1853861d79fSDimitry Andric volatile int JSONAnchorSource = 0;
1863861d79fSDimitry Andric
1874ba319b5SDimitry Andric } // namespace tooling
1884ba319b5SDimitry Andric } // namespace clang
1894ba319b5SDimitry Andric
19039d628a0SDimitry Andric std::unique_ptr<JSONCompilationDatabase>
loadFromFile(StringRef FilePath,std::string & ErrorMessage,JSONCommandLineSyntax Syntax)1913861d79fSDimitry Andric JSONCompilationDatabase::loadFromFile(StringRef FilePath,
19244290647SDimitry Andric std::string &ErrorMessage,
19344290647SDimitry Andric JSONCommandLineSyntax Syntax) {
19459d1ed5bSDimitry Andric llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
19559d1ed5bSDimitry Andric llvm::MemoryBuffer::getFile(FilePath);
19659d1ed5bSDimitry Andric if (std::error_code Result = DatabaseBuffer.getError()) {
1973861d79fSDimitry Andric ErrorMessage = "Error while opening JSON database: " + Result.message();
19859d1ed5bSDimitry Andric return nullptr;
1993861d79fSDimitry Andric }
20059d1ed5bSDimitry Andric std::unique_ptr<JSONCompilationDatabase> Database(
20144290647SDimitry Andric new JSONCompilationDatabase(std::move(*DatabaseBuffer), Syntax));
2023861d79fSDimitry Andric if (!Database->parse(ErrorMessage))
20359d1ed5bSDimitry Andric return nullptr;
20439d628a0SDimitry Andric return Database;
2053861d79fSDimitry Andric }
2063861d79fSDimitry Andric
20739d628a0SDimitry Andric std::unique_ptr<JSONCompilationDatabase>
loadFromBuffer(StringRef DatabaseString,std::string & ErrorMessage,JSONCommandLineSyntax Syntax)2083861d79fSDimitry Andric JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
20944290647SDimitry Andric std::string &ErrorMessage,
21044290647SDimitry Andric JSONCommandLineSyntax Syntax) {
21159d1ed5bSDimitry Andric std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
2123861d79fSDimitry Andric llvm::MemoryBuffer::getMemBuffer(DatabaseString));
21359d1ed5bSDimitry Andric std::unique_ptr<JSONCompilationDatabase> Database(
21444290647SDimitry Andric new JSONCompilationDatabase(std::move(DatabaseBuffer), Syntax));
2153861d79fSDimitry Andric if (!Database->parse(ErrorMessage))
21659d1ed5bSDimitry Andric return nullptr;
21739d628a0SDimitry Andric return Database;
2183861d79fSDimitry Andric }
2193861d79fSDimitry Andric
2203861d79fSDimitry Andric std::vector<CompileCommand>
getCompileCommands(StringRef FilePath) const2213861d79fSDimitry Andric JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
222139f7f9bSDimitry Andric SmallString<128> NativeFilePath;
2233861d79fSDimitry Andric llvm::sys::path::native(FilePath, NativeFilePath);
22459d1ed5bSDimitry Andric
2253861d79fSDimitry Andric std::string Error;
2263861d79fSDimitry Andric llvm::raw_string_ostream ES(Error);
22733956c43SDimitry Andric StringRef Match = MatchTrie.findEquivalent(NativeFilePath, ES);
228139f7f9bSDimitry Andric if (Match.empty())
2294ba319b5SDimitry Andric return {};
2304ba319b5SDimitry Andric const auto CommandsRefI = IndexByFile.find(Match);
2313861d79fSDimitry Andric if (CommandsRefI == IndexByFile.end())
2324ba319b5SDimitry Andric return {};
2333861d79fSDimitry Andric std::vector<CompileCommand> Commands;
234139f7f9bSDimitry Andric getCommands(CommandsRefI->getValue(), Commands);
2353861d79fSDimitry Andric return Commands;
2363861d79fSDimitry Andric }
2373861d79fSDimitry Andric
2383861d79fSDimitry Andric std::vector<std::string>
getAllFiles() const2393861d79fSDimitry Andric JSONCompilationDatabase::getAllFiles() const {
2403861d79fSDimitry Andric std::vector<std::string> Result;
2414ba319b5SDimitry Andric for (const auto &CommandRef : IndexByFile)
2424ba319b5SDimitry Andric Result.push_back(CommandRef.first().str());
2433861d79fSDimitry Andric return Result;
2443861d79fSDimitry Andric }
2453861d79fSDimitry Andric
246139f7f9bSDimitry Andric std::vector<CompileCommand>
getAllCompileCommands() const247139f7f9bSDimitry Andric JSONCompilationDatabase::getAllCompileCommands() const {
248139f7f9bSDimitry Andric std::vector<CompileCommand> Commands;
2490623d748SDimitry Andric getCommands(AllCommands, Commands);
250139f7f9bSDimitry Andric return Commands;
251139f7f9bSDimitry Andric }
252139f7f9bSDimitry Andric
2530623d748SDimitry Andric static std::vector<std::string>
nodeToCommandLine(JSONCommandLineSyntax Syntax,const std::vector<llvm::yaml::ScalarNode * > & Nodes)25444290647SDimitry Andric nodeToCommandLine(JSONCommandLineSyntax Syntax,
25544290647SDimitry Andric const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
2560623d748SDimitry Andric SmallString<1024> Storage;
2574ba319b5SDimitry Andric if (Nodes.size() == 1)
25844290647SDimitry Andric return unescapeCommandLine(Syntax, Nodes[0]->getValue(Storage));
2590623d748SDimitry Andric std::vector<std::string> Arguments;
2604ba319b5SDimitry Andric for (const auto *Node : Nodes)
2610623d748SDimitry Andric Arguments.push_back(Node->getValue(Storage));
2620623d748SDimitry Andric return Arguments;
2630623d748SDimitry Andric }
2640623d748SDimitry Andric
getCommands(ArrayRef<CompileCommandRef> CommandsRef,std::vector<CompileCommand> & Commands) const265139f7f9bSDimitry Andric void JSONCompilationDatabase::getCommands(
266139f7f9bSDimitry Andric ArrayRef<CompileCommandRef> CommandsRef,
267139f7f9bSDimitry Andric std::vector<CompileCommand> &Commands) const {
2684ba319b5SDimitry Andric for (const auto &CommandRef : CommandsRef) {
269139f7f9bSDimitry Andric SmallString<8> DirectoryStorage;
2700623d748SDimitry Andric SmallString<32> FilenameStorage;
27144290647SDimitry Andric SmallString<32> OutputStorage;
2724ba319b5SDimitry Andric auto Output = std::get<3>(CommandRef);
27397bc6c73SDimitry Andric Commands.emplace_back(
2744ba319b5SDimitry Andric std::get<0>(CommandRef)->getValue(DirectoryStorage),
2754ba319b5SDimitry Andric std::get<1>(CommandRef)->getValue(FilenameStorage),
2764ba319b5SDimitry Andric nodeToCommandLine(Syntax, std::get<2>(CommandRef)),
27744290647SDimitry Andric Output ? Output->getValue(OutputStorage) : "");
278139f7f9bSDimitry Andric }
279139f7f9bSDimitry Andric }
280139f7f9bSDimitry Andric
parse(std::string & ErrorMessage)2813861d79fSDimitry Andric bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
2823861d79fSDimitry Andric llvm::yaml::document_iterator I = YAMLStream.begin();
2833861d79fSDimitry Andric if (I == YAMLStream.end()) {
2843861d79fSDimitry Andric ErrorMessage = "Error while parsing YAML.";
2853861d79fSDimitry Andric return false;
2863861d79fSDimitry Andric }
2873861d79fSDimitry Andric llvm::yaml::Node *Root = I->getRoot();
28859d1ed5bSDimitry Andric if (!Root) {
2893861d79fSDimitry Andric ErrorMessage = "Error while parsing YAML.";
2903861d79fSDimitry Andric return false;
2913861d79fSDimitry Andric }
2924ba319b5SDimitry Andric auto *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
29359d1ed5bSDimitry Andric if (!Array) {
2943861d79fSDimitry Andric ErrorMessage = "Expected array.";
2953861d79fSDimitry Andric return false;
2963861d79fSDimitry Andric }
2970623d748SDimitry Andric for (auto &NextObject : *Array) {
2984ba319b5SDimitry Andric auto *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
29959d1ed5bSDimitry Andric if (!Object) {
3003861d79fSDimitry Andric ErrorMessage = "Expected object.";
3013861d79fSDimitry Andric return false;
3023861d79fSDimitry Andric }
30359d1ed5bSDimitry Andric llvm::yaml::ScalarNode *Directory = nullptr;
3040623d748SDimitry Andric llvm::Optional<std::vector<llvm::yaml::ScalarNode *>> Command;
30559d1ed5bSDimitry Andric llvm::yaml::ScalarNode *File = nullptr;
30644290647SDimitry Andric llvm::yaml::ScalarNode *Output = nullptr;
3070623d748SDimitry Andric for (auto& NextKeyValue : *Object) {
3084ba319b5SDimitry Andric auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
3090623d748SDimitry Andric if (!KeyString) {
3100623d748SDimitry Andric ErrorMessage = "Expected strings as key.";
3110623d748SDimitry Andric return false;
3120623d748SDimitry Andric }
3130623d748SDimitry Andric SmallString<10> KeyStorage;
3140623d748SDimitry Andric StringRef KeyValue = KeyString->getValue(KeyStorage);
3150623d748SDimitry Andric llvm::yaml::Node *Value = NextKeyValue.getValue();
31659d1ed5bSDimitry Andric if (!Value) {
3173861d79fSDimitry Andric ErrorMessage = "Expected value.";
3183861d79fSDimitry Andric return false;
3193861d79fSDimitry Andric }
3204ba319b5SDimitry Andric auto *ValueString = dyn_cast<llvm::yaml::ScalarNode>(Value);
3214ba319b5SDimitry Andric auto *SequenceString = dyn_cast<llvm::yaml::SequenceNode>(Value);
3220623d748SDimitry Andric if (KeyValue == "arguments" && !SequenceString) {
3230623d748SDimitry Andric ErrorMessage = "Expected sequence as value.";
3240623d748SDimitry Andric return false;
3250623d748SDimitry Andric } else if (KeyValue != "arguments" && !ValueString) {
3263861d79fSDimitry Andric ErrorMessage = "Expected string as value.";
3273861d79fSDimitry Andric return false;
3283861d79fSDimitry Andric }
3290623d748SDimitry Andric if (KeyValue == "directory") {
3300623d748SDimitry Andric Directory = ValueString;
3310623d748SDimitry Andric } else if (KeyValue == "arguments") {
3320623d748SDimitry Andric Command = std::vector<llvm::yaml::ScalarNode *>();
3330623d748SDimitry Andric for (auto &Argument : *SequenceString) {
3344ba319b5SDimitry Andric auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
3350623d748SDimitry Andric if (!Scalar) {
3360623d748SDimitry Andric ErrorMessage = "Only strings are allowed in 'arguments'.";
3373861d79fSDimitry Andric return false;
3383861d79fSDimitry Andric }
3390623d748SDimitry Andric Command->push_back(Scalar);
3400623d748SDimitry Andric }
3410623d748SDimitry Andric } else if (KeyValue == "command") {
3420623d748SDimitry Andric if (!Command)
3430623d748SDimitry Andric Command = std::vector<llvm::yaml::ScalarNode *>(1, ValueString);
3440623d748SDimitry Andric } else if (KeyValue == "file") {
3453861d79fSDimitry Andric File = ValueString;
34644290647SDimitry Andric } else if (KeyValue == "output") {
34744290647SDimitry Andric Output = ValueString;
3483861d79fSDimitry Andric } else {
3493861d79fSDimitry Andric ErrorMessage = ("Unknown key: \"" +
3503861d79fSDimitry Andric KeyString->getRawValue() + "\"").str();
3513861d79fSDimitry Andric return false;
3523861d79fSDimitry Andric }
3533861d79fSDimitry Andric }
3543861d79fSDimitry Andric if (!File) {
3553861d79fSDimitry Andric ErrorMessage = "Missing key: \"file\".";
3563861d79fSDimitry Andric return false;
3573861d79fSDimitry Andric }
3583861d79fSDimitry Andric if (!Command) {
3590623d748SDimitry Andric ErrorMessage = "Missing key: \"command\" or \"arguments\".";
3603861d79fSDimitry Andric return false;
3613861d79fSDimitry Andric }
3623861d79fSDimitry Andric if (!Directory) {
3633861d79fSDimitry Andric ErrorMessage = "Missing key: \"directory\".";
3643861d79fSDimitry Andric return false;
3653861d79fSDimitry Andric }
366139f7f9bSDimitry Andric SmallString<8> FileStorage;
3673861d79fSDimitry Andric StringRef FileName = File->getValue(FileStorage);
368139f7f9bSDimitry Andric SmallString<128> NativeFilePath;
3693861d79fSDimitry Andric if (llvm::sys::path::is_relative(FileName)) {
370139f7f9bSDimitry Andric SmallString<8> DirectoryStorage;
371139f7f9bSDimitry Andric SmallString<128> AbsolutePath(
3723861d79fSDimitry Andric Directory->getValue(DirectoryStorage));
3733861d79fSDimitry Andric llvm::sys::path::append(AbsolutePath, FileName);
37433956c43SDimitry Andric llvm::sys::path::native(AbsolutePath, NativeFilePath);
3753861d79fSDimitry Andric } else {
3763861d79fSDimitry Andric llvm::sys::path::native(FileName, NativeFilePath);
3773861d79fSDimitry Andric }
37844290647SDimitry Andric auto Cmd = CompileCommandRef(Directory, File, *Command, Output);
3790623d748SDimitry Andric IndexByFile[NativeFilePath].push_back(Cmd);
3800623d748SDimitry Andric AllCommands.push_back(Cmd);
38133956c43SDimitry Andric MatchTrie.insert(NativeFilePath);
3823861d79fSDimitry Andric }
3833861d79fSDimitry Andric return true;
3843861d79fSDimitry Andric }
385