diff --git a/include/clang/Tooling/CompilationDatabase.h b/include/clang/Tooling/CompilationDatabase.h
index f78ffae..3a56636 100644
--- a/include/clang/Tooling/CompilationDatabase.h
+++ b/include/clang/Tooling/CompilationDatabase.h
@@ -34,7 +34,9 @@
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/PathV2.h"
 #include "llvm/Support/SourceMgr.h"
 #include "llvm/Support/YAMLParser.h"
 #include <string>
@@ -169,6 +171,66 @@ private:
   std::vector<CompileCommand> CompileCommands;
 };
 
+struct PathComparator {
+  virtual bool equivalent(const Twine &FileA, const Twine &FileB) const {
+    return FileA.str() == FileB.str() ||
+        llvm::sys::fs::equivalent(FileA, FileB);
+  }
+};
+
+/// \brief A trie to efficiently match against the entries of the compilation
+/// database in order of matching suffix length.
+///
+/// When a clang tool is supposed to operate on a specific file, we have to
+/// find the corresponding file in the compilation database. Although entries
+/// in the compilation database are keyed by filename, a simple string match
+/// is insufficient because of symlinks. Commonly, a project hierarchy looks
+/// like this:
+///   /<project-root/src/<path>/<somefile>.cc      (used as input for the tool)
+///   /<project-root/build/<symlink-to-src>/<path>/<somefile>.cc (stored in DB)
+///
+/// Furthermore, there might be symlinks inside the source folder or inside the
+/// database, so that the same source file is translated with different build
+/// options.
+///
+/// For a given input file, the \c FileNameMatchTrie finds its entries in order
+/// of matching suffix length. For each suffix length, there might be one or
+/// more entries in the database. For each of those entries, it calls
+/// \c llvm::sys::fs::equivalent() (injected as \c PathComparator). There might
+/// be zero or more entries with the same matching suffix length that are
+/// equivalent to the input file. Three cases are distinguished:
+/// 0  equivalent files: Continue with the next suffix length.
+/// 1  equivalent file:  Best match found, return it.
+/// >1 equivalent files: Match is ambiguous, return error.
+class FileNameMatchTrie {
+public:
+  /// \brief Inserts 'NewPath' into this trie.
+  void insert(StringRef NewPath, unsigned ConsumedLength = 0);
+
+  /// \brief Finds the corresponding file in this trie.
+  ///
+  /// Returns file name stored in this trie that is equivalent to 'FileName'
+  /// according to 'Comparator', if it can be uniquely identified. If there
+  /// are no matches an empty StringRef is return. If there are ambigious
+  /// matches, an empty StringRef is return and a corresponding message written
+  /// to 'Error'.
+  StringRef findEquivalent(const PathComparator &Comparator,
+                           StringRef FileName,
+                           std::string *Error,
+                           unsigned ConsumedLength = 0) const;
+
+  /// \brief Gets all paths in this FileNameMatchTrie.
+  void getAll(std::vector<StringRef> &Results) const;
+
+private:
+  // The stored absolute path in this node. Only valid for leaf nodes, i.e.
+  // nodes where Children.empty().
+  std::string Path;
+
+  // The children of this node stored in a map based on the next path segment.
+  llvm::StringMap<FileNameMatchTrie> Children;
+};
+
 /// \brief A JSON based compilation database.
 ///
 /// JSON compilation database files must contain a list of JSON objects which
@@ -204,8 +266,7 @@ public:
   /// \brief Returns all compile comamnds in which the specified file was
   /// compiled.
   ///
-  /// FIXME: Currently FilePath must be an absolute path inside the
-  /// source directory which does not have symlinks resolved.
+  /// Currently FilePath must be an absolute path.
   virtual std::vector<CompileCommand> getCompileCommands(
     StringRef FilePath) const;
 
@@ -233,6 +294,8 @@ private:
   // Maps file paths to the compile command lines for that file.
   llvm::StringMap< std::vector<CompileCommandRef> > IndexByFile;
 
