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