17330f729Sjoerg //===- JSONCompilationDatabase.cpp ----------------------------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file contains the implementation of the JSONCompilationDatabase.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "clang/Tooling/JSONCompilationDatabase.h"
147330f729Sjoerg #include "clang/Basic/LLVM.h"
157330f729Sjoerg #include "clang/Tooling/CompilationDatabase.h"
167330f729Sjoerg #include "clang/Tooling/CompilationDatabasePluginRegistry.h"
177330f729Sjoerg #include "clang/Tooling/Tooling.h"
187330f729Sjoerg #include "llvm/ADT/Optional.h"
197330f729Sjoerg #include "llvm/ADT/STLExtras.h"
207330f729Sjoerg #include "llvm/ADT/SmallString.h"
217330f729Sjoerg #include "llvm/ADT/SmallVector.h"
227330f729Sjoerg #include "llvm/ADT/StringRef.h"
237330f729Sjoerg #include "llvm/ADT/Triple.h"
247330f729Sjoerg #include "llvm/Support/Allocator.h"
257330f729Sjoerg #include "llvm/Support/Casting.h"
267330f729Sjoerg #include "llvm/Support/CommandLine.h"
277330f729Sjoerg #include "llvm/Support/ErrorOr.h"
287330f729Sjoerg #include "llvm/Support/Host.h"
297330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
307330f729Sjoerg #include "llvm/Support/Path.h"
317330f729Sjoerg #include "llvm/Support/StringSaver.h"
32*e038c9c4Sjoerg #include "llvm/Support/VirtualFileSystem.h"
337330f729Sjoerg #include "llvm/Support/YAMLParser.h"
347330f729Sjoerg #include "llvm/Support/raw_ostream.h"
357330f729Sjoerg #include <cassert>
367330f729Sjoerg #include <memory>
377330f729Sjoerg #include <string>
387330f729Sjoerg #include <system_error>
397330f729Sjoerg #include <tuple>
407330f729Sjoerg #include <utility>
417330f729Sjoerg #include <vector>
427330f729Sjoerg
437330f729Sjoerg using namespace clang;
447330f729Sjoerg using namespace tooling;
457330f729Sjoerg
467330f729Sjoerg namespace {
477330f729Sjoerg
487330f729Sjoerg /// A parser for escaped strings of command line arguments.
497330f729Sjoerg ///
507330f729Sjoerg /// Assumes \-escaping for quoted arguments (see the documentation of
517330f729Sjoerg /// unescapeCommandLine(...)).
527330f729Sjoerg class CommandLineArgumentParser {
537330f729Sjoerg public:
CommandLineArgumentParser(StringRef CommandLine)547330f729Sjoerg CommandLineArgumentParser(StringRef CommandLine)
557330f729Sjoerg : Input(CommandLine), Position(Input.begin()-1) {}
567330f729Sjoerg
parse()577330f729Sjoerg std::vector<std::string> parse() {
587330f729Sjoerg bool HasMoreInput = true;
597330f729Sjoerg while (HasMoreInput && nextNonWhitespace()) {
607330f729Sjoerg std::string Argument;
617330f729Sjoerg HasMoreInput = parseStringInto(Argument);
627330f729Sjoerg CommandLine.push_back(Argument);
637330f729Sjoerg }
647330f729Sjoerg return CommandLine;
657330f729Sjoerg }
667330f729Sjoerg
677330f729Sjoerg private:
687330f729Sjoerg // All private methods return true if there is more input available.
697330f729Sjoerg
parseStringInto(std::string & String)707330f729Sjoerg bool parseStringInto(std::string &String) {
717330f729Sjoerg do {
727330f729Sjoerg if (*Position == '"') {
737330f729Sjoerg if (!parseDoubleQuotedStringInto(String)) return false;
747330f729Sjoerg } else if (*Position == '\'') {
757330f729Sjoerg if (!parseSingleQuotedStringInto(String)) return false;
767330f729Sjoerg } else {
777330f729Sjoerg if (!parseFreeStringInto(String)) return false;
787330f729Sjoerg }
797330f729Sjoerg } while (*Position != ' ');
807330f729Sjoerg return true;
817330f729Sjoerg }
827330f729Sjoerg
parseDoubleQuotedStringInto(std::string & String)837330f729Sjoerg bool parseDoubleQuotedStringInto(std::string &String) {
847330f729Sjoerg if (!next()) return false;
857330f729Sjoerg while (*Position != '"') {
867330f729Sjoerg if (!skipEscapeCharacter()) return false;
877330f729Sjoerg String.push_back(*Position);
887330f729Sjoerg if (!next()) return false;
897330f729Sjoerg }
907330f729Sjoerg return next();
917330f729Sjoerg }
927330f729Sjoerg
parseSingleQuotedStringInto(std::string & String)937330f729Sjoerg bool parseSingleQuotedStringInto(std::string &String) {
947330f729Sjoerg if (!next()) return false;
957330f729Sjoerg while (*Position != '\'') {
967330f729Sjoerg String.push_back(*Position);
977330f729Sjoerg if (!next()) return false;
987330f729Sjoerg }
997330f729Sjoerg return next();
1007330f729Sjoerg }
1017330f729Sjoerg
parseFreeStringInto(std::string & String)1027330f729Sjoerg bool parseFreeStringInto(std::string &String) {
1037330f729Sjoerg do {
1047330f729Sjoerg if (!skipEscapeCharacter()) return false;
1057330f729Sjoerg String.push_back(*Position);
1067330f729Sjoerg if (!next()) return false;
1077330f729Sjoerg } while (*Position != ' ' && *Position != '"' && *Position != '\'');
1087330f729Sjoerg return true;
1097330f729Sjoerg }
1107330f729Sjoerg
skipEscapeCharacter()1117330f729Sjoerg bool skipEscapeCharacter() {
1127330f729Sjoerg if (*Position == '\\') {
1137330f729Sjoerg return next();
1147330f729Sjoerg }
1157330f729Sjoerg return true;
1167330f729Sjoerg }
1177330f729Sjoerg
nextNonWhitespace()1187330f729Sjoerg bool nextNonWhitespace() {
1197330f729Sjoerg do {
1207330f729Sjoerg if (!next()) return false;
1217330f729Sjoerg } while (*Position == ' ');
1227330f729Sjoerg return true;
1237330f729Sjoerg }
1247330f729Sjoerg
next()1257330f729Sjoerg bool next() {
1267330f729Sjoerg ++Position;
1277330f729Sjoerg return Position != Input.end();
1287330f729Sjoerg }
1297330f729Sjoerg
1307330f729Sjoerg const StringRef Input;
1317330f729Sjoerg StringRef::iterator Position;
1327330f729Sjoerg std::vector<std::string> CommandLine;
1337330f729Sjoerg };
1347330f729Sjoerg
unescapeCommandLine(JSONCommandLineSyntax Syntax,StringRef EscapedCommandLine)1357330f729Sjoerg std::vector<std::string> unescapeCommandLine(JSONCommandLineSyntax Syntax,
1367330f729Sjoerg StringRef EscapedCommandLine) {
1377330f729Sjoerg if (Syntax == JSONCommandLineSyntax::AutoDetect) {
1387330f729Sjoerg Syntax = JSONCommandLineSyntax::Gnu;
1397330f729Sjoerg llvm::Triple Triple(llvm::sys::getProcessTriple());
1407330f729Sjoerg if (Triple.getOS() == llvm::Triple::OSType::Win32) {
1417330f729Sjoerg // Assume Windows command line parsing on Win32 unless the triple
1427330f729Sjoerg // explicitly tells us otherwise.
1437330f729Sjoerg if (!Triple.hasEnvironment() ||
1447330f729Sjoerg Triple.getEnvironment() == llvm::Triple::EnvironmentType::MSVC)
1457330f729Sjoerg Syntax = JSONCommandLineSyntax::Windows;
1467330f729Sjoerg }
1477330f729Sjoerg }
1487330f729Sjoerg
1497330f729Sjoerg if (Syntax == JSONCommandLineSyntax::Windows) {
1507330f729Sjoerg llvm::BumpPtrAllocator Alloc;
1517330f729Sjoerg llvm::StringSaver Saver(Alloc);
1527330f729Sjoerg llvm::SmallVector<const char *, 64> T;
1537330f729Sjoerg llvm::cl::TokenizeWindowsCommandLine(EscapedCommandLine, Saver, T);
1547330f729Sjoerg std::vector<std::string> Result(T.begin(), T.end());
1557330f729Sjoerg return Result;
1567330f729Sjoerg }
1577330f729Sjoerg assert(Syntax == JSONCommandLineSyntax::Gnu);
1587330f729Sjoerg CommandLineArgumentParser parser(EscapedCommandLine);
1597330f729Sjoerg return parser.parse();
1607330f729Sjoerg }
1617330f729Sjoerg
1627330f729Sjoerg // This plugin locates a nearby compile_command.json file, and also infers
1637330f729Sjoerg // compile commands for files not present in the database.
1647330f729Sjoerg class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin {
1657330f729Sjoerg std::unique_ptr<CompilationDatabase>
loadFromDirectory(StringRef Directory,std::string & ErrorMessage)1667330f729Sjoerg loadFromDirectory(StringRef Directory, std::string &ErrorMessage) override {
1677330f729Sjoerg SmallString<1024> JSONDatabasePath(Directory);
1687330f729Sjoerg llvm::sys::path::append(JSONDatabasePath, "compile_commands.json");
1697330f729Sjoerg auto Base = JSONCompilationDatabase::loadFromFile(
1707330f729Sjoerg JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect);
1717330f729Sjoerg return Base ? inferTargetAndDriverMode(
172*e038c9c4Sjoerg inferMissingCompileCommands(expandResponseFiles(
173*e038c9c4Sjoerg std::move(Base), llvm::vfs::getRealFileSystem())))
1747330f729Sjoerg : nullptr;
1757330f729Sjoerg }
1767330f729Sjoerg };
1777330f729Sjoerg
1787330f729Sjoerg } // namespace
1797330f729Sjoerg
1807330f729Sjoerg // Register the JSONCompilationDatabasePlugin with the
1817330f729Sjoerg // CompilationDatabasePluginRegistry using this statically initialized variable.
1827330f729Sjoerg static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin>
1837330f729Sjoerg X("json-compilation-database", "Reads JSON formatted compilation databases");
1847330f729Sjoerg
1857330f729Sjoerg namespace clang {
1867330f729Sjoerg namespace tooling {
1877330f729Sjoerg
1887330f729Sjoerg // This anchor is used to force the linker to link in the generated object file
1897330f729Sjoerg // and thus register the JSONCompilationDatabasePlugin.
1907330f729Sjoerg volatile int JSONAnchorSource = 0;
1917330f729Sjoerg
1927330f729Sjoerg } // namespace tooling
1937330f729Sjoerg } // namespace clang
1947330f729Sjoerg
1957330f729Sjoerg std::unique_ptr<JSONCompilationDatabase>
loadFromFile(StringRef FilePath,std::string & ErrorMessage,JSONCommandLineSyntax Syntax)1967330f729Sjoerg JSONCompilationDatabase::loadFromFile(StringRef FilePath,
1977330f729Sjoerg std::string &ErrorMessage,
1987330f729Sjoerg JSONCommandLineSyntax Syntax) {
1997330f729Sjoerg // Don't mmap: if we're a long-lived process, the build system may overwrite.
2007330f729Sjoerg llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> DatabaseBuffer =
201*e038c9c4Sjoerg llvm::MemoryBuffer::getFile(FilePath, /*IsText=*/false,
2027330f729Sjoerg /*RequiresNullTerminator=*/true,
2037330f729Sjoerg /*IsVolatile=*/true);
2047330f729Sjoerg if (std::error_code Result = DatabaseBuffer.getError()) {
2057330f729Sjoerg ErrorMessage = "Error while opening JSON database: " + Result.message();
2067330f729Sjoerg return nullptr;
2077330f729Sjoerg }
2087330f729Sjoerg std::unique_ptr<JSONCompilationDatabase> Database(
2097330f729Sjoerg new JSONCompilationDatabase(std::move(*DatabaseBuffer), Syntax));
2107330f729Sjoerg if (!Database->parse(ErrorMessage))
2117330f729Sjoerg return nullptr;
2127330f729Sjoerg return Database;
2137330f729Sjoerg }
2147330f729Sjoerg
2157330f729Sjoerg std::unique_ptr<JSONCompilationDatabase>
loadFromBuffer(StringRef DatabaseString,std::string & ErrorMessage,JSONCommandLineSyntax Syntax)2167330f729Sjoerg JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString,
2177330f729Sjoerg std::string &ErrorMessage,
2187330f729Sjoerg JSONCommandLineSyntax Syntax) {
2197330f729Sjoerg std::unique_ptr<llvm::MemoryBuffer> DatabaseBuffer(
220*e038c9c4Sjoerg llvm::MemoryBuffer::getMemBufferCopy(DatabaseString));
2217330f729Sjoerg std::unique_ptr<JSONCompilationDatabase> Database(
2227330f729Sjoerg new JSONCompilationDatabase(std::move(DatabaseBuffer), Syntax));
2237330f729Sjoerg if (!Database->parse(ErrorMessage))
2247330f729Sjoerg return nullptr;
2257330f729Sjoerg return Database;
2267330f729Sjoerg }
2277330f729Sjoerg
2287330f729Sjoerg std::vector<CompileCommand>
getCompileCommands(StringRef FilePath) const2297330f729Sjoerg JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
2307330f729Sjoerg SmallString<128> NativeFilePath;
2317330f729Sjoerg llvm::sys::path::native(FilePath, NativeFilePath);
2327330f729Sjoerg
2337330f729Sjoerg std::string Error;
2347330f729Sjoerg llvm::raw_string_ostream ES(Error);
2357330f729Sjoerg StringRef Match = MatchTrie.findEquivalent(NativeFilePath, ES);
2367330f729Sjoerg if (Match.empty())
2377330f729Sjoerg return {};
2387330f729Sjoerg const auto CommandsRefI = IndexByFile.find(Match);
2397330f729Sjoerg if (CommandsRefI == IndexByFile.end())
2407330f729Sjoerg return {};
2417330f729Sjoerg std::vector<CompileCommand> Commands;
2427330f729Sjoerg getCommands(CommandsRefI->getValue(), Commands);
2437330f729Sjoerg return Commands;
2447330f729Sjoerg }
2457330f729Sjoerg
2467330f729Sjoerg std::vector<std::string>
getAllFiles() const2477330f729Sjoerg JSONCompilationDatabase::getAllFiles() const {
2487330f729Sjoerg std::vector<std::string> Result;
2497330f729Sjoerg for (const auto &CommandRef : IndexByFile)
2507330f729Sjoerg Result.push_back(CommandRef.first().str());
2517330f729Sjoerg return Result;
2527330f729Sjoerg }
2537330f729Sjoerg
2547330f729Sjoerg std::vector<CompileCommand>
getAllCompileCommands() const2557330f729Sjoerg JSONCompilationDatabase::getAllCompileCommands() const {
2567330f729Sjoerg std::vector<CompileCommand> Commands;
2577330f729Sjoerg getCommands(AllCommands, Commands);
2587330f729Sjoerg return Commands;
2597330f729Sjoerg }
2607330f729Sjoerg
stripExecutableExtension(llvm::StringRef Name)2617330f729Sjoerg static llvm::StringRef stripExecutableExtension(llvm::StringRef Name) {
2627330f729Sjoerg Name.consume_back(".exe");
2637330f729Sjoerg return Name;
2647330f729Sjoerg }
2657330f729Sjoerg
2667330f729Sjoerg // There are compiler-wrappers (ccache, distcc, gomacc) that take the "real"
2677330f729Sjoerg // compiler as an argument, e.g. distcc gcc -O3 foo.c.
2687330f729Sjoerg // These end up in compile_commands.json when people set CC="distcc gcc".
2697330f729Sjoerg // Clang's driver doesn't understand this, so we need to unwrap.
unwrapCommand(std::vector<std::string> & Args)2707330f729Sjoerg static bool unwrapCommand(std::vector<std::string> &Args) {
2717330f729Sjoerg if (Args.size() < 2)
2727330f729Sjoerg return false;
2737330f729Sjoerg StringRef Wrapper =
2747330f729Sjoerg stripExecutableExtension(llvm::sys::path::filename(Args.front()));
275*e038c9c4Sjoerg if (Wrapper == "distcc" || Wrapper == "gomacc" || Wrapper == "ccache" ||
276*e038c9c4Sjoerg Wrapper == "sccache") {
2777330f729Sjoerg // Most of these wrappers support being invoked 3 ways:
2787330f729Sjoerg // `distcc g++ file.c` This is the mode we're trying to match.
2797330f729Sjoerg // We need to drop `distcc`.
2807330f729Sjoerg // `distcc file.c` This acts like compiler is cc or similar.
2817330f729Sjoerg // Clang's driver can handle this, no change needed.
2827330f729Sjoerg // `g++ file.c` g++ is a symlink to distcc.
2837330f729Sjoerg // We don't even notice this case, and all is well.
2847330f729Sjoerg //
2857330f729Sjoerg // We need to distinguish between the first and second case.
2867330f729Sjoerg // The wrappers themselves don't take flags, so Args[1] is a compiler flag,
2877330f729Sjoerg // an input file, or a compiler. Inputs have extensions, compilers don't.
2887330f729Sjoerg bool HasCompiler =
2897330f729Sjoerg (Args[1][0] != '-') &&
2907330f729Sjoerg !llvm::sys::path::has_extension(stripExecutableExtension(Args[1]));
2917330f729Sjoerg if (HasCompiler) {
2927330f729Sjoerg Args.erase(Args.begin());
2937330f729Sjoerg return true;
2947330f729Sjoerg }
2957330f729Sjoerg // If !HasCompiler, wrappers act like GCC. Fine: so do we.
2967330f729Sjoerg }
2977330f729Sjoerg return false;
2987330f729Sjoerg }
2997330f729Sjoerg
3007330f729Sjoerg static std::vector<std::string>
nodeToCommandLine(JSONCommandLineSyntax Syntax,const std::vector<llvm::yaml::ScalarNode * > & Nodes)3017330f729Sjoerg nodeToCommandLine(JSONCommandLineSyntax Syntax,
3027330f729Sjoerg const std::vector<llvm::yaml::ScalarNode *> &Nodes) {
3037330f729Sjoerg SmallString<1024> Storage;
3047330f729Sjoerg std::vector<std::string> Arguments;
3057330f729Sjoerg if (Nodes.size() == 1)
3067330f729Sjoerg Arguments = unescapeCommandLine(Syntax, Nodes[0]->getValue(Storage));
3077330f729Sjoerg else
3087330f729Sjoerg for (const auto *Node : Nodes)
309*e038c9c4Sjoerg Arguments.push_back(std::string(Node->getValue(Storage)));
3107330f729Sjoerg // There may be multiple wrappers: using distcc and ccache together is common.
3117330f729Sjoerg while (unwrapCommand(Arguments))
3127330f729Sjoerg ;
3137330f729Sjoerg return Arguments;
3147330f729Sjoerg }
3157330f729Sjoerg
getCommands(ArrayRef<CompileCommandRef> CommandsRef,std::vector<CompileCommand> & Commands) const3167330f729Sjoerg void JSONCompilationDatabase::getCommands(
3177330f729Sjoerg ArrayRef<CompileCommandRef> CommandsRef,
3187330f729Sjoerg std::vector<CompileCommand> &Commands) const {
3197330f729Sjoerg for (const auto &CommandRef : CommandsRef) {
3207330f729Sjoerg SmallString<8> DirectoryStorage;
3217330f729Sjoerg SmallString<32> FilenameStorage;
3227330f729Sjoerg SmallString<32> OutputStorage;
3237330f729Sjoerg auto Output = std::get<3>(CommandRef);
3247330f729Sjoerg Commands.emplace_back(
3257330f729Sjoerg std::get<0>(CommandRef)->getValue(DirectoryStorage),
3267330f729Sjoerg std::get<1>(CommandRef)->getValue(FilenameStorage),
3277330f729Sjoerg nodeToCommandLine(Syntax, std::get<2>(CommandRef)),
3287330f729Sjoerg Output ? Output->getValue(OutputStorage) : "");
3297330f729Sjoerg }
3307330f729Sjoerg }
3317330f729Sjoerg
parse(std::string & ErrorMessage)3327330f729Sjoerg bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
3337330f729Sjoerg llvm::yaml::document_iterator I = YAMLStream.begin();
3347330f729Sjoerg if (I == YAMLStream.end()) {
3357330f729Sjoerg ErrorMessage = "Error while parsing YAML.";
3367330f729Sjoerg return false;
3377330f729Sjoerg }
3387330f729Sjoerg llvm::yaml::Node *Root = I->getRoot();
3397330f729Sjoerg if (!Root) {
3407330f729Sjoerg ErrorMessage = "Error while parsing YAML.";
3417330f729Sjoerg return false;
3427330f729Sjoerg }
3437330f729Sjoerg auto *Array = dyn_cast<llvm::yaml::SequenceNode>(Root);
3447330f729Sjoerg if (!Array) {
3457330f729Sjoerg ErrorMessage = "Expected array.";
3467330f729Sjoerg return false;
3477330f729Sjoerg }
3487330f729Sjoerg for (auto &NextObject : *Array) {
3497330f729Sjoerg auto *Object = dyn_cast<llvm::yaml::MappingNode>(&NextObject);
3507330f729Sjoerg if (!Object) {
3517330f729Sjoerg ErrorMessage = "Expected object.";
3527330f729Sjoerg return false;
3537330f729Sjoerg }
3547330f729Sjoerg llvm::yaml::ScalarNode *Directory = nullptr;
3557330f729Sjoerg llvm::Optional<std::vector<llvm::yaml::ScalarNode *>> Command;
3567330f729Sjoerg llvm::yaml::ScalarNode *File = nullptr;
3577330f729Sjoerg llvm::yaml::ScalarNode *Output = nullptr;
3587330f729Sjoerg for (auto& NextKeyValue : *Object) {
3597330f729Sjoerg auto *KeyString = dyn_cast<llvm::yaml::ScalarNode>(NextKeyValue.getKey());
3607330f729Sjoerg if (!KeyString) {
3617330f729Sjoerg ErrorMessage = "Expected strings as key.";
3627330f729Sjoerg return false;
3637330f729Sjoerg }
3647330f729Sjoerg SmallString<10> KeyStorage;
3657330f729Sjoerg StringRef KeyValue = KeyString->getValue(KeyStorage);
3667330f729Sjoerg llvm::yaml::Node *Value = NextKeyValue.getValue();
3677330f729Sjoerg if (!Value) {
3687330f729Sjoerg ErrorMessage = "Expected value.";
3697330f729Sjoerg return false;
3707330f729Sjoerg }
3717330f729Sjoerg auto *ValueString = dyn_cast<llvm::yaml::ScalarNode>(Value);
3727330f729Sjoerg auto *SequenceString = dyn_cast<llvm::yaml::SequenceNode>(Value);
373*e038c9c4Sjoerg if (KeyValue == "arguments") {
374*e038c9c4Sjoerg if (!SequenceString) {
3757330f729Sjoerg ErrorMessage = "Expected sequence as value.";
3767330f729Sjoerg return false;
3777330f729Sjoerg }
3787330f729Sjoerg Command = std::vector<llvm::yaml::ScalarNode *>();
3797330f729Sjoerg for (auto &Argument : *SequenceString) {
3807330f729Sjoerg auto *Scalar = dyn_cast<llvm::yaml::ScalarNode>(&Argument);
3817330f729Sjoerg if (!Scalar) {
3827330f729Sjoerg ErrorMessage = "Only strings are allowed in 'arguments'.";
3837330f729Sjoerg return false;
3847330f729Sjoerg }
3857330f729Sjoerg Command->push_back(Scalar);
3867330f729Sjoerg }
387*e038c9c4Sjoerg } else {
388*e038c9c4Sjoerg if (!ValueString) {
389*e038c9c4Sjoerg ErrorMessage = "Expected string as value.";
390*e038c9c4Sjoerg return false;
391*e038c9c4Sjoerg }
392*e038c9c4Sjoerg if (KeyValue == "directory") {
393*e038c9c4Sjoerg Directory = ValueString;
3947330f729Sjoerg } else if (KeyValue == "command") {
3957330f729Sjoerg if (!Command)
3967330f729Sjoerg Command = std::vector<llvm::yaml::ScalarNode *>(1, ValueString);
3977330f729Sjoerg } else if (KeyValue == "file") {
3987330f729Sjoerg File = ValueString;
3997330f729Sjoerg } else if (KeyValue == "output") {
4007330f729Sjoerg Output = ValueString;
4017330f729Sjoerg } else {
402*e038c9c4Sjoerg ErrorMessage =
403*e038c9c4Sjoerg ("Unknown key: \"" + KeyString->getRawValue() + "\"").str();
4047330f729Sjoerg return false;
4057330f729Sjoerg }
4067330f729Sjoerg }
407*e038c9c4Sjoerg }
4087330f729Sjoerg if (!File) {
4097330f729Sjoerg ErrorMessage = "Missing key: \"file\".";
4107330f729Sjoerg return false;
4117330f729Sjoerg }
4127330f729Sjoerg if (!Command) {
4137330f729Sjoerg ErrorMessage = "Missing key: \"command\" or \"arguments\".";
4147330f729Sjoerg return false;
4157330f729Sjoerg }
4167330f729Sjoerg if (!Directory) {
4177330f729Sjoerg ErrorMessage = "Missing key: \"directory\".";
4187330f729Sjoerg return false;
4197330f729Sjoerg }
4207330f729Sjoerg SmallString<8> FileStorage;
4217330f729Sjoerg StringRef FileName = File->getValue(FileStorage);
4227330f729Sjoerg SmallString<128> NativeFilePath;
4237330f729Sjoerg if (llvm::sys::path::is_relative(FileName)) {
4247330f729Sjoerg SmallString<8> DirectoryStorage;
4257330f729Sjoerg SmallString<128> AbsolutePath(
4267330f729Sjoerg Directory->getValue(DirectoryStorage));
4277330f729Sjoerg llvm::sys::path::append(AbsolutePath, FileName);
4287330f729Sjoerg llvm::sys::path::remove_dots(AbsolutePath, /*remove_dot_dot=*/ true);
4297330f729Sjoerg llvm::sys::path::native(AbsolutePath, NativeFilePath);
4307330f729Sjoerg } else {
4317330f729Sjoerg llvm::sys::path::native(FileName, NativeFilePath);
4327330f729Sjoerg }
4337330f729Sjoerg auto Cmd = CompileCommandRef(Directory, File, *Command, Output);
4347330f729Sjoerg IndexByFile[NativeFilePath].push_back(Cmd);
4357330f729Sjoerg AllCommands.push_back(Cmd);
4367330f729Sjoerg MatchTrie.insert(NativeFilePath);
4377330f729Sjoerg }
4387330f729Sjoerg return true;
4397330f729Sjoerg }
440