From c661f1467a84a0a3a83a396b067188b647844ee9 Mon Sep 17 00:00:00 2001 From: Manuel Klimek Date: Tue, 17 Apr 2012 16:54:26 +0000 Subject: [PATCH] Switches the JSONCompilationDatabase to use the YAML parser. This will allow us to delete the JSON parser from llvm. The biggest change is a general change of strategy - instead of storing StringRef's to the values for the command line and directory in the input buffer, we store ScalarNode*'s. The reason is that the YAML parser's getRawValue on ScalarNodes returns a string that includes the quotes in case of double quoted strings. For the same reason we're removing the JSON parsing part of the command line parsing - this means an extra copy for a command line when it is requested (and only when it is requested). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@154929 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Tooling/CompilationDatabase.h | 17 +++-- lib/Tooling/CompilationDatabase.cpp | 81 ++++++++++++--------- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h index 3430320b51..60e9a080dc 100644 --- a/include/clang/Tooling/CompilationDatabase.h +++ b/include/clang/Tooling/CompilationDatabase.h @@ -34,13 +34,11 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/YAMLParser.h" #include #include -namespace llvm { -class MemoryBuffer; -} // end namespace llvm - namespace clang { namespace tooling { @@ -139,7 +137,7 @@ public: private: /// \brief Constructs a JSON compilation database on a memory buffer. JSONCompilationDatabase(llvm::MemoryBuffer *Database) - : Database(Database) {} + : Database(Database), YAMLStream(Database->getBuffer(), SM) {} /// \brief Parses the database file and creates the index. /// @@ -147,14 +145,17 @@ private: /// failed. bool parse(std::string &ErrorMessage); - // Tuple (directory, commandline) where 'commandline' is a JSON escaped bash - // escaped command line. - typedef std::pair CompileCommandRef; + // Tuple (directory, commandline) where 'commandline' pointing to the + // corresponding nodes in the YAML stream. + typedef std::pair CompileCommandRef; // Maps file paths to the compile command lines for that file. llvm::StringMap< std::vector > IndexByFile; llvm::OwningPtr Database; + llvm::SourceMgr SM; + llvm::yaml::Stream YAMLStream; }; } // end namespace tooling diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp index eea1055f49..f8993658da 100644 --- a/lib/Tooling/CompilationDatabase.cpp +++ b/lib/Tooling/CompilationDatabase.cpp @@ -13,7 +13,7 @@ #include "clang/Tooling/CompilationDatabase.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/JSONParser.h" +#include "llvm/Support/YAMLParser.h" #include "llvm/Support/Path.h" #include "llvm/Support/system_error.h" @@ -22,10 +22,10 @@ namespace tooling { namespace { -/// \brief A parser for JSON escaped strings of command line arguments. +/// \brief A parser for escaped strings of command line arguments. /// /// Assumes \-escaping for quoted arguments (see the documentation of -/// unescapeJSONCommandLine(...)). +/// unescapeCommandLine(...)). class CommandLineArgumentParser { public: CommandLineArgumentParser(StringRef CommandLine) @@ -90,9 +90,6 @@ class CommandLineArgumentParser { bool next() { ++Position; - if (Position == Input.end()) return false; - // Remove the JSON escaping first. This is done unconditionally. - if (*Position == '\\') ++Position; return Position != Input.end(); } @@ -101,9 +98,9 @@ class CommandLineArgumentParser { std::vector CommandLine; }; -std::vector unescapeJSONCommandLine( - StringRef JSONEscapedCommandLine) { - CommandLineArgumentParser parser(JSONEscapedCommandLine); +std::vector unescapeCommandLine( + StringRef EscapedCommandLine) { + CommandLineArgumentParser parser(EscapedCommandLine); return parser.parse(); } @@ -162,65 +159,77 @@ JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const { const std::vector &CommandsRef = CommandsRefI->getValue(); std::vector Commands; for (int I = 0, E = CommandsRef.size(); I != E; ++I) { + llvm::SmallString<8> DirectoryStorage; + llvm::SmallString<1024> CommandStorage; Commands.push_back(CompileCommand( // FIXME: Escape correctly: - CommandsRef[I].first, - unescapeJSONCommandLine(CommandsRef[I].second))); + CommandsRef[I].first->getValue(DirectoryStorage), + unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage)))); } return Commands; } bool JSONCompilationDatabase::parse(std::string &ErrorMessage) { - llvm::SourceMgr SM; - llvm::JSONParser Parser(Database->getBuffer(), &SM); - llvm::JSONValue *Root = Parser.parseRoot(); + llvm::yaml::document_iterator I = YAMLStream.begin(); + if (I == YAMLStream.end()) { + ErrorMessage = "Error while parsing YAML."; + return false; + } + llvm::yaml::Node *Root = I->getRoot(); if (Root == NULL) { - ErrorMessage = "Error while parsing JSON."; + ErrorMessage = "Error while parsing YAML."; return false; } - llvm::JSONArray *Array = dyn_cast(Root); + llvm::yaml::SequenceNode *Array = + llvm::dyn_cast(Root); if (Array == NULL) { ErrorMessage = "Expected array."; return false; } - for (llvm::JSONArray::const_iterator AI = Array->begin(), AE = Array->end(); + for (llvm::yaml::SequenceNode::iterator AI = Array->begin(), + AE = Array->end(); AI != AE; ++AI) { - const llvm::JSONObject *Object = dyn_cast(*AI); + llvm::yaml::MappingNode *Object = + llvm::dyn_cast(&*AI); if (Object == NULL) { ErrorMessage = "Expected object."; return false; } - StringRef EntryDirectory; - StringRef EntryFile; - StringRef EntryCommand; - for (llvm::JSONObject::const_iterator KVI = Object->begin(), - KVE = Object->end(); + llvm::yaml::ScalarNode *Directory; + llvm::yaml::ScalarNode *Command; + llvm::SmallString<8> FileStorage; + llvm::StringRef File; + for (llvm::yaml::MappingNode::iterator KVI = Object->begin(), + KVE = Object->end(); KVI != KVE; ++KVI) { - const llvm::JSONValue *Value = (*KVI)->Value; + llvm::yaml::Node *Value = (*KVI).getValue(); if (Value == NULL) { ErrorMessage = "Expected value."; return false; } - const llvm::JSONString *ValueString = - dyn_cast(Value); + llvm::yaml::ScalarNode *ValueString = + llvm::dyn_cast(Value); if (ValueString == NULL) { ErrorMessage = "Expected string as value."; return false; } - if ((*KVI)->Key->getRawText() == "directory") { - EntryDirectory = ValueString->getRawText(); - } else if ((*KVI)->Key->getRawText() == "file") { - EntryFile = ValueString->getRawText(); - } else if ((*KVI)->Key->getRawText() == "command") { - EntryCommand = ValueString->getRawText(); + llvm::yaml::ScalarNode *KeyString = + llvm::dyn_cast((*KVI).getKey()); + llvm::SmallString<8> KeyStorage; + if (KeyString->getValue(KeyStorage) == "directory") { + Directory = ValueString; + } else if (KeyString->getValue(KeyStorage) == "command") { + Command = ValueString; + } else if (KeyString->getValue(KeyStorage) == "file") { + File = ValueString->getValue(FileStorage); } else { - ErrorMessage = (Twine("Unknown key: \"") + - (*KVI)->Key->getRawText() + "\"").str(); + ErrorMessage = ("Unknown key: \"" + + KeyString->getRawValue() + "\"").str(); return false; } } - IndexByFile[EntryFile].push_back( - CompileCommandRef(EntryDirectory, EntryCommand)); + IndexByFile[File].push_back( + CompileCommandRef(Directory, Command)); } return true; } -- 2.40.0