+  FileNameMatchTrie MatchTrie;
+
   llvm::OwningPtr<llvm::MemoryBuffer> Database;
   llvm::SourceMgr SM;
   llvm::yaml::Stream YAMLStream;
diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp
index 3139cc2..bbf9b53 100644
--- a/lib/Tooling/CompilationDatabase.cpp
+++ b/lib/Tooling/CompilationDatabase.cpp
@@ -14,6 +14,7 @@
 #include "clang/Tooling/CompilationDatabase.h"
 #include "clang/Tooling/Tooling.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/Support/FileSystem.h"
 #include "llvm/Support/YAMLParser.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/system_error.h"
@@ -237,8 +238,19 @@ std::vector<CompileCommand>
 JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const {
   llvm::SmallString<128> NativeFilePath;
   llvm::sys::path::native(FilePath, NativeFilePath);
+  std::vector<StringRef> PossibleMatches;
+  PathComparator Comparator;
+  std::string Error;
+  StringRef Match = MatchTrie.findEquivalent(Comparator, NativeFilePath.str(),
+                                             &Error);
+  if (Match.empty()) {
+    if (Error.empty())
+      Error = "No match found.";
+    llvm::outs() << Error << "\n";
+    return std::vector<CompileCommand>();
+  }
   llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator
-    CommandsRefI = IndexByFile.find(NativeFilePath);
+    CommandsRefI = IndexByFile.find(Match);
   if (CommandsRefI == IndexByFile.end())
     return std::vector<CompileCommand>();
   const std::vector<CompileCommandRef> &CommandsRef = CommandsRefI->getValue();
@@ -344,13 +356,100 @@ bool JSONCompilationDatabase::parse(std::string &ErrorMessage) {
       return false;
     }
     llvm::SmallString<8> FileStorage;
+    StringRef FileName = File->getValue(FileStorage);
     llvm::SmallString<128> NativeFilePath;
-    llvm::sys::path::native(File->getValue(FileStorage), NativeFilePath);
+    if (llvm::sys::path::is_relative(FileName)) {
+      llvm::SmallString<8> DirectoryStorage;
+      llvm::SmallString<128> AbsolutePath(Directory->getValue(DirectoryStorage));
+      llvm::sys::path::append(AbsolutePath, FileName);
+      llvm::sys::path::native(AbsolutePath.str(), NativeFilePath);
+    } else {
+      llvm::sys::path::native(FileName, NativeFilePath);
+    }
     IndexByFile[NativeFilePath].push_back(
-      CompileCommandRef(Directory, Command));
+        CompileCommandRef(Directory, Command));
+    MatchTrie.insert(NativeFilePath.str());
   }
   return true;
 }
 
