summaryrefslogtreecommitdiffstats
path: root/clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp
diff options
context:
space:
mode:
authorManuel Klimek <klimek@google.com>2011-04-27 16:39:14 +0000
committerManuel Klimek <klimek@google.com>2011-04-27 16:39:14 +0000
commit6825eebcd6e420e6d6415efefd6bfe75836ebe1e (patch)
tree5df643a09ca35c4d6ef0051d7ad0fb13f270c2b2 /clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp
parent27c0c9bb87cd535c684b00c1617e344067351dd2 (diff)
downloadbcm5719-llvm-6825eebcd6e420e6d6415efefd6bfe75836ebe1e.tar.gz
bcm5719-llvm-6825eebcd6e420e6d6415efefd6bfe75836ebe1e.zip
This is the next step in building the standalone tools infrastructure:
This patch simplifies writing of standalone Clang tools. As an example, we add clang-check, a tool that runs a syntax only frontend action over a .cc file. When you integrate this into your favorite editor, you get much faster feedback on your compilation errors, thus reducing your feedback cycle especially when writing new code. The tool depends on integration of an outstanding patch to CMake to work which allows you to always have a current compile command database in your cmake output directory when you set CMAKE_EXPORT_COMPILE_COMMANDS. llvm-svn: 130306
Diffstat (limited to 'clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp')
-rw-r--r--clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp214
1 files changed, 214 insertions, 0 deletions
diff --git a/clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp b/clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp
new file mode 100644
index 00000000000..7f027cfbead
--- /dev/null
+++ b/clang/lib/Tooling/JsonCompileCommandLineDatabase.cpp
@@ -0,0 +1,214 @@
+//===--- JsonCompileCommandLineDatabase.cpp - Simple JSON database --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements reading a compile command line database, as written
+// out for example by CMake.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JsonCompileCommandLineDatabase.h"
+#include "llvm/ADT/Twine.h"
+
+namespace clang {
+namespace tooling {
+
+namespace {
+
+// A parser for JSON escaped strings of command line arguments with \-escaping
+// for quoted arguments (see the documentation of UnescapeJsonCommandLine(...)).
+class CommandLineArgumentParser {
+ public:
+ CommandLineArgumentParser(llvm::StringRef CommandLine)
+ : Input(CommandLine), Position(Input.begin()-1) {}
+
+ std::vector<std::string> Parse() {
+ bool HasMoreInput = true;
+ while (HasMoreInput && NextNonWhitespace()) {
+ std::string Argument;
+ HasMoreInput = ParseStringInto(Argument);
+ CommandLine.push_back(Argument);
+ }
+ return CommandLine;
+ }
+
+ private:
+ // All private methods return true if there is more input available.
+
+ bool ParseStringInto(std::string &String) {
+ do {
+ if (*Position == '"') {
+ if (!ParseQuotedStringInto(String)) return false;
+ } else {
+ if (!ParseFreeStringInto(String)) return false;
+ }
+ } while (*Position != ' ');
+ return true;
+ }
+
+ bool ParseQuotedStringInto(std::string &String) {
+ if (!Next()) return false;
+ while (*Position != '"') {
+ if (!SkipEscapeCharacter()) return false;
+ String.push_back(*Position);
+ if (!Next()) return false;
+ }
+ return Next();
+ }
+
+ bool ParseFreeStringInto(std::string &String) {
+ do {
+ if (!SkipEscapeCharacter()) return false;
+ String.push_back(*Position);
+ if (!Next()) return false;
+ } while (*Position != ' ' && *Position != '"');
+ return true;
+ }
+
+ bool SkipEscapeCharacter() {
+ if (*Position == '\\') {
+ return Next();
+ }
+ return true;
+ }
+
+ bool NextNonWhitespace() {
+ do {
+ if (!Next()) return false;
+ } while (*Position == ' ');
+ return true;
+ }
+
+ 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();
+ }
+
+ const llvm::StringRef Input;
+ llvm::StringRef::iterator Position;
+ std::vector<std::string> CommandLine;
+};
+
+} // end namespace
+
+std::vector<std::string> UnescapeJsonCommandLine(
+ llvm::StringRef JsonEscapedCommandLine) {
+ CommandLineArgumentParser parser(JsonEscapedCommandLine);
+ return parser.Parse();
+}
+
+JsonCompileCommandLineParser::JsonCompileCommandLineParser(
+ const llvm::StringRef Input, CompileCommandHandler *CommandHandler)
+ : Input(Input), Position(Input.begin()-1), CommandHandler(CommandHandler) {}
+
+bool JsonCompileCommandLineParser::Parse() {
+ NextNonWhitespace();
+ return ParseTranslationUnits();
+}
+
+std::string JsonCompileCommandLineParser::GetErrorMessage() const {
+ return ErrorMessage;
+}
+
+bool JsonCompileCommandLineParser::ParseTranslationUnits() {
+ if (!ConsumeOrError('[', "at start of compile command file")) return false;
+ if (!ParseTranslationUnit(/*First=*/true)) return false;
+ while (Consume(',')) {
+ if (!ParseTranslationUnit(/*First=*/false)) return false;
+ }
+ if (!ConsumeOrError(']', "at end of array")) return false;
+ if (CommandHandler != NULL) {
+ CommandHandler->EndTranslationUnits();
+ }
+ return true;
+}
+
+bool JsonCompileCommandLineParser::ParseTranslationUnit(bool First) {
+ if (First) {
+ if (!Consume('{')) return true;
+ } else {
+ if (!ConsumeOrError('{', "at start of object")) return false;
+ }
+ if (!Consume('}')) {
+ if (!ParseObjectKeyValuePairs()) return false;
+ if (!ConsumeOrError('}', "at end of object")) return false;
+ }
+ if (CommandHandler != NULL) {
+ CommandHandler->EndTranslationUnit();
+ }
+ return true;
+}
+
+bool JsonCompileCommandLineParser::ParseObjectKeyValuePairs() {
+ do {
+ llvm::StringRef Key;
+ if (!ParseString(Key)) return false;
+ if (!ConsumeOrError(':', "between name and value")) return false;
+ llvm::StringRef Value;
+ if (!ParseString(Value)) return false;
+ if (CommandHandler != NULL) {
+ CommandHandler->HandleKeyValue(Key, Value);
+ }
+ } while (Consume(','));
+ return true;
+}
+
+bool JsonCompileCommandLineParser::ParseString(llvm::StringRef &String) {
+ if (!ConsumeOrError('"', "at start of string")) return false;
+ llvm::StringRef::iterator First = Position;
+ llvm::StringRef::iterator Last = Position;
+ while (!Consume('"')) {
+ Consume('\\');
+ ++Position;
+ // We need to store Position, as Consume will change Last before leaving
+ // the loop.
+ Last = Position;
+ }
+ String = llvm::StringRef(First, Last - First);
+ return true;
+}
+
+bool JsonCompileCommandLineParser::Consume(char C) {
+ if (Position == Input.end()) return false;
+ if (*Position != C) return false;
+ NextNonWhitespace();
+ return true;
+}
+
+bool JsonCompileCommandLineParser::ConsumeOrError(
+ char C, llvm::StringRef Message) {
+ if (!Consume(C)) {
+ SetExpectError(C, Message);
+ return false;
+ }
+ return true;
+}
+
+void JsonCompileCommandLineParser::SetExpectError(
+ char C, llvm::StringRef Message) {
+ ErrorMessage = (llvm::Twine("'") + llvm::StringRef(&C, 1) +
+ "' expected " + Message + ".").str();
+}
+
+void JsonCompileCommandLineParser::NextNonWhitespace() {
+ do {
+ ++Position;
+ } while (IsWhitespace());
+}
+
+bool JsonCompileCommandLineParser::IsWhitespace() {
+ if (Position == Input.end()) return false;
+ return (*Position == ' ' || *Position == '\t' ||
+ *Position == '\n' || *Position == '\r');
+}
+
+} // end namespace tooling
+} // end namespace clang
OpenPOWER on IntegriCloud