diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 9a32ee406523cc231612ee698d5869095ba29184..8e16ef1c6cfbb3aab974d65edc522898d2a6970d 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,3 +1,3 @@
 add_subdirectory(clang-interpreter)
 add_subdirectory(PrintFunctionNames)
-
+add_subdirectory(Tooling)
diff --git a/examples/Tooling/CMakeLists.txt b/examples/Tooling/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..257d3ea8eaa304939b93f7407404faffcac1d2f1
--- /dev/null
+++ b/examples/Tooling/CMakeLists.txt
@@ -0,0 +1,6 @@
+set(LLVM_USED_LIBS clangTooling clangBasic)
+
+add_clang_executable(clang-check
+  ClangCheck.cpp
+  )
+
diff --git a/examples/Tooling/ClangCheck.cpp b/examples/Tooling/ClangCheck.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9f0b1dde7061c573dd9452502527306ddbf62692
--- /dev/null
+++ b/examples/Tooling/ClangCheck.cpp
@@ -0,0 +1,108 @@
+//===- examples/Tooling/ClangCheck.cpp - Clang check tool -----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file implements a clang-check tool that runs the
+//  clang::SyntaxOnlyAction over a number of translation units.
+//
+//  Usage:
+//  clang-check <cmake-output-dir> <file1> <file2> ...
+//
+//  Where <cmake-output-dir> is a CMake build directory in which a file named
+//  compile_commands.json exists (enable -DCMAKE_EXPORT_COMPILE_COMMANDS in
+//  CMake to get this output).
+//
+//  <file1> ... specify the paths of files in the CMake source tree. This  path
+//  is looked up in the compile command database. If the path of a file is
+//  absolute, it needs to point into CMake's source tree. If the path is
+//  relative, the current working directory needs to be in the CMake source
+//  tree and the file must be in a subdirectory of the current working
+//  directory. "./" prefixes in the relative files will be automatically
+//  removed, but the rest of a relative path must be a suffix of a path in
+//  the compile command line database.
+//
+//  For example, to use clang-check on all files in a subtree of the source
+//  tree, use:
+//  /path/to/cmake/sources $ find . -name '*.cpp' \
+//      |xargs clang-check /path/to/cmake/build
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/system_error.h"
+
+/// \brief Returns the absolute path of 'File', by prepending it with
+/// 'BaseDirectory' if 'File' is not absolute. Otherwise returns 'File'.
+/// If 'File' starts with "./", the returned path will not contain the "./".
+/// Otherwise, the returned path will contain the literal path-concatenation of
+/// 'BaseDirectory' and 'File'.
+///
+/// \param File Either an absolute or relative path.
+/// \param BaseDirectory An absolute path.
+///
+/// FIXME: Put this somewhere where it is more generally available.
+static std::string GetAbsolutePath(
+    llvm::StringRef File, llvm::StringRef BaseDirectory) {
+  assert(llvm::sys::path::is_absolute(BaseDirectory));
+  if (llvm::sys::path::is_absolute(File)) {
+    return File;
+  }
+  llvm::StringRef RelativePath(File);
+  if (RelativePath.startswith("./")) {
+    RelativePath = RelativePath.substr(strlen("./"));
+  }
+  llvm::SmallString<1024> AbsolutePath(BaseDirectory);
+  llvm::sys::path::append(AbsolutePath, RelativePath);
+  return AbsolutePath.str();
+}
+
+int main(int argc, char **argv) {
+  if (argc < 3) {
+    llvm::outs() << "Usage: " << argv[0] << " <cmake-output-dir> "
+                 << "<file1> <file2> ...\n";
+    return 1;
+  }
+  // FIXME: We should pull how to find the database into the Tooling package.
+  llvm::OwningPtr<llvm::MemoryBuffer> JsonDatabase;
+  llvm::SmallString<1024> JsonDatabasePath(argv[1]);
+  llvm::sys::path::append(JsonDatabasePath, "compile_commands.json");
+  llvm::error_code Result =
+      llvm::MemoryBuffer::getFile(JsonDatabasePath, JsonDatabase);
+  if (Result != 0) {
+    llvm::outs() << "Error while opening JSON database: " << Result.message()
+                 << "\n";
+    return 1;
+  }
+  llvm::StringRef BaseDirectory(::getenv("PWD"));
+  for (int I = 2; I < argc; ++I) {
+    llvm::SmallString<1024> File(GetAbsolutePath(argv[I], BaseDirectory));
+    llvm::outs() << "Processing " << File << ".\n";
+    std::string ErrorMessage;
+    clang::tooling::CompileCommand LookupResult =
+        clang::tooling::FindCompileArgsInJsonDatabase(
+            File.str(), JsonDatabase->getBuffer(), ErrorMessage);
+    if (!LookupResult.CommandLine.empty()) {
+      if (!clang::tooling::RunToolWithFlags(
+               new clang::SyntaxOnlyAction,
+               LookupResult.CommandLine.size(),
+               clang::tooling::CommandLineToArgv(
+                   &LookupResult.CommandLine).data())) {
+        llvm::outs() << "Error while processing " << File << ".\n";
+      }
+    } else {
+      llvm::outs() << "Skipping " << File << ". Command line not found.\n";
+    }
+  }
+  return 0;
+}
diff --git a/include/clang/Tooling/Tooling.h b/include/clang/Tooling/Tooling.h
index f07adeb832b4466201a582475f8938f5fb033770..6ccccd0bff0cf5fdf6c8a90853e2409133110e7e 100644
--- a/include/clang/Tooling/Tooling.h
+++ b/include/clang/Tooling/Tooling.h
@@ -16,6 +16,8 @@
 #define LLVM_CLANG_TOOLING_TOOLING_H
 
 #include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
 
 namespace clang {
 
@@ -26,12 +28,53 @@ namespace tooling {
 /// \brief Runs (and deletes) the tool on 'Code' with the -fsynatx-only flag.
 ///
 /// \param ToolAction The action to run over the code.
-//  \param Code C++ code.
+/// \param Code C++ code.
 ///
 /// \return - True if 'ToolAction' was successfully executed.
 bool RunSyntaxOnlyToolOnCode(
     clang::FrontendAction *ToolAction, llvm::StringRef Code);
 
+/// \brief Runs (and deletes) the tool with the given Clang flags.
+///
+/// \param ToolAction The action to run over the code.
+/// \param Argc The number of elements in Argv.
+/// \param Argv The command line arguments, including the path the binary
+/// was started with (Argv[0]).
+bool RunToolWithFlags(
+    clang::FrontendAction* ToolAction, int Argc, char *Argv[]);
+
+/// \brief Converts a vector<string> into a vector<char*> suitable to pass
+/// to main-style functions taking (int Argc, char *Argv[]).
+std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command);
+
+/// \brief Specifies the working directory and command of a compilation.
+struct CompileCommand {
+  /// \brief The working directory the command was executed from.
+  std::string Directory;
+
+  /// \brief The command line that was executed.
+  std::vector<std::string> CommandLine;
+};
+
+/// \brief Looks up the compile command for 'FileName' in 'JsonDatabase'.
+///
+/// \param FileName The path to an input file for which we want the compile
+/// command line. If the 'JsonDatabase' was created by CMake, this must be
+/// an absolute path inside the CMake source directory which does not have
+/// symlinks resolved.
+///
+/// \param JsonDatabase A JSON formatted list of compile commands. This lookup
+/// command supports only a subset of the JSON standard as written by CMake.
+///
+/// \param ErrorMessage If non-empty, an error occurred and 'ErrorMessage' will
+/// be set to contain the error message. In this case CompileCommand will
+/// contain an empty directory and command line.
+///
+/// \see JsonCompileCommandLineDatabase
+CompileCommand FindCompileArgsInJsonDatabase(
+    llvm::StringRef FileName, llvm::StringRef JsonDatabase,
+    std::string &ErrorMessage);
+
 } // end namespace tooling
 } // end namespace clang
 
diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt
index 6736d6537d3562cc2beca9fe64fd4864cae5bee1..f52cf6c8917f2550375fcf95b9e4994acc9770c1 100644
--- a/lib/Tooling/CMakeLists.txt
+++ b/lib/Tooling/CMakeLists.txt
@@ -1,5 +1,6 @@
 SET(LLVM_USED_LIBS clangBasic clangFrontend clangAST)
 
 add_clang_library(clangTooling
+  JsonCompileCommandLineDatabase.cpp
   Tooling.cpp
   )
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.cpp b/lib/Tooling/JsonCompileCommandLineDatabase.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7f027cfbead4fb13d7381f641ed5e6a4fb873382
--- /dev/null
+++ b/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
diff --git a/lib/Tooling/JsonCompileCommandLineDatabase.h b/lib/Tooling/JsonCompileCommandLineDatabase.h
new file mode 100644
index 0000000000000000000000000000000000000000..dcd1e4bbbb5b768a88e78cf68f9587514bf6ae45
--- /dev/null
+++ b/lib/Tooling/JsonCompileCommandLineDatabase.h
@@ -0,0 +1,107 @@
+//===--- JsonCompileCommandLineDatabase - Simple JSON database --*- C++ -*-===//
+//
+//                     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. It only supports the subset of the JSON standard
+//  that is needed to parse the CMake output.
+//  See http://www.json.org/ for the full standard.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
+#define LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
+
+#include "llvm/ADT/StringRef.h"
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tooling {
+
+/// \brief Converts a JSON escaped command line to a vector of arguments.
+///
+/// \param JsonEscapedCommandLine The escaped command line as a string. This
+/// is assumed to be escaped as a JSON string (e.g. " and \ are escaped).
+/// In addition, any arguments containing spaces are assumed to be \-escaped
+///
+/// For example, the input (|| denoting non C-escaped strings):
+///   |./call  a  \"b \\\" c \\\\ \"  d|
+/// would yield:
+///   [ |./call|, |a|, |b " c \ |, |d| ].
+std::vector<std::string> UnescapeJsonCommandLine(
+    llvm::StringRef JsonEscapedCommandLine);
+
+/// \brief Interface for users of the JsonCompileCommandLineParser.
+class CompileCommandHandler {
+ public:
+  virtual ~CompileCommandHandler() {};
+
+  /// \brief Called after all translation units are parsed.
+  virtual void EndTranslationUnits() {}
+
+  /// \brief Called at the end of a single translation unit.
+  virtual void EndTranslationUnit() {}
+
+  /// \brief Called for every (Key, Value) pair in a translation unit
+  /// description.
+  virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {}
+};
+
+/// \brief A JSON parser that supports the subset of JSON needed to parse
+/// JSON compile command line databases as written out by CMake.
+///
+/// The supported subset describes a list of compile command lines for
+/// each processed translation unit. The translation units are stored in a
+/// JSON array, where each translation unit is described by a JSON object
+/// containing (Key, Value) pairs for the working directory the compile command
+/// line was executed from, the main C/C++ input file of the translation unit
+/// and the actual compile command line, for example:
+/// [
+///   {
+///     "file":"/file.cpp",
+///     "directory":"/",
+///     "command":"/cc /file.cpp"
+///   }
+/// ]
+class JsonCompileCommandLineParser {
+ public:
+  /// \brief Create a parser on 'Input', calling 'CommandHandler' to handle the
+  /// parsed constructs. 'CommandHandler' may be NULL in order to just check
+  /// the validity of 'Input'.
+  JsonCompileCommandLineParser(const llvm::StringRef Input,
+                               CompileCommandHandler *CommandHandler);
+
+  /// \brief Parses the specified input. Returns true if no parsing errors were
+  /// foudn.
+  bool Parse();
+
+  /// \brief Returns an error message if Parse() returned false previously.
+  std::string GetErrorMessage() const;
+
+ private:
+  bool ParseTranslationUnits();
+  bool ParseTranslationUnit(bool First);
+  bool ParseObjectKeyValuePairs();
+  bool ParseString(llvm::StringRef &String);
+  bool Consume(char C);
+  bool ConsumeOrError(char C, llvm::StringRef Message);
+  void NextNonWhitespace();
+  bool IsWhitespace();
+  void SetExpectError(char C, llvm::StringRef Message);
+
+  const llvm::StringRef Input;
+  llvm::StringRef::iterator Position;
+  std::string ErrorMessage;
+  CompileCommandHandler * const CommandHandler;
+};
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_JSON_COMPILE_COMMAND_LINE_DATABASE_H
diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp
index a5bd1acf0e20ea76a3f136f12b0e7e0c1744ffde..8fc76b6b7543d0a6d930b0ac15193c62611dd916 100644
--- a/lib/Tooling/Tooling.cpp
+++ b/lib/Tooling/Tooling.cpp
@@ -29,14 +29,41 @@
 #include "clang/Frontend/FrontendAction.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
-
-#include <string>
+#include "JsonCompileCommandLineDatabase.h"
 #include <map>
-#include <vector>
+#include <cstdio>
 
 namespace clang {
 namespace tooling {
 
+namespace {
+
+// Checks that the input conforms to the argv[] convention as in
+// main().  Namely:
+//   - it must contain at least a program path,
+//   - argv[0], ..., and argv[argc - 1] mustn't be NULL, and
+//   - argv[argc] must be NULL.
+void ValidateArgv(int argc, char* argv[]) {
+  if (argc < 1) {
+    fprintf(stderr, "ERROR: argc is %d.  It must be >= 1.\n", argc);
+    abort();
+  }
+
+  for (int i = 0; i < argc; ++i) {
+    if (argv[i] == NULL) {
+      fprintf(stderr, "ERROR: argv[%d] is NULL.\n", i);
+      abort();
+    }
+  }
+
+  if (argv[argc] != NULL) {
+    fprintf(stderr, "ERROR: argv[argc] isn't NULL.\n");
+    abort();
+  }
+}
+
+} // end namespace
+
 // FIXME: This file contains structural duplication with other parts of the
 // code that sets up a compiler to run tools on it, and we should refactor
 // it to be based on the same framework.
@@ -156,6 +183,25 @@ std::vector<char*> CommandLineToArgv(const std::vector<std::string>* Command) {
   return Result;
 }
 
+bool RunToolWithFlags(
+    clang::FrontendAction* ToolAction, int Args, char* Argv[]) {
+  ValidateArgv(Args, Argv);
+  const llvm::OwningPtr<clang::Diagnostic> Diagnostics(NewTextDiagnostics());
+  const llvm::OwningPtr<clang::driver::Driver> Driver(
+      NewDriver(Diagnostics.get(), Argv[0]));
+  const llvm::OwningPtr<clang::driver::Compilation> Compilation(
+      Driver->BuildCompilation(llvm::ArrayRef<const char*>(Argv, Args)));
+  const clang::driver::ArgStringList* const CC1Args = GetCC1Arguments(
+      Diagnostics.get(), Compilation.get());
+  if (CC1Args == NULL) {
+    return false;
+  }
+  llvm::OwningPtr<clang::CompilerInvocation> Invocation(
+      NewInvocation(Diagnostics.get(), *CC1Args));
+  return RunInvocation(Argv[0], Compilation.get(), Invocation.take(),
+                       *CC1Args, ToolAction);
+}
+
 /// \brief Runs 'ToolAction' on the code specified by 'FileContents'.
 ///
 /// \param FileContents A mapping from file name to source code. For each
@@ -213,6 +259,64 @@ bool RunSyntaxOnlyToolOnCode(
       FileContents, ToolAction);
 }
 
+namespace {
+
+// A CompileCommandHandler implementation that finds compile commands for a
+// specific input file.
+//
+// FIXME: Implement early exit when JsonCompileCommandLineParser supports it.
+class FindHandler : public clang::tooling::CompileCommandHandler {
+ public:
+  explicit FindHandler(llvm::StringRef File)
+      : FileToMatch(File), FoundMatchingCommand(false) {};
+
+  virtual void EndTranslationUnits() {
+    if (!FoundMatchingCommand && ErrorMessage.empty()) {
+      ErrorMessage = "ERROR: No matching command found.";
+    }
+  }
+
+  virtual void EndTranslationUnit() {
+    if (File == FileToMatch) {
+      FoundMatchingCommand = true;
+      MatchingCommand.Directory = Directory;
+      MatchingCommand.CommandLine = UnescapeJsonCommandLine(Command);
+    }
+  }
+
+  virtual void HandleKeyValue(llvm::StringRef Key, llvm::StringRef Value) {
+    if (Key == "directory") { Directory = Value; }
+    else if (Key == "file") { File = Value; }
+    else if (Key == "command") { Command = Value; }
+    else {
+      ErrorMessage = (llvm::Twine("Unknown key: \"") + Key + "\"").str();
+    }
+  }
+
+  const llvm::StringRef FileToMatch;
+  bool FoundMatchingCommand;
+  CompileCommand MatchingCommand;
+  std::string ErrorMessage;
+
+  llvm::StringRef Directory;
+  llvm::StringRef File;
+  llvm::StringRef Command;
+};
+
+} // end namespace
+
+CompileCommand FindCompileArgsInJsonDatabase(
+    llvm::StringRef FileName, llvm::StringRef JsonDatabase,
+    std::string &ErrorMessage) {
+  FindHandler find_handler(FileName);
+  JsonCompileCommandLineParser parser(JsonDatabase, &find_handler);
+  if (!parser.Parse()) {
+    ErrorMessage = parser.GetErrorMessage();
+    return CompileCommand();
+  }
+  return find_handler.MatchingCommand;
+}
+
 } // end namespace tooling
 } // end namespace clang
 
diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt
index dd6bad5fa90020dfbd86ac62de8ba4a09750cb47..f7f495ee9dd77dd392b3c2db29b8e663f2a7d538 100644
--- a/unittests/CMakeLists.txt
+++ b/unittests/CMakeLists.txt
@@ -64,3 +64,8 @@ add_clang_unittest(Tooling
   Tooling/ToolingTest.cpp
   USED_LIBS gtest gtest_main clangTooling
  )
+
+add_clang_unittest(JsonCompileCommandLineDatabase
+  Tooling/JsonCompileCommandLineDatabaseTest.cpp
+  USED_LIBS gtest gtest_main clangTooling
+ )
diff --git a/unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp b/unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..d875293e5d857646a988d5892997c7e2ed7fdaa3
--- /dev/null
+++ b/unittests/Tooling/JsonCompileCommandLineDatabaseTest.cpp
@@ -0,0 +1,232 @@
+//===- unittest/Tooling/JsonCompileCommandLineDatabaseTest ----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../../lib/Tooling/JsonCompileCommandLineDatabase.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tooling {
+
+TEST(UnescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
+  std::vector<std::string> Result = UnescapeJsonCommandLine("");
+  EXPECT_TRUE(Result.empty());
+}
+
+TEST(UnescapeJsonCommandLine, SplitsOnSpaces) {
+  std::vector<std::string> Result = UnescapeJsonCommandLine("a b c");
+  ASSERT_EQ(3ul, Result.size());
+  EXPECT_EQ("a", Result[0]);
+  EXPECT_EQ("b", Result[1]);
+  EXPECT_EQ("c", Result[2]);
+}
+
+TEST(UnescapeJsonCommandLine, MungesMultipleSpaces) {
+  std::vector<std::string> Result = UnescapeJsonCommandLine("   a   b   ");
+  ASSERT_EQ(2ul, Result.size());
+  EXPECT_EQ("a", Result[0]);
+  EXPECT_EQ("b", Result[1]);
+}
+
+TEST(UnescapeJsonCommandLine, UnescapesBackslashCharacters) {
+  std::vector<std::string> Backslash = UnescapeJsonCommandLine("a\\\\\\\\");
+  ASSERT_EQ(1ul, Backslash.size());
+  EXPECT_EQ("a\\", Backslash[0]);
+  std::vector<std::string> Quote = UnescapeJsonCommandLine("a\\\\\\\"");
+  ASSERT_EQ(1ul, Quote.size());
+  EXPECT_EQ("a\"", Quote[0]);
+}
+
+TEST(UnescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
+  std::vector<std::string> Result = UnescapeJsonCommandLine("\\\"  a  b  \\\"");
+  ASSERT_EQ(1ul, Result.size());
+  EXPECT_EQ("  a  b  ", Result[0]);
+}
+
+TEST(UnescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
+  std::vector<std::string> Result = UnescapeJsonCommandLine(
+      "  \\\" a \\\"  \\\" b \\\"  ");
+  ASSERT_EQ(2ul, Result.size());
+  EXPECT_EQ(" a ", Result[0]);
+  EXPECT_EQ(" b ", Result[1]);
+}
+
+TEST(UnescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
+  std::vector<std::string> Result = UnescapeJsonCommandLine(
+      "\\\"\\\"\\\"\\\"");
+  ASSERT_EQ(1ul, Result.size());
+  EXPECT_TRUE(Result[0].empty()) << Result[0];
+}
+
+TEST(UnescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
+  std::vector<std::string> Result = UnescapeJsonCommandLine(
+      "\\\"\\\\\\\"\\\"");
+  ASSERT_EQ(1ul, Result.size());
+  EXPECT_EQ("\"", Result[0]);
+}
+
+TEST(UnescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
+  std::vector<std::string> Result = UnescapeJsonCommandLine(
+      "  \\\\\\\"  \\\"a \\\\\\\" b \\\"     \\\"and\\\\\\\\c\\\"   \\\\\\\"");
+  ASSERT_EQ(4ul, Result.size());
+  EXPECT_EQ("\"", Result[0]);
+  EXPECT_EQ("a \" b ", Result[1]);
+  EXPECT_EQ("and\\c", Result[2]);
+  EXPECT_EQ("\"", Result[3]);
+}
+
+TEST(UnescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
+  std::vector<std::string> QuotedNoSpaces = UnescapeJsonCommandLine(
+      "\\\"a\\\"\\\"b\\\"");
+  ASSERT_EQ(1ul, QuotedNoSpaces.size());
+  EXPECT_EQ("ab", QuotedNoSpaces[0]);
+
+  std::vector<std::string> MixedNoSpaces = UnescapeJsonCommandLine(
+      "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
+  ASSERT_EQ(1ul, MixedNoSpaces.size());
+  EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
+}
+
+TEST(JsonCompileCommandLineParser, FailsOnEmptyString) {
+  JsonCompileCommandLineParser Parser("", NULL);
+  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, DoesNotReadAfterInput) {
+  JsonCompileCommandLineParser Parser(llvm::StringRef(NULL, 0), NULL);
+  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesEmptyArray) {
+  JsonCompileCommandLineParser Parser("[]", NULL);
+  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsIfNotClosingArray) {
+  JsonCompileCommandLineParser JustOpening("[", NULL);
+  EXPECT_FALSE(JustOpening.Parse()) << JustOpening.GetErrorMessage();
+  JsonCompileCommandLineParser WithSpaces("  [  ", NULL);
+  EXPECT_FALSE(WithSpaces.Parse()) << WithSpaces.GetErrorMessage();
+  JsonCompileCommandLineParser WithGarbage("  [x", NULL);
+  EXPECT_FALSE(WithGarbage.Parse()) << WithGarbage.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesEmptyArrayWithWhitespace) {
+  JsonCompileCommandLineParser Spaces("   [   ]   ", NULL);
+  EXPECT_TRUE(Spaces.Parse()) << Spaces.GetErrorMessage();
+  JsonCompileCommandLineParser AllWhites("\t\r\n[\t\n \t\r ]\t\r \n\n", NULL);
+  EXPECT_TRUE(AllWhites.Parse()) << AllWhites.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsIfNotStartingArray) {
+  JsonCompileCommandLineParser ObjectStart("{", NULL);
+  EXPECT_FALSE(ObjectStart.Parse()) << ObjectStart.GetErrorMessage();
+  // We don't implement a full JSON parser, and thus parse only a subset
+  // of valid JSON.
+  JsonCompileCommandLineParser Object("{}", NULL);
+  EXPECT_FALSE(Object.Parse()) << Object.GetErrorMessage();
+  JsonCompileCommandLineParser Character("x", NULL);
+  EXPECT_FALSE(Character.Parse()) << Character.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesEmptyObject) {
+  JsonCompileCommandLineParser Parser("[{}]", NULL);
+  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesObject) {
+  JsonCompileCommandLineParser Parser("[{\"a\":\"/b\"}]", NULL);
+  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesMultipleKeyValuePairsInObject) {
+  JsonCompileCommandLineParser Parser(
+      "[{\"a\":\"/b\",\"c\":\"d\",\"e\":\"f\"}]", NULL);
+  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsIfNotClosingObject) {
+  JsonCompileCommandLineParser MissingCloseOnEmpty("[{]", NULL);
+  EXPECT_FALSE(MissingCloseOnEmpty.Parse())
+      << MissingCloseOnEmpty.GetErrorMessage();
+  JsonCompileCommandLineParser MissingCloseAfterPair("[{\"a\":\"b\"]", NULL);
+  EXPECT_FALSE(MissingCloseAfterPair.Parse())
+      << MissingCloseAfterPair.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsIfMissingColon) {
+  JsonCompileCommandLineParser StringString("[{\"a\"\"/b\"}]", NULL);
+  EXPECT_FALSE(StringString.Parse()) << StringString.GetErrorMessage();
+  JsonCompileCommandLineParser StringSpaceString("[{\"a\" \"b\"}]", NULL);
+  EXPECT_FALSE(StringSpaceString.Parse())
+      << StringSpaceString.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsOnMissingQuote) {
+  JsonCompileCommandLineParser OpenQuote("[{a\":\"b\"}]", NULL);
+  EXPECT_FALSE(OpenQuote.Parse()) << OpenQuote.GetErrorMessage();
+  JsonCompileCommandLineParser CloseQuote("[{\"a\":\"b}]", NULL);
+  EXPECT_FALSE(CloseQuote.Parse()) << CloseQuote.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesEscapedQuotes) {
+  JsonCompileCommandLineParser Parser(
+      "[{\"a\":\"\\\"b\\\"  \\\" \\\"\"}]", NULL);
+  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesEmptyString) {
+  JsonCompileCommandLineParser Parser("[{\"a\":\"\"}]", NULL);
+  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsOnMissingString) {
+  JsonCompileCommandLineParser MissingValue("[{\"a\":}]", NULL);
+  EXPECT_FALSE(MissingValue.Parse()) << MissingValue.GetErrorMessage();
+  JsonCompileCommandLineParser MissingKey("[{:\"b\"}]", NULL);
+  EXPECT_FALSE(MissingKey.Parse()) << MissingKey.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesMultipleObjects) {
+  JsonCompileCommandLineParser Parser(
+      "["
+      " { \"a\" : \"b\" },"
+      " { \"a\" : \"b\" },"
+      " { \"a\" : \"b\" }"
+      "]", NULL);
+  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsOnMissingComma) {
+  JsonCompileCommandLineParser Parser(
+      "["
+      " { \"a\" : \"b\" }"
+      " { \"a\" : \"b\" }"
+      "]", NULL);
+  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, FailsOnSuperfluousComma) {
+  JsonCompileCommandLineParser Parser(
+      "[ { \"a\" : \"b\" }, ]", NULL);
+  EXPECT_FALSE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+TEST(JsonCompileCommandLineParser, ParsesSpacesInBetweenTokens) {
+  JsonCompileCommandLineParser Parser(
+      " \t \n\n \r [ \t \n\n \r"
+      " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
+      " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r,\t \n\n \r"
+      " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :"
+      " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r]\t \n\n \r",
+      NULL);
+  EXPECT_TRUE(Parser.Parse()) << Parser.GetErrorMessage();
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/unittests/Tooling/ToolingTest.cpp b/unittests/Tooling/ToolingTest.cpp
index da89c0ba1049bb0162620f6832980f7169fcc67f..6e5bc6b613e01041ffb7f1a9da5526ceef2e5b38 100644
--- a/unittests/Tooling/ToolingTest.cpp
+++ b/unittests/Tooling/ToolingTest.cpp
@@ -7,6 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "llvm/ADT/Twine.h"
 #include "clang/AST/ASTConsumer.h"
 #include "clang/AST/DeclCXX.h"
 #include "clang/AST/DeclGroup.h"
@@ -86,6 +87,89 @@ TEST(RunSyntaxOnlyToolOnCode, FindsClassDecl) {
   EXPECT_FALSE(FoundClassDeclX);
 }
 
+TEST(FindCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
+  std::string ErrorMessage;
+  CompileCommand NotFound = FindCompileArgsInJsonDatabase(
+      "a-file.cpp", "", ErrorMessage);
+  EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
+  EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
+}
+
+TEST(FindCompileArgsInJsonDatabase, ReadsSingleEntry) {
+  llvm::StringRef Directory("/some/directory");
+  llvm::StringRef FileName("/path/to/a-file.cpp");
+  llvm::StringRef Command("/path/to/compiler and some arguments");
+  std::string ErrorMessage;
+  CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
+      FileName,
+      (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
+                     "\"command\":\"" + Command + "\","
+                     "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
+  EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
+  ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
+  EXPECT_EQ("/path/to/compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
+  EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
+  EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
+  EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
+
+  CompileCommand NotFound = FindCompileArgsInJsonDatabase(
+      "a-file.cpp",
+      (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
+                     "\"command\":\"" + Command + "\","
+                     "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
+  EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
+  EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
+}
+
+TEST(FindCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
+  llvm::StringRef Directory("/some/directory");
+  llvm::StringRef FileName("/path/to/a-file.cpp");
+  llvm::StringRef Command("\\\"/path to compiler\\\" \\\"and an argument\\\"");
+  std::string ErrorMessage;
+  CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
+      FileName,
+      (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
+                     "\"command\":\"" + Command + "\","
+                     "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
+  ASSERT_EQ(2u, FoundCommand.CommandLine.size());
+  EXPECT_EQ("/path to compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
+  EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
+}
+
+TEST(FindCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
+  llvm::StringRef Directory("/some directory / with spaces");
+  llvm::StringRef FileName("/path/to/a-file.cpp");
+  llvm::StringRef Command("a command");
+  std::string ErrorMessage;
+  CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
+      FileName,
+      (llvm::Twine("[{\"directory\":\"") + Directory + "\"," +
+                     "\"command\":\"" + Command + "\","
+                     "\"file\":\"" + FileName + "\"}]").str(), ErrorMessage);
+  EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
+}
+
+TEST(FindCompileArgsInJsonDatabase, FindsEntry) {
+  llvm::StringRef Directory("directory");
+  llvm::StringRef FileName("file");
+  llvm::StringRef Command("command");
+  std::string JsonDatabase = "[";
+  for (int I = 0; I < 10; ++I) {
+    if (I > 0) JsonDatabase += ",";
+    JsonDatabase += (llvm::Twine(
+        "{\"directory\":\"") + Directory + llvm::Twine(I) + "\"," +
+         "\"command\":\"" + Command + llvm::Twine(I) + "\","
+         "\"file\":\"" + FileName + llvm::Twine(I) + "\"}").str();
+  }
+  JsonDatabase += "]";
+  std::string ErrorMessage;
+  CompileCommand FoundCommand = FindCompileArgsInJsonDatabase(
+      "file4", JsonDatabase, ErrorMessage);
+  EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage;
+  ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
+  EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
+}
+
 } // end namespace tooling
 } // end namespace clang