+void FileNameMatchTrie::insert(StringRef NewPath, unsigned ConsumedLength) {
+  if (llvm::sys::path::is_relative(NewPath))
+    return;
+  if (Path.empty()) {
+    // This is an empty leaf. Store NewPath and return.
+    Path = NewPath;
+    return;
+  }
+  if (Children.empty()) {
+    // This is a leaf, ignore duplicate entry if 'Path' equals 'NewPath'. 
+    if (NewPath == Path)
+        return;
+    // Make this a node and create a child-leaf with 'Path'.
+    StringRef Element(llvm::sys::path::filename(
+        StringRef(Path).drop_back(ConsumedLength)));
+    Children[Element].Path = Path;
+  }
+  StringRef Element(llvm::sys::path::filename(
+        StringRef(NewPath).drop_back(ConsumedLength)));
+  Children[Element].insert(NewPath, ConsumedLength + Element.size() + 1);
+}
+
+StringRef FileNameMatchTrie::findEquivalent(const PathComparator &Comparator,
+                                            StringRef FileName,
+                                            std::string *Error,
+                                            unsigned ConsumedLength) const {
+  if (llvm::sys::path::is_relative(FileName)) {
+    *Error = "Cannot resolve relative paths";
+    return StringRef();
+  }
+  if (Children.empty()) {
+    if (Comparator.equivalent(StringRef(Path), FileName))
+      return StringRef(Path);
+    return StringRef();
+  }
+  StringRef Element(llvm::sys::path::filename(FileName.drop_back(
+      ConsumedLength)));
+  llvm::StringMap<FileNameMatchTrie>::const_iterator MatchingChild =
+      Children.find(Element);
+  if (MatchingChild != Children.end()) {
+    StringRef Result = MatchingChild->getValue().findEquivalent(
+        Comparator, FileName, Error, ConsumedLength + Element.size() + 1);
+    if (!Result.empty() || !Error->empty())
+      return Result;
+  }
+  // FIXME: This will re-examine 'MatchingChild' which does not have any
+  // matching children. Thus, the result is still correct, but performance
+  // can be improved.
+  std::vector<StringRef> AllChildren;
+  getAll(AllChildren);
+  StringRef Result;
+  for (unsigned i = 0; i < AllChildren.size(); i++) {
+    if (Comparator.equivalent(AllChildren[i], FileName)) {
+      if (Result.empty()) {
+        Result = AllChildren[i];
+      } else {
+        *Error = "Path is ambiguous";
+        return StringRef();
+      }
+    }
+  }
+  return Result;
+}
+
+void FileNameMatchTrie::getAll(std::vector<StringRef> &Results) const {
+  if (Path.empty())
+    return;
+  if (Children.empty()) {
+    Results.push_back(StringRef(Path));
+    return;
+  }
+  for (llvm::StringMap<FileNameMatchTrie>::const_iterator
+       It = Children.begin(), E = Children.end();
+       It != E; ++It) {
+    It->getValue().getAll(Results);
+  }
+}
+
 } // end namespace tooling
 } // end namespace clang
diff --git a/unittests/Tooling/CompilationDatabaseTest.cpp b/unittests/Tooling/CompilationDatabaseTest.cpp
index 591d48d..237f18bf 100644
--- a/unittests/Tooling/CompilationDatabaseTest.cpp
+++ b/unittests/Tooling/CompilationDatabaseTest.cpp
@@ -55,13 +55,13 @@ TEST(JSONCompilationDatabase, GetAllFiles) {
             getAllFiles("[]", ErrorMessage)) << ErrorMessage;
 
   std::vector<std::string> expected_files;
-  expected_files.push_back("file1");
-  expected_files.push_back("file2");
+  expected_files.push_back("/dir/file1");
+  expected_files.push_back("/dir/file2");
   EXPECT_EQ(expected_files, getAllFiles(
-    "[{\"directory\":\"dir\","
+    "[{\"directory\":\"/dir\","
       "\"command\":\"command\","
       "\"file\":\"file1\"},"
-    " {\"directory\":\"dir\","
+    " {\"directory\":\"/dir\","
       "\"command\":\"command\","
       "\"file\":\"file2\"}]",
     ErrorMessage)) << ErrorMessage;
@@ -81,6 +81,82 @@ static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
   return Commands[0];
 }
 
+struct FakeComparator : public PathComparator {
+  virtual bool equivalent(const Twine &FileA, const Twine &FileB) const {
+    return StringRef(FileA.str()).equals_lower(FileB.str());
+  }
+};
+
+class FileNameMatchTrieTest : public ::testing::Test {
+protected:
+  StringRef find(StringRef Path) {
+    return Trie.findEquivalent(Comparator, Path, &Error);
+  }
+
+  FileNameMatchTrie Trie;
+  FakeComparator Comparator;
+  std::string Error;
+};
+
+TEST_F(FileNameMatchTrieTest, InsertingRelativePath) {
+  Trie.insert("/path/file.cc");
+  Trie.insert("file.cc");
+  EXPECT_EQ("/path/file.cc", find("/path/file.cc"));
+  EXPECT_EQ("", Error);
+}
+
+TEST_F(FileNameMatchTrieTest, MatchingRelativePath) {
+  EXPECT_EQ("", find("file.cc"));
+  EXPECT_EQ("Cannot resolve relative paths", Error);
+}
+
+TEST_F(FileNameMatchTrieTest, ReturnsBestResults) {
+  Trie.insert("/d/c/b.cc");
+  Trie.insert("/d/b/b.cc");
+  EXPECT_EQ("/d/b/b.cc", find("/d/b/b.cc"));
+  EXPECT_EQ("", Error);
+}
+
+TEST_F(FileNameMatchTrieTest, HandlesSymlinks) {
+  Trie.insert("/AA/file.cc");
+  EXPECT_EQ("/AA/file.cc", find("/aa/file.cc"));
+  EXPECT_EQ("", Error);
+}
+
+TEST_F(FileNameMatchTrieTest, ReportsSymlinkAmbiguity) {
+  Trie.insert("/Aa/file.cc");
+  Trie.insert("/aA/file.cc");
+  EXPECT_TRUE(find("/aa/file.cc").empty());
+  EXPECT_EQ("Path is ambiguous", Error);
+}
+
+TEST_F(FileNameMatchTrieTest, LongerMatchingSuffixPreferred) {
+  Trie.insert("/src/Aa/file.cc");
+  Trie.insert("/src/aA/file.cc");
+  Trie.insert("/SRC/aa/file.cc");
+  EXPECT_EQ("/SRC/aa/file.cc", find("/src/aa/file.cc"));
+  EXPECT_EQ("", Error);
+}
+
+TEST_F(FileNameMatchTrieTest, EmptyTrie) {
+  EXPECT_TRUE(find("/some/path").empty());
+  EXPECT_EQ("", Error);
+}
+
+TEST_F(FileNameMatchTrieTest, NoResult) {
+  Trie.insert("/somepath/otherfile.cc");
+  Trie.insert("/otherpath/somefile.cc");
+  EXPECT_EQ("", find("/somepath/somefile.cc"));
+  EXPECT_EQ("", Error);
+}
+
+TEST_F(FileNameMatchTrieTest, RootElementDifferent) {
+  Trie.insert("/path/file.cc");
+  Trie.insert("/otherpath/file.cc");
+  EXPECT_EQ("/path/file.cc", find("/path/file.cc"));
+  EXPECT_EQ("", Error);
+}
+
 TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
   std::string ErrorMessage;
   CompileCommand NotFound = findCompileArgsInJsonDatabase(
@@ -148,7 +224,7 @@ TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
 }
 
 TEST(findCompileArgsInJsonDatabase, FindsEntry) {
-  StringRef Directory("directory");
+  StringRef Directory("/directory");
   StringRef FileName("file");
   StringRef Command("command");
   std::string JsonDatabase = "[";
@@ -162,19 +238,19 @@ TEST(findCompileArgsInJsonDatabase, FindsEntry) {
   JsonDatabase += "]";
   std::string ErrorMessage;
   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
-    "file4", JsonDatabase, ErrorMessage);
-  EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage;
+    "/directory4/file4", JsonDatabase, ErrorMessage);
+  EXPECT_EQ("/directory4", FoundCommand.Directory) << ErrorMessage;
   ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
   EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
 }
 
 static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
   std::string JsonDatabase =
-    ("[{\"directory\":\"\", \"file\":\"test\", \"command\": \"" +
+    ("[{\"directory\":\"/root\", \"file\":\"test\", \"command\": \"" +
      Command + "\"}]").str();
   std::string ErrorMessage;
   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
-    "test", JsonDatabase, ErrorMessage);
+    "/root/test", JsonDatabase, ErrorMessage);
   EXPECT_TRUE(ErrorMessage.empty()) << ErrorMessage;
   return FoundCommand.CommandLine;
 }
