Merge pull request #96 from graydon/rdar-30851899-bridging-pch-mergemodule-mismatch-swift-4.0-branch

Rdar 30851899 bridging pch mergemodule mismatch swift 4.0 branch
diff --git a/include/clang/Basic/DiagnosticFrontendKinds.td b/include/clang/Basic/DiagnosticFrontendKinds.td
index 257448e..30452be 100644
--- a/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -213,6 +213,10 @@
   Error<"file '%0' specified by '-fmodules-embed-file=' not found">,
   DefaultFatal;
 
+def remark_index_producing_module_file_data : Remark<"producing index data for "
+  "module file '%0'">,
+  InGroup<IndexStore>;
+
 def err_test_module_file_extension_version : Error<
   "test module file extension '%0' has different version (%1.%2) than expected "
   "(%3.%4)">;
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index 48345f0..7af7845 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -283,6 +283,7 @@
 def ModuleBuild : DiagGroup<"module-build">;
 def ModuleConflict : DiagGroup<"module-conflict">;
 def ModuleFileExtension : DiagGroup<"module-file-extension">;
+def IndexStore : DiagGroup<"index-store">;
 def NewlineEOF : DiagGroup<"newline-eof">;
 def Nullability : DiagGroup<"nullability">;
 def NullabilityDeclSpec : DiagGroup<"nullability-declspec">;
diff --git a/include/clang/DirectoryWatcher/DirectoryWatcher.h b/include/clang/DirectoryWatcher/DirectoryWatcher.h
new file mode 100644
index 0000000..09d17a9
--- /dev/null
+++ b/include/clang/DirectoryWatcher/DirectoryWatcher.h
@@ -0,0 +1,47 @@
+//===- DirectoryWatcher.h - Listens for directory file changes --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief Utility class for listening for file system changes in a directory.
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_DIRECTORYWATCHER_DIRECTORYWATCHER_H
+#define LLVM_CLANG_DIRECTORYWATCHER_DIRECTORYWATCHER_H
+
+#include "clang/Basic/LLVM.h"
+#include "clang/Index/IndexDataStore.h"
+#include <functional>
+#include <memory>
+#include <string>
+
+namespace clang {
+
+/// Provides notifications for file system changes in a directory.
+///
+/// Guarantees that the first time the directory is processed, the receiver will
+/// be invoked even if the directory is empty.
+class DirectoryWatcher : public index::AbstractDirectoryWatcher {
+  struct Implementation;
+  Implementation &Impl;
+
+  DirectoryWatcher();
+
+  DirectoryWatcher(const DirectoryWatcher&) = delete;
+  DirectoryWatcher &operator =(const DirectoryWatcher&) = delete;
+
+public:
+  ~DirectoryWatcher();
+
+  static std::unique_ptr<DirectoryWatcher>
+    create(StringRef Path, EventReceiver Receiver, bool waitInitialSync,
+           std::string &Error);
+};
+
+} // namespace clang
+
+#endif
diff --git a/include/clang/Driver/Job.h b/include/clang/Driver/Job.h
index 54bed09..08f24ad 100644
--- a/include/clang/Driver/Job.h
+++ b/include/clang/Driver/Job.h
@@ -33,9 +33,11 @@
 struct CrashReportInfo {
   StringRef Filename;
   StringRef VFSPath;
+  StringRef IndexStorePath;
 
-  CrashReportInfo(StringRef Filename, StringRef VFSPath)
-      : Filename(Filename), VFSPath(VFSPath) {}
+  CrashReportInfo(StringRef Filename, StringRef VFSPath,
+                  StringRef IndexStorePath)
+      : Filename(Filename), VFSPath(VFSPath), IndexStorePath(IndexStorePath) {}
 };
 
 /// Command - An executable path/name and argument vector to
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index bbf9091..fa23cf6 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -229,6 +229,13 @@
 def : Joined<["-"], "objcmt-white-list-dir-path=">, Flags<[CC1Option]>,
     Alias<objcmt_whitelist_dir_path>;
 
+def index_store_path : Separate<["-"], "index-store-path">, Flags<[CC1Option]>,
+  HelpText<"Enable indexing with the specified data store path">;
+def index_ignore_system_symbols : Flag<["-"], "index-ignore-system-symbols">, Flags<[CC1Option]>,
+  HelpText<"Ignore symbols from system headers">;
+def index_record_codegen_name : Flag<["-"], "index-record-codegen-name">, Flags<[CC1Option]>,
+  HelpText<"Record the codegen name for symbols">;
+
 // Make sure all other -ccc- options are rejected.
 def ccc_ : Joined<["-"], "ccc-">, Group<internal_Group>, Flags<[Unsupported]>;
 
diff --git a/include/clang/Frontend/FrontendOptions.h b/include/clang/Frontend/FrontendOptions.h
index 9c960bb..8026419 100644
--- a/include/clang/Frontend/FrontendOptions.h
+++ b/include/clang/Frontend/FrontendOptions.h
@@ -212,6 +212,10 @@
   std::string MTMigrateDir;
   std::string ARCMTMigrateReportOut;
 
+  std::string IndexStorePath;
+  unsigned IndexIgnoreSystemSymbols : 1;
+  unsigned IndexRecordCodegenName : 1;
+
   /// The input files and their types.
   std::vector<FrontendInputFile> Inputs;
 
@@ -285,8 +289,9 @@
     SkipFunctionBodies(false), UseGlobalModuleIndex(true),
     GenerateGlobalModuleIndex(true), ASTDumpDecls(false), ASTDumpLookups(false),
     BuildingImplicitModule(false), ModulesEmbedAllFiles(false),
-    IncludeTimestamps(true), ARCMTAction(ARCMT_None),
-    ObjCMTAction(ObjCMT_None), ProgramAction(frontend::ParseSyntaxOnly)
+    IncludeTimestamps(true), ARCMTAction(ARCMT_None), ObjCMTAction(ObjCMT_None),
+    IndexIgnoreSystemSymbols(false), IndexRecordCodegenName(false),
+    ProgramAction(frontend::ParseSyntaxOnly)
   {}
 
   /// getInputKindForExtension - Return the appropriate input kind for a file
diff --git a/include/clang/Index/IndexDataStore.h b/include/clang/Index/IndexDataStore.h
new file mode 100644
index 0000000..714ccdd
--- /dev/null
+++ b/include/clang/Index/IndexDataStore.h
@@ -0,0 +1,102 @@
+//===--- IndexDataStore.h - Index data store info -------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_INDEXDATASTORE_H
+#define LLVM_CLANG_INDEX_INDEXDATASTORE_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace index {
+
+class AbstractDirectoryWatcher {
+public:
+  enum class EventKind {
+    /// A file was added.
+    Added,
+    /// A file was removed.
+    Removed,
+    /// A file was modified.
+    Modified,
+    /// The watched directory got deleted. No more events will follow.
+    DirectoryDeleted,
+  };
+
+  struct Event {
+    EventKind Kind;
+    std::string Filename;
+    timespec ModTime;
+  };
+
+  typedef std::function<void(ArrayRef<Event> Events, bool isInitial)> EventReceiver;
+  typedef std::unique_ptr<AbstractDirectoryWatcher>(CreateFnTy)
+    (StringRef Path, EventReceiver Receiver, bool waitInitialSync, std::string &Error);
+
+  virtual ~AbstractDirectoryWatcher() {}
+};
+
+class IndexDataStore {
+public:
+  ~IndexDataStore();
+
+  static std::unique_ptr<IndexDataStore>
+    create(StringRef IndexStorePath, std::string &Error);
+
+  StringRef getFilePath() const;
+  bool foreachUnitName(bool sorted,
+                       llvm::function_ref<bool(StringRef unitName)> receiver);
+
+  static unsigned getFormatVersion();
+
+  enum class UnitEventKind {
+    Added,
+    Removed,
+    Modified,
+    /// The directory got deleted. No more events will follow.
+    DirectoryDeleted,
+  };
+  struct UnitEvent {
+    UnitEventKind Kind;
+    StringRef UnitName;
+    timespec ModTime;
+  };
+  struct UnitEventNotification {
+    bool IsInitial;
+    ArrayRef<UnitEvent> Events;
+  };
+  typedef std::function<void(UnitEventNotification)> UnitEventHandler;
+
+  void setUnitEventHandler(UnitEventHandler Handler);
+  /// \returns true if an error occurred.
+  bool startEventListening(llvm::function_ref<AbstractDirectoryWatcher::CreateFnTy> createFn,
+                           bool waitInitialSync, std::string &Error);
+  void stopEventListening();
+
+  void discardUnit(StringRef UnitName);
+  void discardRecord(StringRef RecordName);
+
+  void purgeStaleData();
+
+private:
+  IndexDataStore(void *Impl) : Impl(Impl) {}
+
+  void *Impl; // An IndexDataStoreImpl.
+};
+
+} // namespace index
+} // namespace clang
+
+#endif
diff --git a/include/clang/Index/IndexDataStoreSymbolUtils.h b/include/clang/Index/IndexDataStoreSymbolUtils.h
new file mode 100644
index 0000000..e1d982d
--- /dev/null
+++ b/include/clang/Index/IndexDataStoreSymbolUtils.h
@@ -0,0 +1,53 @@
+//===--- IndexDataStoreSymbolUtils.h - Utilities for indexstore symbols ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_INDEXDATASTORESYMBOLUTILS_H
+#define LLVM_CLANG_INDEX_INDEXDATASTORESYMBOLUTILS_H
+
+#include "indexstore/indexstore.h"
+#include "clang/Index/IndexSymbol.h"
+
+namespace clang {
+namespace index {
+
+/// Map an indexstore_symbol_kind_t to a SymbolKind, handling unknown values.
+SymbolKind getSymbolKind(indexstore_symbol_kind_t K);
+
+SymbolSubKind getSymbolSubKind(indexstore_symbol_subkind_t K);
+
+/// Map an indexstore_symbol_language_t to a SymbolLanguage, handling unknown
+/// values.
+SymbolLanguage getSymbolLanguage(indexstore_symbol_language_t L);
+
+/// Map an indexstore representation to a SymbolPropertySet, handling
+/// unknown values.
+SymbolPropertySet getSymbolProperties(uint64_t Props);
+
+/// Map an indexstore representation to a SymbolRoleSet, handling unknown
+/// values.
+SymbolRoleSet getSymbolRoles(uint64_t Roles);
+
+/// Map a SymbolLanguage to a indexstore_symbol_language_t.
+indexstore_symbol_kind_t getIndexStoreKind(SymbolKind K);
+
+indexstore_symbol_subkind_t getIndexStoreSubKind(SymbolSubKind K);
+
+/// Map a SymbolLanguage to a indexstore_symbol_language_t.
+indexstore_symbol_language_t getIndexStoreLang(SymbolLanguage L);
+
+/// Map a SymbolPropertySet to its indexstore representation.
+uint64_t getIndexStoreProperties(SymbolPropertySet Props);
+
+/// Map a SymbolRoleSet to its indexstore representation.
+uint64_t getIndexStoreRoles(SymbolRoleSet Roles);
+
+} // end namespace index
+} // end namespace clang
+
+#endif // LLVM_CLANG_INDEX_INDEXDATASTORESYMBOLUTILS_H
diff --git a/include/clang/Index/IndexRecordReader.h b/include/clang/Index/IndexRecordReader.h
new file mode 100644
index 0000000..ef8edff
--- /dev/null
+++ b/include/clang/Index/IndexRecordReader.h
@@ -0,0 +1,109 @@
+//===--- IndexRecordReader.h - Index record deserialization ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_INDEXRECORDREADER_H
+#define LLVM_CLANG_INDEX_INDEXRECORDREADER_H
+
+#include "clang/Index/IndexSymbol.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include <memory>
+
+namespace llvm {
+  class MemoryBuffer;
+}
+
+namespace clang {
+namespace index {
+
+struct IndexRecordDecl {
+  unsigned DeclID;
+  SymbolInfo SymInfo;
+  SymbolRoleSet Roles;
+  SymbolRoleSet RelatedRoles;
+  StringRef Name;
+  StringRef USR;
+  StringRef CodeGenName;
+};
+
+struct IndexRecordRelation {
+  SymbolRoleSet Roles;
+  const IndexRecordDecl *Dcl = nullptr;
+
+  IndexRecordRelation() = default;
+  IndexRecordRelation(SymbolRoleSet Roles, const IndexRecordDecl *Dcl)
+    : Roles(Roles), Dcl(Dcl) {}
+};
+
+struct IndexRecordOccurrence {
+  const IndexRecordDecl *Dcl;
+  SmallVector<IndexRecordRelation, 4> Relations;
+  SymbolRoleSet Roles;
+  unsigned Line;
+  unsigned Column;
+};
+
+class IndexRecordReader {
+  IndexRecordReader();
+
+public:
+  static std::unique_ptr<IndexRecordReader>
+    createWithRecordFilename(StringRef RecordFilename, StringRef StorePath,
+                             std::string &Error);
+  static std::unique_ptr<IndexRecordReader>
+    createWithFilePath(StringRef FilePath, std::string &Error);
+  static std::unique_ptr<IndexRecordReader>
+    createWithBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer,
+                     std::string &Error);
+
+  ~IndexRecordReader();
+
+  struct DeclSearchReturn {
+    bool AcceptDecl;
+    bool ContinueSearch;
+  };
+  typedef DeclSearchReturn(DeclSearchCheck)(const IndexRecordDecl &);
+
+  /// Goes through and passes record decls, after filtering using a \c Checker
+  /// function.
+  ///
+  /// Resulting decls can be used as filter for \c foreachOccurrence. This
+  /// allows allocating memory only for the record decls that the caller is
+  /// interested in.
+  bool searchDecls(llvm::function_ref<DeclSearchCheck> Checker,
+                   llvm::function_ref<void(const IndexRecordDecl *)> Receiver);
+
+  /// \param NoCache if true, avoids allocating memory for the decls.
+  /// Useful when the caller does not intend to keep \c IndexRecordReader
+  /// for more queries.
+  bool foreachDecl(bool NoCache,
+                   llvm::function_ref<bool(const IndexRecordDecl *)> Receiver);
+
+  /// \param DeclsFilter if non-empty indicates the list of decls that we want
+  /// to get occurrences for. An empty array indicates that we want occurrences
+  /// for all decls.
+  /// \param RelatedDeclsFilter Same as \c DeclsFilter but for related decls.
+  bool foreachOccurrence(ArrayRef<const IndexRecordDecl *> DeclsFilter,
+                         ArrayRef<const IndexRecordDecl *> RelatedDeclsFilter,
+              llvm::function_ref<bool(const IndexRecordOccurrence &)> Receiver);
+  bool foreachOccurrence(
+              llvm::function_ref<bool(const IndexRecordOccurrence &)> Receiver);
+
+  bool foreachOccurrenceInLineRange(unsigned lineStart, unsigned lineCount,
+              llvm::function_ref<bool(const IndexRecordOccurrence &)> Receiver);
+
+  struct Implementation;
+private:
+  Implementation &Impl;
+};
+
+} // namespace index
+} // namespace clang
+
+#endif
diff --git a/include/clang/Index/IndexRecordWriter.h b/include/clang/Index/IndexRecordWriter.h
new file mode 100644
index 0000000..8a9720a
--- /dev/null
+++ b/include/clang/Index/IndexRecordWriter.h
@@ -0,0 +1,102 @@
+//===--- IndexRecordWriter.h - Index record serialization -----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_INDEXRECORDWRITER_H
+#define LLVM_CLANG_INDEX_INDEXRECORDWRITER_H
+
+#include "clang/Index/IndexSymbol.h"
+#include "llvm/ADT/SmallString.h"
+
+namespace clang {
+namespace index {
+
+namespace writer {
+/// An opaque pointer to a declaration or other symbol used by the
+/// IndexRecordWriter to identify when two occurrences refer to the same symbol,
+/// and as a token for getting information about a symbol from the caller.
+typedef const void *OpaqueDecl;
+
+/// An indexer symbol suitable for serialization.
+///
+/// This includes all the information about the symbol that will be serialized
+/// except for roles, which are synthesized by looking at all the occurrences.
+///
+/// \seealso IndexRecordDecl
+/// \note this struct is generally accompanied by a buffer that owns the string
+/// storage.  It should not be stored permanently.
+struct Symbol {
+  SymbolInfo SymInfo;
+  StringRef Name;
+  StringRef USR;
+  StringRef CodeGenName;
+};
+
+/// An relation to an opaque symbol.
+/// \seealso IndexRecordRelation
+struct SymbolRelation {
+  OpaqueDecl RelatedSymbol;
+  SymbolRoleSet Roles;
+};
+
+typedef llvm::function_ref<Symbol(OpaqueDecl, SmallVectorImpl<char> &Scratch)>
+    SymbolWriterCallback;
+} // end namespace writer
+
+/// A language-independent utility for serializing index record files.
+///
+/// Internally, this class is a small state machine.  Users should first call
+/// beginRecord, and if the file does not already exist, then proceed to add
+/// all symbol occurrences (addOccurrence) and finally finish with endRecord.
+class IndexRecordWriter {
+  SmallString<64> RecordsPath; ///< The records directory path.
+  void *Record = nullptr;      ///< The state of the current record.
+public:
+  IndexRecordWriter(StringRef IndexPath);
+
+  enum class Result {
+    Success,
+    Failure,
+    AlreadyExists,
+  };
+
+  /// Begin writing a record for the file \p Filename with contents uniquely
+  /// identified by \p RecordHash.
+  ///
+  /// \param Filename the name of the file this is a record for.
+  /// \param RecordHash the unique hash of the record contents.
+  /// \param Error on failure, set to the error message.
+  /// \param RecordFile if non-null, this is set to the name of the record file.
+  ///
+  /// \returns Success if we should continue writing this record, AlreadyExists
+  /// if the record file has already been written, or Failure if there was an
+  /// error, in which case \p Error will be set.
+  Result beginRecord(StringRef Filename, llvm::hash_code RecordHash,
+                     std::string &Error, std::string *RecordFile = nullptr);
+
+  /// Finish writing the record file.
+  ///
+  /// \param Error on failure, set to the error message.
+  /// \param GetSymbolForDecl a callback mapping an writer::OpaqueDecl to its
+  /// writer::Symbol. This is how the language-specific symbol information is
+  /// provided to the IndexRecordWriter. The scratch parameter can be used for
+  /// any necessary storage.
+  ///
+  /// \return Success, or Failure and sets \p Error.
+  Result endRecord(std::string &Error,
+                   writer::SymbolWriterCallback GetSymbolForDecl);
+
+  /// Add an occurrence of the symbol \p D with the given \p Roles and location.
+  void addOccurrence(writer::OpaqueDecl D, SymbolRoleSet Roles, unsigned Line,
+                     unsigned Column, ArrayRef<writer::SymbolRelation> Related);
+};
+
+} // end namespace index
+} // end namespace clang
+
+#endif // LLVM_CLANG_INDEX_INDEXRECORDWRITER_H
diff --git a/include/clang/Index/IndexUnitReader.h b/include/clang/Index/IndexUnitReader.h
new file mode 100644
index 0000000..ccd2dce
--- /dev/null
+++ b/include/clang/Index/IndexUnitReader.h
@@ -0,0 +1,85 @@
+//===--- IndexUnitReader.h - Index unit deserialization -------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_INDEXUNITREADER_H
+#define LLVM_CLANG_INDEX_INDEXUNITREADER_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Chrono.h"
+
+namespace clang {
+namespace index {
+
+class IndexUnitReader {
+public:
+  enum class DependencyKind {
+    Unit,
+    Record,
+    File,
+  };
+
+  ~IndexUnitReader();
+
+  static std::unique_ptr<IndexUnitReader>
+    createWithUnitFilename(StringRef UnitFilename, StringRef StorePath,
+                           std::string &Error);
+  static std::unique_ptr<IndexUnitReader>
+    createWithFilePath(StringRef FilePath, std::string &Error);
+
+  static Optional<llvm::sys::TimePoint<>>
+    getModificationTimeForUnit(StringRef UnitFilename, StringRef StorePath,
+                               std::string &Error);
+
+  StringRef getProviderIdentifier() const;
+  StringRef getProviderVersion() const;
+
+  llvm::sys::TimePoint<> getModificationTime() const;
+  StringRef getWorkingDirectory() const;
+  StringRef getOutputFile() const;
+  StringRef getSysrootPath() const;
+  StringRef getMainFilePath() const;
+  StringRef getModuleName() const;
+  StringRef getTarget() const;
+  bool hasMainFile() const;
+  bool isSystemUnit() const;
+  bool isModuleUnit() const;
+  bool isDebugCompilation() const;
+
+  struct DependencyInfo {
+    DependencyKind Kind;
+    bool IsSystem;
+    StringRef UnitOrRecordName;
+    StringRef FilePath;
+    StringRef ModuleName;
+    size_t FileSize;
+    time_t ModTime;
+  };
+  struct IncludeInfo {
+    StringRef SourcePath;
+    unsigned SourceLine;
+    StringRef TargetPath;
+  };
+  /// Unit dependencies are provided ahead of record ones, record ones
+  /// ahead of the file ones.
+  bool foreachDependency(llvm::function_ref<bool(const DependencyInfo &Info)> Receiver);
+
+  bool foreachInclude(llvm::function_ref<bool(const IncludeInfo &Info)> Receiver);
+
+private:
+  IndexUnitReader(void *Impl) : Impl(Impl) {}
+
+  void *Impl; // An IndexUnitReaderImpl.
+};
+
+} // namespace index
+} // namespace clang
+
+#endif
diff --git a/include/clang/Index/IndexUnitWriter.h b/include/clang/Index/IndexUnitWriter.h
new file mode 100644
index 0000000..40d2c11
--- /dev/null
+++ b/include/clang/Index/IndexUnitWriter.h
@@ -0,0 +1,140 @@
+//===--- IndexUnitWriter.h - Index unit serialization ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEX_INDEXUNITWRITER_H
+#define LLVM_CLANG_INDEX_INDEXUNITWRITER_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallString.h"
+#include <string>
+#include <vector>
+
+namespace llvm {
+  class BitstreamWriter;
+}
+
+namespace clang {
+  class FileEntry;
+  class FileManager;
+
+namespace index {
+
+namespace writer {
+/// An opaque pointer to a module used by the IndexUnitWriter to associate
+/// record and file dependencies with a module, and as a token for getting
+/// information about the module from the caller.
+typedef const void *OpaqueModule;
+
+/// Module info suitable for serialization.
+///
+/// This is used for top-level modules and sub-modules.
+struct ModuleInfo {
+  /// Full, dot-separate, module name.
+  StringRef Name;
+};
+
+typedef llvm::function_ref<ModuleInfo(OpaqueModule, SmallVectorImpl<char> &Scratch)>
+    ModuleInfoWriterCallback;
+} // end namespace writer
+
+class IndexUnitWriter {
+  FileManager &FileMgr;
+  SmallString<64> UnitsPath;
+  std::string ProviderIdentifier;
+  std::string ProviderVersion;
+  std::string OutputFile;
+  std::string ModuleName;
+  const FileEntry *MainFile;
+  bool IsSystemUnit;
+  bool IsModuleUnit;
+  bool IsDebugCompilation;
+  std::string TargetTriple;
+  std::string WorkDir;
+  std::string SysrootPath;
+  std::function<writer::ModuleInfo(writer::OpaqueModule,
+                            SmallVectorImpl<char> &Scratch)> GetInfoForModuleFn;
+  struct FileInclude {
+    int Index;
+    unsigned Line;
+  };
+  struct FileEntryData {
+    const FileEntry *File;
+    bool IsSystem;
+    int ModuleIndex;
+    std::vector<FileInclude> Includes;
+  };
+  std::vector<FileEntryData> Files;
+  std::vector<writer::OpaqueModule> Modules;
+  llvm::DenseMap<const FileEntry *, int> IndexByFile;
+  llvm::DenseMap<writer::OpaqueModule, int> IndexByModule;
+  llvm::DenseSet<const FileEntry *> SeenASTFiles;
+  struct RecordOrUnitData {
+    std::string Name;
+    int FileIndex;
+    int ModuleIndex;
+    bool IsSystem;
+  };
+  std::vector<RecordOrUnitData> Records;
+  std::vector<RecordOrUnitData> ASTFileUnits;
+
+public:
+  /// \param MainFile the main file for a compiled source file. This should be
+  /// null for PCH and module units.
+  /// \param IsSystem true for system module units, false otherwise.
+  IndexUnitWriter(FileManager &FileMgr,
+                  StringRef StorePath,
+                  StringRef ProviderIdentifier, StringRef ProviderVersion,
+                  StringRef OutputFile,
+                  StringRef ModuleName,
+                  const FileEntry *MainFile,
+                  bool IsSystem,
+                  bool IsModuleUnit,
+                  bool IsDebugCompilation,
+                  StringRef TargetTriple,
+                  StringRef SysrootPath,
+                  writer::ModuleInfoWriterCallback GetInfoForModule);
+  ~IndexUnitWriter();
+
+  int addFileDependency(const FileEntry *File, bool IsSystem,
+                        writer::OpaqueModule Mod);
+  void addRecordFile(StringRef RecordFile, const FileEntry *File, bool IsSystem,
+                     writer::OpaqueModule Mod);
+  void addASTFileDependency(const FileEntry *File, bool IsSystem,
+                            writer::OpaqueModule Mod, bool withoutUnitName = false);
+  void addUnitDependency(StringRef UnitFile, const FileEntry *File, bool IsSystem,
+                         writer::OpaqueModule Mod);
+  bool addInclude(const FileEntry *Source, unsigned Line, const FileEntry *Target);
+
+  bool write(std::string &Error);
+
+  void getUnitNameForOutputFile(StringRef FilePath, SmallVectorImpl<char> &Str);
+  void getUnitPathForOutputFile(StringRef FilePath, SmallVectorImpl<char> &Str);
+  /// If the unit file exists and \p timeCompareFilePath is provided, it will
+  /// return true if \p timeCompareFilePath is older than the unit file.
+  Optional<bool> isUnitUpToDateForOutputFile(StringRef FilePath,
+                                             Optional<StringRef> TimeCompareFilePath,
+                                             std::string &Error);
+  static void getUnitNameForAbsoluteOutputFile(StringRef FilePath, SmallVectorImpl<char> &Str);
+  static bool initIndexDirectory(StringRef StorePath, std::string &Error);
+
+private:
+  class PathStorage;
+  int addModule(writer::OpaqueModule Mod);
+  void writeUnitInfo(llvm::BitstreamWriter &Stream, PathStorage &PathStore);
+  void writeDependencies(llvm::BitstreamWriter &Stream, PathStorage &PathStore);
+  void writeIncludes(llvm::BitstreamWriter &Stream, PathStorage &PathStore);
+  void writePaths(llvm::BitstreamWriter &Stream, PathStorage &PathStore);
+  void writeModules(llvm::BitstreamWriter &Stream);
+};
+
+} // end namespace index
+} // end namespace clang
+
+#endif
diff --git a/include/clang/Index/IndexingAction.h b/include/clang/Index/IndexingAction.h
index 8eed33c..7dd25b8 100644
--- a/include/clang/Index/IndexingAction.h
+++ b/include/clang/Index/IndexingAction.h
@@ -12,11 +12,15 @@
 
 #include "clang/Basic/LLVM.h"
 #include <memory>
+#include <string>
 
 namespace clang {
   class ASTReader;
   class ASTUnit;
+  class CompilerInstance;
   class FrontendAction;
+  class FrontendOptions;
+  class Module;
 
 namespace serialization {
   class ModuleFile;
@@ -24,6 +28,7 @@
 
 namespace index {
   class IndexDataConsumer;
+  class IndexUnitWriter;
 
 struct IndexingOptions {
   enum class SystemSymbolFilterKind {
@@ -37,6 +42,19 @@
   bool IndexFunctionLocals = false;
 };
 
+struct RecordingOptions {
+  enum class IncludesRecordingKind {
+    None,
+    UserOnly, // only record includes inside non-system files.
+    All,
+  };
+
+  std::string DataDirPath;
+  bool RecordSymbolCodeGenName = false;
+  bool RecordSystemDependencies = true;
+  IncludesRecordingKind RecordIncludes = IncludesRecordingKind::UserOnly;
+};
+
 /// \param WrappedAction another frontend action to wrap over or null.
 std::unique_ptr<FrontendAction>
 createIndexingAction(std::shared_ptr<IndexDataConsumer> DataConsumer,
@@ -52,6 +70,18 @@
                      std::shared_ptr<IndexDataConsumer> DataConsumer,
                      IndexingOptions Opts);
 
+/// \param WrappedAction another frontend action to wrap over or null.
+std::unique_ptr<FrontendAction>
+createIndexDataRecordingAction(const FrontendOptions &FEOpts,
+                               std::unique_ptr<FrontendAction> WrappedAction);
+
+/// Checks if the unit file exists for the module file, if it doesn't it
+/// generates index data for it.
+///
+/// \returns true if the index data were generated, false otherwise.
+bool emitIndexDataForModuleFile(const Module *Mod, const CompilerInstance &CI,
+                                IndexUnitWriter &ParentUnitWriter);
+
 } // namespace index
 } // namespace clang
 
diff --git a/include/indexstore/IndexStoreCXX.h b/include/indexstore/IndexStoreCXX.h
new file mode 100644
index 0000000..addaa86
--- /dev/null
+++ b/include/indexstore/IndexStoreCXX.h
@@ -0,0 +1,502 @@
+//===--- IndexStoreCXX.h - C++ wrapper for the Index Store C API. ---------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Header-only C++ wrapper for the Index Store C API.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INDEXSTORE_INDEXSTORECXX_H
+#define LLVM_CLANG_INDEXSTORE_INDEXSTORECXX_H
+
+#include "indexstore/indexstore.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include <ctime>
+
+namespace indexstore {
+  using llvm::ArrayRef;
+  using llvm::Optional;
+  using llvm::StringRef;
+
+static inline StringRef stringFromIndexStoreStringRef(indexstore_string_ref_t str) {
+  return StringRef(str.data, str.length);
+}
+
+class IndexRecordSymbol {
+  indexstore_symbol_t obj;
+  friend class IndexRecordReader;
+
+public:
+  IndexRecordSymbol(indexstore_symbol_t obj) : obj(obj) {}
+
+  indexstore_symbol_language_t getLanguage() {
+    return indexstore_symbol_get_language(obj);
+  }
+  indexstore_symbol_kind_t getKind() { return indexstore_symbol_get_kind(obj); }
+  indexstore_symbol_subkind_t getSubKind() { return indexstore_symbol_get_subkind(obj); }
+  uint64_t getProperties() {
+    return indexstore_symbol_get_properties(obj);
+  }
+  uint64_t getRoles() { return indexstore_symbol_get_roles(obj); }
+  uint64_t getRelatedRoles() { return indexstore_symbol_get_related_roles(obj); }
+  StringRef getName() { return stringFromIndexStoreStringRef(indexstore_symbol_get_name(obj)); }
+  StringRef getUSR() { return stringFromIndexStoreStringRef(indexstore_symbol_get_usr(obj)); }
+  StringRef getCodegenName() { return stringFromIndexStoreStringRef(indexstore_symbol_get_codegen_name(obj)); }
+};
+
+class IndexSymbolRelation {
+  indexstore_symbol_relation_t obj;
+
+public:
+  IndexSymbolRelation(indexstore_symbol_relation_t obj) : obj(obj) {}
+
+  uint64_t getRoles() { return indexstore_symbol_relation_get_roles(obj); }
+  IndexRecordSymbol getSymbol() { return indexstore_symbol_relation_get_symbol(obj); }
+};
+
+class IndexRecordOccurrence {
+  indexstore_occurrence_t obj;
+
+public:
+  IndexRecordOccurrence(indexstore_occurrence_t obj) : obj(obj) {}
+
+  IndexRecordSymbol getSymbol() { return indexstore_occurrence_get_symbol(obj); }
+  uint64_t getRoles() { return indexstore_occurrence_get_roles(obj); }
+
+  bool foreachRelation(llvm::function_ref<bool(IndexSymbolRelation)> receiver) {
+#if INDEXSTORE_HAS_BLOCKS
+    return indexstore_occurrence_relations_apply(obj, ^bool(indexstore_symbol_relation_t sym_rel) {
+      return receiver(sym_rel);
+    });
+#else
+    return false;
+#endif
+  }
+
+  std::pair<unsigned, unsigned> getLineCol() {
+    unsigned line, col;
+    indexstore_occurrence_get_line_col(obj, &line, &col);
+    return std::make_pair(line, col);
+  }
+};
+
+class IndexStore;
+typedef std::shared_ptr<IndexStore> IndexStoreRef;
+
+class IndexStore {
+  indexstore_t obj;
+  friend class IndexRecordReader;
+  friend class IndexUnitReader;
+
+public:
+  IndexStore(StringRef path, std::string &error) {
+    llvm::SmallString<64> buf = path;
+    indexstore_error_t c_err = nullptr;
+    obj = indexstore_store_create(buf.c_str(), &c_err);
+    if (c_err) {
+      error = indexstore_error_get_description(c_err);
+      indexstore_error_dispose(c_err);
+    }
+  }
+
+  IndexStore(IndexStore &&other) : obj(other.obj) {
+    other.obj = nullptr;
+  }
+
+  ~IndexStore() {
+    indexstore_store_dispose(obj);
+  }
+
+  static IndexStoreRef create(StringRef path, std::string &error) {
+    auto storeRef = std::make_shared<IndexStore>(path, error);
+    if (storeRef->isInvalid())
+      return nullptr;
+    return storeRef;
+  }
+
+  static unsigned formatVersion() {
+    return indexstore_format_version();
+  }
+
+  bool isValid() const { return obj; }
+  bool isInvalid() const { return !isValid(); }
+  explicit operator bool() const { return isValid(); }
+
+  bool foreachUnit(bool sorted, llvm::function_ref<bool(StringRef unitName)> receiver) {
+#if INDEXSTORE_HAS_BLOCKS
+    return indexstore_store_units_apply(obj, sorted, ^bool(indexstore_string_ref_t unit_name) {
+      return receiver(stringFromIndexStoreStringRef(unit_name));
+    });
+#else
+    return false;
+#endif
+  }
+
+  class UnitEvent {
+    indexstore_unit_event_t obj;
+  public:
+    UnitEvent(indexstore_unit_event_t obj) : obj(obj) {}
+
+    enum class Kind {
+      Added,
+      Removed,
+      Modified,
+      DirectoryDeleted,
+    };
+    Kind getKind() const {
+      indexstore_unit_event_kind_t c_k = indexstore_unit_event_get_kind(obj);
+      Kind K;
+      switch (c_k) {
+      case INDEXSTORE_UNIT_EVENT_ADDED: K = Kind::Added; break;
+      case INDEXSTORE_UNIT_EVENT_REMOVED: K = Kind::Removed; break;
+      case INDEXSTORE_UNIT_EVENT_MODIFIED: K = Kind::Modified; break;
+      case INDEXSTORE_UNIT_EVENT_DIRECTORY_DELETED: K = Kind::DirectoryDeleted; break;
+      }
+      return K;
+    }
+
+    StringRef getUnitName() const {
+      return stringFromIndexStoreStringRef(indexstore_unit_event_get_unit_name(obj));
+    }
+
+    timespec getModificationTime() const { return indexstore_unit_event_get_modification_time(obj); }
+  };
+
+  class UnitEventNotification {
+    indexstore_unit_event_notification_t obj;
+  public:
+    UnitEventNotification(indexstore_unit_event_notification_t obj) : obj(obj) {}
+
+    bool isInitial() const { return indexstore_unit_event_notification_is_initial(obj); }
+    size_t getEventsCount() const { return indexstore_unit_event_notification_get_events_count(obj); }
+    UnitEvent getEvent(size_t index) const { return indexstore_unit_event_notification_get_event(obj, index); }
+  };
+
+  typedef std::function<void(UnitEventNotification)> UnitEventHandler;
+
+  void setUnitEventHandler(UnitEventHandler handler) {
+#if INDEXSTORE_HAS_BLOCKS
+    if (!handler) {
+      indexstore_store_set_unit_event_handler(obj, nullptr);
+      return;
+    }
+
+    indexstore_store_set_unit_event_handler(obj, ^(indexstore_unit_event_notification_t evt_note) {
+      handler(UnitEventNotification(evt_note));
+    });
+#endif
+  }
+
+  bool startEventListening(bool waitInitialSync, std::string &error) {
+    indexstore_unit_event_listen_options_t opts;
+    opts.wait_initial_sync = waitInitialSync;
+    indexstore_error_t c_err = nullptr;
+    bool ret = indexstore_store_start_unit_event_listening(obj, &opts, sizeof(opts), &c_err);
+    if (c_err) {
+      error = indexstore_error_get_description(c_err);
+      indexstore_error_dispose(c_err);
+    }
+    return ret;
+  }
+
+  void stopEventListening() {
+    return indexstore_store_stop_unit_event_listening(obj);
+  }
+
+  void discardUnit(StringRef UnitName) {
+    llvm::SmallString<64> buf = UnitName;
+    indexstore_store_discard_unit(obj, buf.c_str());
+  }
+
+  void discardRecord(StringRef RecordName) {
+    llvm::SmallString<64> buf = RecordName;
+    indexstore_store_discard_record(obj, buf.c_str());
+  }
+
+  void getUnitNameFromOutputPath(StringRef outputPath, llvm::SmallVectorImpl<char> &nameBuf) {
+    llvm::SmallString<256> buf = outputPath;
+    size_t nameLen = indexstore_store_get_unit_name_from_output_path(obj, buf.c_str(), nameBuf.data(), nameBuf.size());
+    if (nameLen+1 > nameBuf.size()) {
+      nameBuf.resize(nameLen+1);
+      indexstore_store_get_unit_name_from_output_path(obj, buf.c_str(), nameBuf.data(), nameBuf.size());
+    }
+  }
+
+  llvm::Optional<timespec>
+  getUnitModificationTime(StringRef unitName, std::string &error) {
+    llvm::SmallString<64> buf = unitName;
+    int64_t seconds, nanoseconds;
+    indexstore_error_t c_err = nullptr;
+    bool err = indexstore_store_get_unit_modification_time(obj, buf.c_str(),
+      &seconds, &nanoseconds, &c_err);
+    if (err && c_err) {
+      error = indexstore_error_get_description(c_err);
+      indexstore_error_dispose(c_err);
+      return llvm::None;
+    }
+    timespec ts;
+    ts.tv_sec = seconds;
+    ts.tv_nsec = nanoseconds;
+    return ts;
+  }
+
+  void purgeStaleData() {
+    indexstore_store_purge_stale_data(obj);
+  }
+};
+
+class IndexRecordReader {
+  indexstore_record_reader_t obj;
+
+public:
+  IndexRecordReader(IndexStore &store, StringRef recordName, std::string &error) {
+    llvm::SmallString<64> buf = recordName;
+    indexstore_error_t c_err = nullptr;
+    obj = indexstore_record_reader_create(store.obj, buf.c_str(), &c_err);
+    if (c_err) {
+      error = indexstore_error_get_description(c_err);
+      indexstore_error_dispose(c_err);
+    }
+  }
+
+  IndexRecordReader(IndexRecordReader &&other) : obj(other.obj) {
+    other.obj = nullptr;
+  }
+
+  ~IndexRecordReader() {
+    indexstore_record_reader_dispose(obj);
+  }
+
+  bool isValid() const { return obj; }
+  bool isInvalid() const { return !isValid(); }
+  explicit operator bool() const { return isValid(); }
+
+  /// Goes through and passes record decls, after filtering using a \c Checker
+  /// function.
+  ///
+  /// Resulting decls can be used as filter for \c foreachOccurrence. This
+  /// allows allocating memory only for the record decls that the caller is
+  /// interested in.
+  bool searchSymbols(llvm::function_ref<bool(IndexRecordSymbol, bool &stop)> filter,
+                     llvm::function_ref<void(IndexRecordSymbol)> receiver) {
+#if INDEXSTORE_HAS_BLOCKS
+    return indexstore_record_reader_search_symbols(obj, ^bool(indexstore_symbol_t symbol, bool *stop) {
+      return filter(symbol, *stop);
+    }, ^(indexstore_symbol_t symbol) {
+      receiver(symbol);
+    });
+#else
+    return false;
+#endif
+  }
+
+  bool foreachSymbol(bool noCache, llvm::function_ref<bool(IndexRecordSymbol)> receiver) {
+#if INDEXSTORE_HAS_BLOCKS
+    return indexstore_record_reader_symbols_apply(obj, noCache, ^bool(indexstore_symbol_t sym) {
+      return receiver(sym);
+    });
+#else
+    return false;
+#endif
+  }
+
+  /// \param DeclsFilter if non-empty indicates the list of decls that we want
+  /// to get occurrences for. An empty array indicates that we want occurrences
+  /// for all decls.
+  /// \param RelatedDeclsFilter Same as \c DeclsFilter but for related decls.
+  bool foreachOccurrence(ArrayRef<IndexRecordSymbol> symbolsFilter,
+                         ArrayRef<IndexRecordSymbol> relatedSymbolsFilter,
+              llvm::function_ref<bool(IndexRecordOccurrence)> receiver) {
+#if INDEXSTORE_HAS_BLOCKS
+    llvm::SmallVector<indexstore_symbol_t, 16> c_symbolsFilter;
+    c_symbolsFilter.reserve(symbolsFilter.size());
+    for (IndexRecordSymbol sym : symbolsFilter) {
+      c_symbolsFilter.push_back(sym.obj);
+    }
+    llvm::SmallVector<indexstore_symbol_t, 16> c_relatedSymbolsFilter;
+    c_relatedSymbolsFilter.reserve(relatedSymbolsFilter.size());
+    for (IndexRecordSymbol sym : relatedSymbolsFilter) {
+      c_relatedSymbolsFilter.push_back(sym.obj);
+    }
+    return indexstore_record_reader_occurrences_of_symbols_apply(obj,
+                                c_symbolsFilter.data(), c_symbolsFilter.size(),
+                                c_relatedSymbolsFilter.data(),
+                                c_relatedSymbolsFilter.size(),
+                                ^bool(indexstore_occurrence_t occur) {
+                                  return receiver(occur);
+                                });
+#else
+    return false;
+#endif
+  }
+
+  bool foreachOccurrence(
+              llvm::function_ref<bool(IndexRecordOccurrence)> receiver) {
+#if INDEXSTORE_HAS_BLOCKS
+    return indexstore_record_reader_occurrences_apply(obj, ^bool(indexstore_occurrence_t occur) {
+      return receiver(occur);
+    });
+#else
+    return false;
+#endif
+  }
+
+  bool foreachOccurrenceInLineRange(unsigned lineStart, unsigned lineEnd,
+              llvm::function_ref<bool(IndexRecordOccurrence)> receiver) {
+#if INDEXSTORE_HAS_BLOCKS
+    return indexstore_record_reader_occurrences_in_line_range_apply(obj,
+                                                                    lineStart,
+                                                                    lineEnd,
+                                          ^bool(indexstore_occurrence_t occur) {
+      return receiver(occur);
+    });
+#else
+    return false;
+#endif
+  }
+};
+
+class IndexUnitDependency {
+  indexstore_unit_dependency_t obj;
+  friend class IndexUnitReader;
+
+public:
+  IndexUnitDependency(indexstore_unit_dependency_t obj) : obj(obj) {}
+
+  enum class DependencyKind {
+    Unit,
+    Record,
+    File,
+  };
+  DependencyKind getKind() {
+    switch (indexstore_unit_dependency_get_kind(obj)) {
+    case INDEXSTORE_UNIT_DEPENDENCY_UNIT: return DependencyKind::Unit;
+    case INDEXSTORE_UNIT_DEPENDENCY_RECORD: return DependencyKind::Record;
+    case INDEXSTORE_UNIT_DEPENDENCY_FILE: return DependencyKind::File;
+    }
+  }
+  bool isSystem() { return indexstore_unit_dependency_is_system(obj); }
+  StringRef getName() { return stringFromIndexStoreStringRef(indexstore_unit_dependency_get_name(obj)); }
+  StringRef getFilePath() { return stringFromIndexStoreStringRef(indexstore_unit_dependency_get_filepath(obj)); }
+  StringRef getModuleName() { return stringFromIndexStoreStringRef(indexstore_unit_dependency_get_modulename(obj)); }
+  time_t getModificationTime() { return indexstore_unit_dependency_get_modification_time(obj); }
+  size_t getFileSize() { return indexstore_unit_dependency_get_file_size(obj); }
+
+};
+
+class IndexUnitInclude {
+  indexstore_unit_include_t obj;
+  friend class IndexUnitReader;
+
+public:
+  IndexUnitInclude(indexstore_unit_include_t obj) : obj(obj) {}
+
+  StringRef getSourcePath() {
+    return stringFromIndexStoreStringRef(indexstore_unit_include_get_source_path(obj));
+  }
+  StringRef getTargetPath() {
+    return stringFromIndexStoreStringRef(indexstore_unit_include_get_target_path(obj));
+  }
+  unsigned getSourceLine() {
+    return indexstore_unit_include_get_source_line(obj);
+  }
+};
+
+class IndexUnitReader {
+  indexstore_unit_reader_t obj;
+
+public:
+  IndexUnitReader(IndexStore &store, StringRef unitName, std::string &error) {
+    llvm::SmallString<64> buf = unitName;
+    indexstore_error_t c_err = nullptr;
+    obj = indexstore_unit_reader_create(store.obj, buf.c_str(), &c_err);
+    if (c_err) {
+      error = indexstore_error_get_description(c_err);
+      indexstore_error_dispose(c_err);
+    }
+  }
+
+  IndexUnitReader(IndexUnitReader &&other) : obj(other.obj) {
+    other.obj = nullptr;
+  }
+
+  ~IndexUnitReader() {
+    indexstore_unit_reader_dispose(obj);
+  }
+
+  bool isValid() const { return obj; }
+  bool isInvalid() const { return !isValid(); }
+  explicit operator bool() const { return isValid(); }
+
+  StringRef getProviderIdentifier() {
+    return stringFromIndexStoreStringRef(indexstore_unit_reader_get_provider_identifier(obj));
+  }
+  StringRef getProviderVersion() {
+    return stringFromIndexStoreStringRef(indexstore_unit_reader_get_provider_version(obj));
+  }
+
+  timespec getModificationTime() {
+    int64_t seconds, nanoseconds;
+    indexstore_unit_reader_get_modification_time(obj, &seconds, &nanoseconds);
+    timespec ts;
+    ts.tv_sec = seconds;
+    ts.tv_nsec = nanoseconds;
+    return ts;
+  }
+
+  bool isSystemUnit() { return indexstore_unit_reader_is_system_unit(obj); }
+  bool isModuleUnit() { return indexstore_unit_reader_is_module_unit(obj); }
+  bool isDebugCompilation() { return indexstore_unit_reader_is_debug_compilation(obj); }
+  bool hasMainFile() { return indexstore_unit_reader_has_main_file(obj); }
+
+  StringRef getMainFilePath() {
+    return stringFromIndexStoreStringRef(indexstore_unit_reader_get_main_file(obj));
+  }
+  StringRef getModuleName() {
+    return stringFromIndexStoreStringRef(indexstore_unit_reader_get_module_name(obj));
+  }
+  StringRef getWorkingDirectory() {
+    return stringFromIndexStoreStringRef(indexstore_unit_reader_get_working_dir(obj));
+  }
+  StringRef getOutputFile() {
+    return stringFromIndexStoreStringRef(indexstore_unit_reader_get_output_file(obj));
+  }
+  StringRef getSysrootPath() {
+    return stringFromIndexStoreStringRef(indexstore_unit_reader_get_sysroot_path(obj));
+  }
+  StringRef getTarget() {
+    return stringFromIndexStoreStringRef(indexstore_unit_reader_get_target(obj));
+  }
+
+  bool foreachDependency(llvm::function_ref<bool(IndexUnitDependency)> receiver) {
+#if INDEXSTORE_HAS_BLOCKS
+    return indexstore_unit_reader_dependencies_apply(obj, ^bool(indexstore_unit_dependency_t dep) {
+      return receiver(dep);
+    });
+#else
+    return false;
+#endif
+  }
+
+  bool foreachInclude(llvm::function_ref<bool(IndexUnitInclude)> receiver) {
+#if INDEXSTORE_HAS_BLOCKS
+    return indexstore_unit_reader_includes_apply(obj, ^bool(indexstore_unit_include_t inc) {
+      return receiver(inc);
+    });
+#else
+    return false;
+#endif
+  }
+};
+
+} // namespace indexstore
+
+#endif
diff --git a/include/indexstore/indexstore.h b/include/indexstore/indexstore.h
new file mode 100644
index 0000000..024cdf6
--- /dev/null
+++ b/include/indexstore/indexstore.h
@@ -0,0 +1,487 @@
+/*===-- indexstore/indexstore.h - Index Store C API ----------------- C -*-===*\
+|*                                                                            *|
+|*                     The LLVM Compiler Infrastructure                       *|
+|*                                                                            *|
+|* This file is distributed under the University of Illinois Open Source      *|
+|* License. See LICENSE.TXT for details.                                      *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* This header provides a C API for the index store.                          *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_CLANG_C_INDEXSTORE_INDEXSTORE_H
+#define LLVM_CLANG_C_INDEXSTORE_INDEXSTORE_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <ctime>
+
+/**
+ * \brief The version constants for the Index Store C API.
+ * INDEXSTORE_VERSION_MINOR should increase when there are API additions.
+ * INDEXSTORE_VERSION_MAJOR is intended for "major" source/ABI breaking changes.
+ */
+#define INDEXSTORE_VERSION_MAJOR 0
+#define INDEXSTORE_VERSION_MINOR 9
+
+#define INDEXSTORE_VERSION_ENCODE(major, minor) ( \
+      ((major) * 10000)                           \
+    + ((minor) *     1))
+
+#define INDEXSTORE_VERSION INDEXSTORE_VERSION_ENCODE( \
+    INDEXSTORE_VERSION_MAJOR,                         \
+    INDEXSTORE_VERSION_MINOR )
+
+#define INDEXSTORE_VERSION_STRINGIZE_(major, minor)   \
+    #major"."#minor
+#define INDEXSTORE_VERSION_STRINGIZE(major, minor)    \
+    INDEXSTORE_VERSION_STRINGIZE_(major, minor)
+
+#define INDEXSTORE_VERSION_STRING INDEXSTORE_VERSION_STRINGIZE( \
+    INDEXSTORE_VERSION_MAJOR,                                   \
+    INDEXSTORE_VERSION_MINOR)
+
+#ifdef  __cplusplus
+# define INDEXSTORE_BEGIN_DECLS  extern "C" {
+# define INDEXSTORE_END_DECLS    }
+#else
+# define INDEXSTORE_BEGIN_DECLS
+# define INDEXSTORE_END_DECLS
+#endif
+
+#ifndef INDEXSTORE_PUBLIC
+# if defined (_MSC_VER)
+#  define INDEXSTORE_PUBLIC __declspec(dllimport)
+# else
+#  define INDEXSTORE_PUBLIC
+# endif
+#endif
+
+#ifndef __has_feature
+# define __has_feature(x) 0
+#endif
+
+#if __has_feature(blocks)
+# define INDEXSTORE_HAS_BLOCKS 1
+#else
+# define INDEXSTORE_HAS_BLOCKS 0
+#endif
+
+INDEXSTORE_BEGIN_DECLS
+
+typedef void *indexstore_error_t;
+
+INDEXSTORE_PUBLIC const char *
+indexstore_error_get_description(indexstore_error_t);
+
+INDEXSTORE_PUBLIC void
+indexstore_error_dispose(indexstore_error_t);
+
+typedef struct {
+  const char *data;
+  size_t length;
+} indexstore_string_ref_t;
+
+INDEXSTORE_PUBLIC unsigned
+indexstore_format_version(void);
+
+typedef void *indexstore_t;
+
+INDEXSTORE_PUBLIC indexstore_t
+indexstore_store_create(const char *store_path, indexstore_error_t *error);
+
+INDEXSTORE_PUBLIC void
+indexstore_store_dispose(indexstore_t);
+
+#if INDEXSTORE_HAS_BLOCKS
+INDEXSTORE_PUBLIC bool
+indexstore_store_units_apply(indexstore_t, unsigned sorted,
+                             bool(^applier)(indexstore_string_ref_t unit_name));
+#endif
+
+typedef void *indexstore_unit_event_notification_t;
+typedef void *indexstore_unit_event_t;
+
+INDEXSTORE_PUBLIC size_t
+indexstore_unit_event_notification_get_events_count(indexstore_unit_event_notification_t);
+
+INDEXSTORE_PUBLIC indexstore_unit_event_t
+indexstore_unit_event_notification_get_event(indexstore_unit_event_notification_t, size_t index);
+
+INDEXSTORE_PUBLIC bool
+indexstore_unit_event_notification_is_initial(indexstore_unit_event_notification_t);
+
+typedef enum {
+  INDEXSTORE_UNIT_EVENT_ADDED = 1,
+  INDEXSTORE_UNIT_EVENT_REMOVED = 2,
+  INDEXSTORE_UNIT_EVENT_MODIFIED = 3,
+  INDEXSTORE_UNIT_EVENT_DIRECTORY_DELETED = 4,
+} indexstore_unit_event_kind_t;
+
+INDEXSTORE_PUBLIC indexstore_unit_event_kind_t
+indexstore_unit_event_get_kind(indexstore_unit_event_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_event_get_unit_name(indexstore_unit_event_t);
+
+INDEXSTORE_PUBLIC timespec
+indexstore_unit_event_get_modification_time(indexstore_unit_event_t);
+
+#if INDEXSTORE_HAS_BLOCKS
+typedef void (^indexstore_unit_event_handler_t)(indexstore_unit_event_notification_t);
+
+INDEXSTORE_PUBLIC void
+indexstore_store_set_unit_event_handler(indexstore_t,
+                                        indexstore_unit_event_handler_t handler);
+#endif
+
+typedef struct {
+  /// If true, \c indexstore_store_start_unit_event_listening will block until
+  /// the initial set of units is passed to the unit event handler, otherwise
+  /// the function will return and the initial set will be passed asynchronously.
+  bool wait_initial_sync;
+} indexstore_unit_event_listen_options_t;
+
+INDEXSTORE_PUBLIC bool
+indexstore_store_start_unit_event_listening(indexstore_t,
+                                            indexstore_unit_event_listen_options_t *,
+                                            size_t listen_options_struct_size,
+                                            indexstore_error_t *error);
+
+INDEXSTORE_PUBLIC void
+indexstore_store_stop_unit_event_listening(indexstore_t);
+
+INDEXSTORE_PUBLIC void
+indexstore_store_discard_unit(indexstore_t, const char *unit_name);
+
+INDEXSTORE_PUBLIC void
+indexstore_store_discard_record(indexstore_t, const char *record_name);
+
+INDEXSTORE_PUBLIC void
+indexstore_store_purge_stale_data(indexstore_t);
+
+/// Determines the unit name from the \c output_path and writes it out in the
+/// \c name_buf buffer. It doesn't write more than \c buf_size.
+/// \returns the length of the name. If this is larger than \c buf_size, the
+/// caller should call the function again with a buffer of the appropriate size.
+INDEXSTORE_PUBLIC size_t
+indexstore_store_get_unit_name_from_output_path(indexstore_t store,
+                                                const char *output_path,
+                                                char *name_buf,
+                                                size_t buf_size);
+
+/// \returns true if an error occurred, false otherwise.
+INDEXSTORE_PUBLIC bool
+indexstore_store_get_unit_modification_time(indexstore_t store,
+                                            const char *unit_name,
+                                            int64_t *seconds,
+                                            int64_t *nanoseconds,
+                                            indexstore_error_t *error);
+
+typedef void *indexstore_symbol_t;
+
+typedef enum {
+  INDEXSTORE_SYMBOL_KIND_UNKNOWN = 0,
+  INDEXSTORE_SYMBOL_KIND_MODULE = 1,
+  INDEXSTORE_SYMBOL_KIND_NAMESPACE = 2,
+  INDEXSTORE_SYMBOL_KIND_NAMESPACEALIAS = 3,
+  INDEXSTORE_SYMBOL_KIND_MACRO = 4,
+  INDEXSTORE_SYMBOL_KIND_ENUM = 5,
+  INDEXSTORE_SYMBOL_KIND_STRUCT = 6,
+  INDEXSTORE_SYMBOL_KIND_CLASS = 7,
+  INDEXSTORE_SYMBOL_KIND_PROTOCOL = 8,
+  INDEXSTORE_SYMBOL_KIND_EXTENSION = 9,
+  INDEXSTORE_SYMBOL_KIND_UNION = 10,
+  INDEXSTORE_SYMBOL_KIND_TYPEALIAS = 11,
+  INDEXSTORE_SYMBOL_KIND_FUNCTION = 12,
+  INDEXSTORE_SYMBOL_KIND_VARIABLE = 13,
+  INDEXSTORE_SYMBOL_KIND_FIELD = 14,
+  INDEXSTORE_SYMBOL_KIND_ENUMCONSTANT = 15,
+  INDEXSTORE_SYMBOL_KIND_INSTANCEMETHOD = 16,
+  INDEXSTORE_SYMBOL_KIND_CLASSMETHOD = 17,
+  INDEXSTORE_SYMBOL_KIND_STATICMETHOD = 18,
+  INDEXSTORE_SYMBOL_KIND_INSTANCEPROPERTY = 19,
+  INDEXSTORE_SYMBOL_KIND_CLASSPROPERTY = 20,
+  INDEXSTORE_SYMBOL_KIND_STATICPROPERTY = 21,
+  INDEXSTORE_SYMBOL_KIND_CONSTRUCTOR = 22,
+  INDEXSTORE_SYMBOL_KIND_DESTRUCTOR = 23,
+  INDEXSTORE_SYMBOL_KIND_CONVERSIONFUNCTION = 24,
+  INDEXSTORE_SYMBOL_KIND_PARAMETER = 25,
+
+  INDEXSTORE_SYMBOL_KIND_COMMENTTAG = 1000,
+} indexstore_symbol_kind_t;
+
+typedef enum {
+  INDEXSTORE_SYMBOL_SUBKIND_NONE = 0,
+  INDEXSTORE_SYMBOL_SUBKIND_CXXCOPYCONSTRUCTOR = 1,
+  INDEXSTORE_SYMBOL_SUBKIND_CXXMOVECONSTRUCTOR = 2,
+  INDEXSTORE_SYMBOL_SUBKIND_ACCESSORGETTER = 3,
+  INDEXSTORE_SYMBOL_SUBKIND_ACCESSORSETTER = 4,
+
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORWILLSET = 1000,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORDIDSET = 1001,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORADDRESSOR = 1002,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMUTABLEADDRESSOR = 1003,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFSTRUCT = 1004,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFCLASS = 1005,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFENUM = 1006,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFPROTOCOL = 1007,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTPREFIXOPERATOR = 1008,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTPOSTFIXOPERATOR = 1009,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTINFIXOPERATOR = 1010,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTSUBSCRIPT = 1011,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTASSOCIATEDTYPE = 1012,
+  INDEXSTORE_SYMBOL_SUBKIND_SWIFTGENERICTYPEPARAM = 1013,
+} indexstore_symbol_subkind_t;
+
+typedef enum {
+  INDEXSTORE_SYMBOL_PROPERTY_GENERIC                          = 1 << 0,
+  INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_PARTIAL_SPECIALIZATION  = 1 << 1,
+  INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_SPECIALIZATION          = 1 << 2,
+  INDEXSTORE_SYMBOL_PROPERTY_UNITTEST                         = 1 << 3,
+  INDEXSTORE_SYMBOL_PROPERTY_IBANNOTATED                      = 1 << 4,
+  INDEXSTORE_SYMBOL_PROPERTY_IBOUTLETCOLLECTION               = 1 << 5,
+  INDEXSTORE_SYMBOL_PROPERTY_GKINSPECTABLE                    = 1 << 6,
+  INDEXSTORE_SYMBOL_PROPERTY_LOCAL                            = 1 << 7,
+} indexstore_symbol_property_t;
+
+typedef enum {
+  INDEXSTORE_SYMBOL_LANG_C = 0,
+  INDEXSTORE_SYMBOL_LANG_OBJC = 1,
+  INDEXSTORE_SYMBOL_LANG_CXX = 2,
+
+  INDEXSTORE_SYMBOL_LANG_SWIFT = 100,
+} indexstore_symbol_language_t;
+
+typedef enum {
+  INDEXSTORE_SYMBOL_ROLE_DECLARATION = 1 << 0,
+  INDEXSTORE_SYMBOL_ROLE_DEFINITION  = 1 << 1,
+  INDEXSTORE_SYMBOL_ROLE_REFERENCE   = 1 << 2,
+  INDEXSTORE_SYMBOL_ROLE_READ        = 1 << 3,
+  INDEXSTORE_SYMBOL_ROLE_WRITE       = 1 << 4,
+  INDEXSTORE_SYMBOL_ROLE_CALL        = 1 << 5,
+  INDEXSTORE_SYMBOL_ROLE_DYNAMIC     = 1 << 6,
+  INDEXSTORE_SYMBOL_ROLE_ADDRESSOF   = 1 << 7,
+  INDEXSTORE_SYMBOL_ROLE_IMPLICIT    = 1 << 8,
+
+  // Relation roles.
+  INDEXSTORE_SYMBOL_ROLE_REL_CHILDOF     = 1 << 9,
+  INDEXSTORE_SYMBOL_ROLE_REL_BASEOF      = 1 << 10,
+  INDEXSTORE_SYMBOL_ROLE_REL_OVERRIDEOF  = 1 << 11,
+  INDEXSTORE_SYMBOL_ROLE_REL_RECEIVEDBY  = 1 << 12,
+  INDEXSTORE_SYMBOL_ROLE_REL_CALLEDBY    = 1 << 13,
+  INDEXSTORE_SYMBOL_ROLE_REL_EXTENDEDBY  = 1 << 14,
+  INDEXSTORE_SYMBOL_ROLE_REL_ACCESSOROF  = 1 << 15,
+  INDEXSTORE_SYMBOL_ROLE_REL_CONTAINEDBY = 1 << 16,
+  INDEXSTORE_SYMBOL_ROLE_REL_IBTYPEOF    = 1 << 17,
+  INDEXSTORE_SYMBOL_ROLE_REL_SPECIALIZATIONOF = 1 << 18,
+} indexstore_symbol_role_t;
+
+INDEXSTORE_PUBLIC indexstore_symbol_language_t
+indexstore_symbol_get_language(indexstore_symbol_t);
+
+INDEXSTORE_PUBLIC indexstore_symbol_kind_t
+indexstore_symbol_get_kind(indexstore_symbol_t);
+
+INDEXSTORE_PUBLIC indexstore_symbol_subkind_t
+indexstore_symbol_get_subkind(indexstore_symbol_t);
+
+INDEXSTORE_PUBLIC uint64_t
+indexstore_symbol_get_properties(indexstore_symbol_t);
+
+INDEXSTORE_PUBLIC uint64_t
+indexstore_symbol_get_roles(indexstore_symbol_t);
+
+INDEXSTORE_PUBLIC uint64_t
+indexstore_symbol_get_related_roles(indexstore_symbol_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_symbol_get_name(indexstore_symbol_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_symbol_get_usr(indexstore_symbol_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_symbol_get_codegen_name(indexstore_symbol_t);
+
+typedef void *indexstore_symbol_relation_t;
+
+INDEXSTORE_PUBLIC uint64_t
+indexstore_symbol_relation_get_roles(indexstore_symbol_relation_t);
+
+INDEXSTORE_PUBLIC indexstore_symbol_t
+indexstore_symbol_relation_get_symbol(indexstore_symbol_relation_t);
+
+typedef void *indexstore_occurrence_t;
+
+INDEXSTORE_PUBLIC indexstore_symbol_t
+indexstore_occurrence_get_symbol(indexstore_occurrence_t);
+
+#if INDEXSTORE_HAS_BLOCKS
+INDEXSTORE_PUBLIC bool
+indexstore_occurrence_relations_apply(indexstore_occurrence_t,
+                      bool(^applier)(indexstore_symbol_relation_t symbol_rel));
+#endif
+
+INDEXSTORE_PUBLIC uint64_t
+indexstore_occurrence_get_roles(indexstore_occurrence_t);
+
+INDEXSTORE_PUBLIC void
+indexstore_occurrence_get_line_col(indexstore_occurrence_t,
+                              unsigned *line, unsigned *column);
+
+typedef void *indexstore_record_reader_t;
+
+INDEXSTORE_PUBLIC indexstore_record_reader_t
+indexstore_record_reader_create(indexstore_t store, const char *record_name,
+                                indexstore_error_t *error);
+
+INDEXSTORE_PUBLIC void
+indexstore_record_reader_dispose(indexstore_record_reader_t);
+
+#if INDEXSTORE_HAS_BLOCKS
+/// Goes through the symbol data and passes symbols to \c receiver, for the
+/// symbol data that \c filter returns true on.
+///
+/// This allows allocating memory only for the record symbols that the caller is
+/// interested in.
+INDEXSTORE_PUBLIC bool
+indexstore_record_reader_search_symbols(indexstore_record_reader_t,
+    bool(^filter)(indexstore_symbol_t symbol, bool *stop),
+    void(^receiver)(indexstore_symbol_t symbol));
+
+/// \param nocache if true, avoids allocating memory for the symbols.
+/// Useful when the caller does not intend to keep \c indexstore_record_reader_t
+/// for more queries.
+INDEXSTORE_PUBLIC bool
+indexstore_record_reader_symbols_apply(indexstore_record_reader_t,
+                                       bool nocache,
+                                    bool(^applier)(indexstore_symbol_t symbol));
+
+INDEXSTORE_PUBLIC bool
+indexstore_record_reader_occurrences_apply(indexstore_record_reader_t,
+                                 bool(^applier)(indexstore_occurrence_t occur));
+
+INDEXSTORE_PUBLIC bool
+indexstore_record_reader_occurrences_in_line_range_apply(indexstore_record_reader_t,
+                                                         unsigned line_start,
+                                                         unsigned line_count,
+                                 bool(^applier)(indexstore_occurrence_t occur));
+
+/// \param symbols if non-zero \c symbols_count, indicates the list of symbols
+/// that we want to get occurrences for. An empty array indicates that we want
+/// occurrences for all symbols.
+/// \param related_symbols Same as \c symbols but for related symbols.
+INDEXSTORE_PUBLIC bool
+indexstore_record_reader_occurrences_of_symbols_apply(indexstore_record_reader_t,
+        indexstore_symbol_t *symbols, size_t symbols_count,
+        indexstore_symbol_t *related_symbols, size_t related_symbols_count,
+        bool(^applier)(indexstore_occurrence_t occur));
+#endif
+
+
+typedef void *indexstore_unit_reader_t;
+
+INDEXSTORE_PUBLIC indexstore_unit_reader_t
+indexstore_unit_reader_create(indexstore_t store, const char *unit_name,
+                              indexstore_error_t *error);
+
+INDEXSTORE_PUBLIC void
+indexstore_unit_reader_dispose(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_reader_get_provider_identifier(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_reader_get_provider_version(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC void
+indexstore_unit_reader_get_modification_time(indexstore_unit_reader_t,
+                                             int64_t *seconds,
+                                             int64_t *nanoseconds);
+
+INDEXSTORE_PUBLIC bool
+indexstore_unit_reader_is_system_unit(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC bool
+indexstore_unit_reader_is_module_unit(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC bool
+indexstore_unit_reader_is_debug_compilation(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC bool
+indexstore_unit_reader_has_main_file(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_reader_get_main_file(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_reader_get_module_name(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_reader_get_working_dir(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_reader_get_output_file(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_reader_get_sysroot_path(indexstore_unit_reader_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_reader_get_target(indexstore_unit_reader_t);
+
+typedef void *indexstore_unit_dependency_t;
+typedef void *indexstore_unit_include_t;
+
+typedef enum {
+  INDEXSTORE_UNIT_DEPENDENCY_UNIT = 1,
+  INDEXSTORE_UNIT_DEPENDENCY_RECORD = 2,
+  INDEXSTORE_UNIT_DEPENDENCY_FILE = 3,
+} indexstore_unit_dependency_kind_t;
+
+INDEXSTORE_PUBLIC indexstore_unit_dependency_kind_t
+indexstore_unit_dependency_get_kind(indexstore_unit_dependency_t);
+
+INDEXSTORE_PUBLIC bool
+indexstore_unit_dependency_is_system(indexstore_unit_dependency_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_dependency_get_filepath(indexstore_unit_dependency_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_dependency_get_modulename(indexstore_unit_dependency_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_dependency_get_name(indexstore_unit_dependency_t);
+
+INDEXSTORE_PUBLIC time_t
+indexstore_unit_dependency_get_modification_time(indexstore_unit_dependency_t);
+
+INDEXSTORE_PUBLIC size_t
+indexstore_unit_dependency_get_file_size(indexstore_unit_dependency_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_include_get_source_path(indexstore_unit_include_t);
+
+INDEXSTORE_PUBLIC indexstore_string_ref_t
+indexstore_unit_include_get_target_path(indexstore_unit_include_t);
+
+INDEXSTORE_PUBLIC unsigned
+indexstore_unit_include_get_source_line(indexstore_unit_include_t);
+
+#if INDEXSTORE_HAS_BLOCKS
+INDEXSTORE_PUBLIC bool
+indexstore_unit_reader_dependencies_apply(indexstore_unit_reader_t,
+                             bool(^applier)(indexstore_unit_dependency_t));
+
+INDEXSTORE_PUBLIC bool
+indexstore_unit_reader_includes_apply(indexstore_unit_reader_t,
+                             bool(^applier)(indexstore_unit_include_t));
+
+#endif
+
+INDEXSTORE_END_DECLS
+
+#endif
diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt
index 574c511..5e291e5 100644
--- a/lib/CMakeLists.txt
+++ b/lib/CMakeLists.txt
@@ -19,6 +19,7 @@
 add_subdirectory(FrontendTool)
 add_subdirectory(Tooling)
 add_subdirectory(Index)
+add_subdirectory(DirectoryWatcher)
 if(CLANG_ENABLE_STATIC_ANALYZER)
   add_subdirectory(StaticAnalyzer)
 endif()
diff --git a/lib/DirectoryWatcher/CMakeLists.txt b/lib/DirectoryWatcher/CMakeLists.txt
new file mode 100644
index 0000000..425a40f
--- /dev/null
+++ b/lib/DirectoryWatcher/CMakeLists.txt
@@ -0,0 +1,8 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangDirectoryWatcher
+  DirectoryWatcher.cpp
+
+  LINK_LIBS
+  clangBasic
+  )
diff --git a/lib/DirectoryWatcher/DirectoryWatcher.cpp b/lib/DirectoryWatcher/DirectoryWatcher.cpp
new file mode 100644
index 0000000..3a90526
--- /dev/null
+++ b/lib/DirectoryWatcher/DirectoryWatcher.cpp
@@ -0,0 +1,275 @@
+//===- DirectoryWatcher.cpp - Listens for directory file changes ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// \brief Utility class for listening for file system changes in a directory.
+//===----------------------------------------------------------------------===//
+
+#include "clang/DirectoryWatcher/DirectoryWatcher.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define HAVE_CORESERVICES 0
+
+#if defined(__has_include)
+#if __has_include(<CoreServices/CoreServices.h>)
+
+#include <CoreServices/CoreServices.h>
+#undef HAVE_CORESERVICES
+#define HAVE_CORESERVICES 1
+
+#endif
+#endif
+
+using namespace clang;
+using namespace llvm;
+
+static timespec toTimeSpec(sys::TimePoint<> tp) {
+  std::chrono::seconds sec = std::chrono::time_point_cast<std::chrono::seconds>(
+                 tp).time_since_epoch();
+  std::chrono::nanoseconds nsec =
+    std::chrono::time_point_cast<std::chrono::nanoseconds>(tp - sec)
+      .time_since_epoch();
+  timespec ts;
+  ts.tv_sec = sec.count();
+  ts.tv_nsec = nsec.count();
+  return ts;
+}
+
+static Optional<timespec> getModTime(StringRef path) {
+  sys::fs::file_status Status;
+  std::error_code EC = status(path, Status);
+  if (EC)
+    return None;
+  return toTimeSpec(Status.getLastModificationTime());
+}
+
+struct DirectoryWatcher::Implementation {
+#if HAVE_CORESERVICES
+  FSEventStreamRef EventStream = nullptr;
+
+  bool setupFSEventStream(StringRef path, EventReceiver receiver,
+                          dispatch_queue_t queue);
+  void stopFSEventStream();
+
+  ~Implementation() {
+    stopFSEventStream();
+  };
+#endif
+};
+
+#if HAVE_CORESERVICES
+namespace {
+struct EventStreamContextData {
+  std::string WatchedPath;
+  DirectoryWatcher::EventReceiver Receiver;
+
+  EventStreamContextData(std::string watchedPath, DirectoryWatcher::EventReceiver receiver)
+  : WatchedPath(std::move(watchedPath)), Receiver(std::move(receiver)) {
+  }
+
+  static void dispose(const void *ctx) {
+    delete static_cast<const EventStreamContextData*>(ctx);
+  }
+};
+}
+
+static void eventStreamCallback(
+                       ConstFSEventStreamRef stream,
+                       void *clientCallBackInfo,
+                       size_t numEvents,
+                       void *eventPaths,
+                       const FSEventStreamEventFlags eventFlags[],
+                       const FSEventStreamEventId eventIds[]) {
+  auto *ctx = static_cast<EventStreamContextData*>(clientCallBackInfo);
+
+  std::vector<DirectoryWatcher::Event> Events;
+  for (size_t i = 0; i < numEvents; ++i) {
+    StringRef path = ((const char **)eventPaths)[i];
+    const FSEventStreamEventFlags flags = eventFlags[i];
+    if (!(flags & kFSEventStreamEventFlagItemIsFile)) {
+      if ((flags & kFSEventStreamEventFlagItemRemoved) && path == ctx->WatchedPath) {
+        DirectoryWatcher::Event Evt{DirectoryWatcher::EventKind::DirectoryDeleted, path, timespec{}};
+        Events.push_back(Evt);
+        break;
+      }
+      continue;
+    }
+    DirectoryWatcher::EventKind K = DirectoryWatcher::EventKind::Modified;
+    if ((flags & kFSEventStreamEventFlagItemCreated) ||
+        (flags & kFSEventStreamEventFlagItemRenamed))
+      K = DirectoryWatcher::EventKind::Added;
+    if (flags & kFSEventStreamEventFlagItemRemoved)
+      K = DirectoryWatcher::EventKind::Removed;
+    timespec modTime{};
+    if (K != DirectoryWatcher::EventKind::Removed) {
+      auto modTimeOpt = getModTime(path);
+      if (!modTimeOpt.hasValue())
+        continue;
+      modTime = modTimeOpt.getValue();
+    }
+    DirectoryWatcher::Event Evt{K, path, modTime};
+    Events.push_back(Evt);
+  }
+
+  ctx->Receiver(Events, /*isInitial=*/false);
+}
+
+bool DirectoryWatcher::Implementation::setupFSEventStream(StringRef path,
+                                                          EventReceiver receiver,
+                                                          dispatch_queue_t queue) {
+  if (path.empty())
+    return true;
+
+  CFMutableArrayRef pathsToWatch = CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks);
+  CFStringRef cfPathStr = CFStringCreateWithBytes(nullptr, (const UInt8 *)path.data(), path.size(), kCFStringEncodingUTF8, false);
+  CFArrayAppendValue(pathsToWatch, cfPathStr);
+  CFRelease(cfPathStr);
+  CFAbsoluteTime latency = 0.2; // Latency in seconds.
+
+  std::string realPath;
+  {
+    SmallString<128> Storage;
+    StringRef P = llvm::Twine(path).toNullTerminatedStringRef(Storage);
+    char Buffer[PATH_MAX];
+    // Use ::realpath to get the real path name
+    if (::realpath(P.begin(), Buffer) != nullptr)
+      realPath = Buffer;
+    else
+      realPath = path;
+  }
+
+  EventStreamContextData *ctxData = new EventStreamContextData(std::move(realPath), std::move(receiver));
+  FSEventStreamContext context;
+  context.version = 0;
+  context.info = ctxData;
+  context.retain = nullptr;
+  context.release = EventStreamContextData::dispose;
+  context.copyDescription = nullptr;
+
+  EventStream = FSEventStreamCreate(nullptr,
+                                    eventStreamCallback,
+                                    &context,
+                                    pathsToWatch,
+                                    kFSEventStreamEventIdSinceNow,
+                                    latency,
+                                    kFSEventStreamCreateFlagFileEvents |
+                                    kFSEventStreamCreateFlagNoDefer);
+  CFRelease(pathsToWatch);
+  if (!EventStream) {
+    return true;
+  }
+  FSEventStreamSetDispatchQueue(EventStream, queue);
+  FSEventStreamStart(EventStream);
+  return false;
+}
+
+void DirectoryWatcher::Implementation::stopFSEventStream() {
+  if (!EventStream)
+    return;
+  FSEventStreamStop(EventStream);
+  FSEventStreamInvalidate(EventStream);
+  FSEventStreamRelease(EventStream);
+  EventStream = nullptr;
+}
+#endif
+
+DirectoryWatcher::DirectoryWatcher()
+  : Impl(*new Implementation()) {}
+
+DirectoryWatcher::~DirectoryWatcher() {
+  delete &Impl;
+}
+
+#if HAVE_CORESERVICES
+static std::vector<DirectoryWatcher::Event> scanDirectory(StringRef Path) {
+  using namespace llvm::sys;
+
+  std::vector<DirectoryWatcher::Event> Events;
+  std::error_code EC;
+  for (auto It = fs::directory_iterator(Path, EC), End = fs::directory_iterator();
+         !EC && It != End; It.increment(EC)) {
+    auto modTime = getModTime(It->path());
+    if (!modTime.hasValue())
+      continue;
+    DirectoryWatcher::Event Event{DirectoryWatcher::EventKind::Added, It->path(), modTime.getValue()};
+    Events.push_back(std::move(Event));
+  }
+  return Events;
+}
+#endif
+
+std::unique_ptr<DirectoryWatcher> DirectoryWatcher::create(StringRef Path,
+        EventReceiver Receiver, bool waitInitialSync, std::string &Error) {
+#if HAVE_CORESERVICES
+
+  using namespace llvm::sys;
+
+  if (!fs::exists(Path)) {
+    std::error_code EC = fs::create_directories(Path);
+    if (EC) {
+      Error = EC.message();
+      return nullptr;
+    }
+  }
+
+  bool IsDir;
+  std::error_code EC = fs::is_directory(Path, IsDir);
+  if (EC) {
+    Error = EC.message();
+    return nullptr;
+  }
+  if (!IsDir) {
+    Error = "path is not a directory: ";
+    Error += Path;
+    return nullptr;
+  }
+
+  std::unique_ptr<DirectoryWatcher> DirWatch;
+  DirWatch.reset(new DirectoryWatcher());
+  auto &Impl = DirWatch->Impl;
+
+  dispatch_queue_t queue = dispatch_queue_create("DirectoryWatcher", DISPATCH_QUEUE_SERIAL);
+  dispatch_semaphore_t initScanSema = dispatch_semaphore_create(0);
+  dispatch_semaphore_t setupFSEventsSema = dispatch_semaphore_create(0);
+
+  std::string copiedPath = Path;
+  dispatch_retain(initScanSema);
+  dispatch_retain(setupFSEventsSema);
+  dispatch_async(queue, ^{
+    // Wait for the event stream to be setup before doing the initial scan,
+    // to make sure we won't miss any events.
+    dispatch_semaphore_wait(setupFSEventsSema, DISPATCH_TIME_FOREVER);
+    auto events = scanDirectory(copiedPath);
+    Receiver(events, /*isInitial=*/true);
+    dispatch_semaphore_signal(initScanSema);
+    dispatch_release(setupFSEventsSema);
+    dispatch_release(initScanSema);
+  });
+  bool fsErr = Impl.setupFSEventStream(Path, Receiver, queue);
+  dispatch_semaphore_signal(setupFSEventsSema);
+
+  if (waitInitialSync) {
+    dispatch_semaphore_wait(initScanSema, DISPATCH_TIME_FOREVER);
+  }
+  dispatch_release(setupFSEventsSema);
+  dispatch_release(initScanSema);
+  dispatch_release(queue);
+
+  if (fsErr) {
+    raw_string_ostream(Error) << "failed to setup FSEvents stream for path: " << Path;
+    return nullptr;
+  }
+
+  return DirWatch;
+#else
+  return nullptr;
+#endif
+}
diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp
index c32f8a4..1b39597 100644
--- a/lib/Driver/Driver.cpp
+++ b/lib/Driver/Driver.cpp
@@ -938,7 +938,9 @@
   }
 
   // Assume associated files are based off of the first temporary file.
-  CrashReportInfo CrashInfo(TempFiles[0], VFS);
+  CrashReportInfo CrashInfo(
+      TempFiles[0], VFS,
+      C.getArgs().getLastArgValue(options::OPT_index_store_path));
 
   std::string Script = CrashInfo.Filename.rsplit('.').first.str() + ".sh";
   std::error_code EC;
diff --git a/lib/Driver/Job.cpp b/lib/Driver/Job.cpp
index 595d6e6..0064668 100644
--- a/lib/Driver/Job.cpp
+++ b/lib/Driver/Job.cpp
@@ -67,6 +67,8 @@
     .Default(false);
   if (IsInclude)
     return HaveCrashVFS ? false : true;
+  if (StringRef(Flag).startswith("-index-store-path"))
+    return true;
 
   // The remaining flags are treated as a single argument.
 
@@ -221,6 +223,7 @@
   }
 
   bool HaveCrashVFS = CrashInfo && !CrashInfo->VFSPath.empty();
+  bool HaveIndexStorePath = CrashInfo && !CrashInfo->IndexStorePath.empty();
   for (size_t i = 0, e = Args.size(); i < e; ++i) {
     const char *const Arg = Args[i];
 
@@ -284,6 +287,24 @@
     printArg(OS, ModCachePath, Quote);
   }
 
+  if (CrashInfo && HaveIndexStorePath) {
+    SmallString<128> IndexStoreDir;
+
+    if (HaveCrashVFS) {
+      IndexStoreDir = llvm::sys::path::parent_path(
+          llvm::sys::path::parent_path(CrashInfo->VFSPath));
+      llvm::sys::path::append(IndexStoreDir, "index-store");
+    } else {
+      IndexStoreDir = "index-store";
+    }
+
+    OS << ' ';
+    printArg(OS, "-index-store-path", Quote);
+    OS << ' ';
+    printArg(OS, IndexStoreDir.c_str(), Quote);
+  }
+
+
   if (ResponseFile != nullptr) {
     OS << "\n Arguments passed via response file:\n";
     writeResponseFile(OS);
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index fd294c2..77804f2 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -5118,6 +5118,25 @@
     Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path);
   }
 
+  if (Args.hasArg(options::OPT_index_store_path)) {
+    Args.AddLastArg(CmdArgs, options::OPT_index_store_path);
+    Args.AddLastArg(CmdArgs, options::OPT_index_ignore_system_symbols);
+    Args.AddLastArg(CmdArgs, options::OPT_index_record_codegen_name);
+
+    // If '-o' is passed along with '-fsyntax-only' pass it along the cc1
+    // invocation so that the index action knows what the out file is.
+    if (isa<CompileJobAction>(JA) && JA.getType() == types::TY_Nothing) {
+      Args.AddLastArg(CmdArgs, options::OPT_o);
+    }
+  }
+
+  if (const char *IdxStorePath = ::getenv("CLANG_PROJECT_INDEX_PATH")) {
+    CmdArgs.push_back("-index-store-path");
+    CmdArgs.push_back(IdxStorePath);
+    CmdArgs.push_back("-index-ignore-system-symbols");
+    CmdArgs.push_back("-index-record-codegen-name");
+  }
+
   // Add preprocessing options like -I, -D, etc. if we are using the
   // preprocessor.
   //
@@ -8548,6 +8567,10 @@
   // more information.
   ArgStringList CmdArgs;
 
+  Args.ClaimAllArgs(options::OPT_index_store_path);
+  Args.ClaimAllArgs(options::OPT_index_ignore_system_symbols);
+  Args.ClaimAllArgs(options::OPT_index_record_codegen_name);
+
   /// Hack(tm) to ignore linking errors when we are doing ARC migration.
   if (Args.hasArg(options::OPT_ccc_arcmt_check,
                   options::OPT_ccc_arcmt_migrate)) {
diff --git a/lib/Frontend/CMakeLists.txt b/lib/Frontend/CMakeLists.txt
index 18abecd..0104564 100644
--- a/lib/Frontend/CMakeLists.txt
+++ b/lib/Frontend/CMakeLists.txt
@@ -56,6 +56,7 @@
   clangBasic
   clangDriver
   clangEdit
+  clangIndex
   clangLex
   clangParse
   clangSema
diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp
index a4b72e0..6d22a49 100644
--- a/lib/Frontend/CompilerInstance.cpp
+++ b/lib/Frontend/CompilerInstance.cpp
@@ -28,6 +28,8 @@
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Frontend/Utils.h"
 #include "clang/Frontend/VerifyDiagnosticConsumer.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Index/IndexingAction.h"
 #include "clang/Lex/HeaderSearch.h"
 #include "clang/Lex/PTHManager.h"
 #include "clang/Lex/Preprocessor.h"
@@ -1169,20 +1171,29 @@
     SourceMgr.overrideFileContents(ModuleMapFile, std::move(ModuleMapBuffer));
   }
 
+  std::unique_ptr<FrontendAction> CreateModuleAction;
+
   // Construct a module-generating action. Passing through the module map is
   // safe because the FileManager is shared between the compiler instances.
-  GenerateModuleFromModuleMapAction CreateModuleAction(
-      ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem);
+  CreateModuleAction.reset(new GenerateModuleFromModuleMapAction(
+      ModMap.getModuleMapFileForUniquing(Module), Module->IsSystem));
 
   ImportingInstance.getDiagnostics().Report(ImportLoc,
                                             diag::remark_module_build)
     << Module->Name << ModuleFileName;
 
+  if (!FrontendOpts.IndexStorePath.empty()) {
+#if defined(__APPLE__)
+    CreateModuleAction = index::createIndexDataRecordingAction(FrontendOpts,
+                                                 std::move(CreateModuleAction));
+#endif
+  }
+
   // Execute the action to actually build the module in-place. Use a separate
   // thread so that we get a stack large enough.
   const unsigned ThreadStackSize = 8 << 20;
   llvm::CrashRecoveryContext CRC;
-  CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(CreateModuleAction); },
+  CRC.RunSafelyOnThread([&]() { Instance.ExecuteAction(*CreateModuleAction); },
                         ThreadStackSize);
 
   ImportingInstance.getDiagnostics().Report(ImportLoc,
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 5381b81..18b6867 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -1318,6 +1318,10 @@
       << "ARC migration" << "ObjC migration";
   }
 
+  Opts.IndexStorePath = Args.getLastArgValue(OPT_index_store_path);
+  Opts.IndexIgnoreSystemSymbols = Args.hasArg(OPT_index_ignore_system_symbols);
+  Opts.IndexRecordCodegenName = Args.hasArg(OPT_index_record_codegen_name);
+
   InputKind DashX = IK_None;
   if (const Arg *A = Args.getLastArg(OPT_x)) {
     DashX = llvm::StringSwitch<InputKind>(A->getValue())
diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
index 187a6e7..67af7bc 100644
--- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp
+++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp
@@ -22,6 +22,7 @@
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/FrontendPluginRegistry.h"
 #include "clang/Frontend/Utils.h"
+#include "clang/Index/IndexingAction.h"
 #include "clang/Rewrite/Frontend/FrontendActions.h"
 #include "clang/StaticAnalyzer/Frontend/FrontendActions.h"
 #include "llvm/Option/OptTable.h"
@@ -162,6 +163,12 @@
   }
 #endif
 
+  if (!FEOpts.IndexStorePath.empty()) {
+#if defined(__APPLE__)
+    Act = index::createIndexDataRecordingAction(FEOpts, std::move(Act));
+#endif
+  }
+
   // If there are any AST files to merge, create a frontend action
   // adaptor to perform the merge.
   if (!FEOpts.ASTMergeFiles.empty())
diff --git a/lib/Index/BitstreamVisitor.h b/lib/Index/BitstreamVisitor.h
new file mode 100644
index 0000000..d324f1a
--- /dev/null
+++ b/lib/Index/BitstreamVisitor.h
@@ -0,0 +1,163 @@
+//===--- BitstreamVisitor.h - Helper for reading a bitstream --------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_INDEX_BITSTREAMVISITOR_H
+#define LLVM_CLANG_LIB_INDEX_BITSTREAMVISITOR_H
+
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Serialization/ASTReader.h"
+#include <string>
+
+namespace clang {
+namespace index {
+namespace store {
+
+/// Helper class that saves the current stream position and
+/// then restores it when destroyed.
+struct SavedStreamPosition {
+  explicit SavedStreamPosition(llvm::BitstreamCursor &Cursor)
+    : Cursor(Cursor), Offset(Cursor.GetCurrentBitNo()) { }
+
+  ~SavedStreamPosition() {
+    Cursor.JumpToBit(Offset);
+  }
+
+private:
+  llvm::BitstreamCursor &Cursor;
+  uint64_t Offset;
+};
+
+enum class StreamVisit {
+  Continue,
+  Skip,
+  Abort
+};
+
+template <typename ImplClass>
+class BitstreamVisitor {
+  SmallVector<unsigned, 4> BlockStack;
+
+protected:
+  llvm::BitstreamCursor &Stream;
+  Optional<llvm::BitstreamBlockInfo> BlockInfo;
+  std::string *Error;
+
+public:
+  BitstreamVisitor(llvm::BitstreamCursor &Stream)
+    : Stream(Stream) {}
+
+  StreamVisit visitBlock(unsigned ID) {
+    return StreamVisit::Continue;
+  }
+
+  bool visit(std::string &Error) {
+    this->Error = &Error;
+
+    ASTReader::RecordData Record;
+    while (1) {
+      llvm::BitstreamEntry Entry = Stream.advance(llvm::BitstreamCursor::AF_DontPopBlockAtEnd);
+
+      switch (Entry.Kind) {
+      case llvm::BitstreamEntry::Error:
+        Error = "malformed serialization";
+        return false;
+
+      case llvm::BitstreamEntry::EndBlock:
+        if (BlockStack.empty())
+          return true;
+        BlockStack.pop_back();
+        if (Stream.ReadBlockEnd()) {
+          Error = "malformed serialization";
+          return false;
+        }
+        if (Stream.AtEndOfStream())
+          return true;
+        break;
+
+      case llvm::BitstreamEntry::SubBlock: {
+        if (Entry.ID == llvm::bitc::BLOCKINFO_BLOCK_ID) {
+          BlockInfo = Stream.ReadBlockInfoBlock();
+          if (!BlockInfo) {
+            Error = "malformed BlockInfoBlock";
+            return false;
+          }
+          Stream.setBlockInfo(&*BlockInfo);
+          break;
+        }
+
+        StreamVisit Ret = static_cast<ImplClass*>(this)->visitBlock(Entry.ID);
+        switch (Ret) {
+        case StreamVisit::Continue:
+          if (Stream.EnterSubBlock(Entry.ID)) {
+            Error = "malformed block record";
+            return false;
+          }
+          readBlockAbbrevs(Stream);
+          BlockStack.push_back(Entry.ID);
+          break;
+
+        case StreamVisit::Skip: 
+          if (Stream.SkipBlock()) {
+            Error = "malformed serialization";
+            return false;
+          }
+          if (Stream.AtEndOfStream())
+            return true;
+          break;
+
+        case StreamVisit::Abort:
+          return false;
+        }
+        break;
+      }
+
+      case llvm::BitstreamEntry::Record: {
+        Record.clear();
+        StringRef Blob;
+        unsigned RecID = Stream.readRecord(Entry.ID, Record, &Blob);
+        unsigned BlockID = BlockStack.empty() ? 0 : BlockStack.back();
+        StreamVisit Ret = static_cast<ImplClass*>(this)->visitRecord(BlockID, RecID, Record, Blob);
+        switch (Ret) {
+        case StreamVisit::Continue:
+          break;
+
+        case StreamVisit::Skip: 
+          Stream.skipRecord(Entry.ID);
+          break;
+
+        case StreamVisit::Abort:
+          return false;
+        }
+        break;
+      }
+      }
+    }
+  }
+
+  static void readBlockAbbrevs(llvm::BitstreamCursor &Cursor) {
+    while (true) {
+      uint64_t Offset = Cursor.GetCurrentBitNo();
+      unsigned Code = Cursor.ReadCode();
+
+      // We expect all abbrevs to be at the start of the block.
+      if (Code != llvm::bitc::DEFINE_ABBREV) {
+        Cursor.JumpToBit(Offset);
+        return;
+      }
+      Cursor.ReadAbbrevRecord();
+    }
+  }
+};
+
+} // end namespace store
+} // end namespace index
+} // end namespace clang
+
+#endif
diff --git a/lib/Index/CMakeLists.txt b/lib/Index/CMakeLists.txt
index c9fbfaf..b5dea4c 100644
--- a/lib/Index/CMakeLists.txt
+++ b/lib/Index/CMakeLists.txt
@@ -4,14 +4,23 @@
   )
 
 add_clang_library(clangIndex
+  ClangIndexRecordWriter.cpp
   CodegenNameGenerator.cpp
   CommentToXML.cpp
+  FileIndexRecord.cpp
   IndexBody.cpp
+  IndexDataStore.cpp
+  IndexDataStoreUtils.cpp
   IndexDecl.cpp
   IndexingAction.cpp
   IndexingContext.cpp
+  IndexRecordHasher.cpp
+  IndexRecordReader.cpp
+  IndexRecordWriter.cpp
   IndexSymbol.cpp
   IndexTypeSourceInfo.cpp
+  IndexUnitReader.cpp
+  IndexUnitWriter.cpp
   USRGeneration.cpp
 
   ADDITIONAL_HEADERS
diff --git a/lib/Index/ClangIndexRecordWriter.cpp b/lib/Index/ClangIndexRecordWriter.cpp
new file mode 100644
index 0000000..612ef1b
--- /dev/null
+++ b/lib/Index/ClangIndexRecordWriter.cpp
@@ -0,0 +1,128 @@
+//===--- ClangIndexRecordWriter.cpp - Index record serialization ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangIndexRecordWriter.h"
+#include "FileIndexRecord.h"
+#include "clang/Index/IndexSymbol.h"
+#include "clang/Index/IndexRecordReader.h"
+#include "clang/Index/USRGeneration.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
+
+using namespace clang;
+using namespace clang::index;
+
+StringRef ClangIndexRecordWriter::getUSR(const Decl *D) {
+  assert(D->isCanonicalDecl());
+  auto Insert = USRByDecl.insert(std::make_pair(D, StringRef()));
+  if (Insert.second) {
+    Insert.first->second = getUSRNonCached(D);
+  }
+  return Insert.first->second;
+}
+
+StringRef ClangIndexRecordWriter::getUSRNonCached(const Decl *D) {
+  SmallString<256> Buf;
+  bool Ignore = generateUSRForDecl(D, Buf);
+  if (Ignore)
+    return StringRef();
+  StringRef USR = Buf.str();
+  char *Ptr = Allocator.Allocate<char>(USR.size());
+  std::copy(USR.begin(), USR.end(), Ptr);
+  return StringRef(Ptr, USR.size());
+}
+
+ClangIndexRecordWriter::ClangIndexRecordWriter(ASTContext &Ctx,
+                                               RecordingOptions Opts)
+    : Impl(Opts.DataDirPath), Ctx(Ctx), RecordOpts(std::move(Opts)),
+      Hasher(Ctx) {
+  if (Opts.RecordSymbolCodeGenName)
+    CGNameGen.reset(new CodegenNameGenerator(Ctx));
+}
+
+ClangIndexRecordWriter::~ClangIndexRecordWriter() {}
+
+bool ClangIndexRecordWriter::writeRecord(StringRef Filename,
+                                         const FileIndexRecord &IdxRecord,
+                                         std::string &Error,
+                                         std::string *OutRecordFile) {
+
+  auto RecordHash = Hasher.hashRecord(IdxRecord);
+
+  switch (Impl.beginRecord(Filename, RecordHash, Error, OutRecordFile)) {
+  case IndexRecordWriter::Result::Success:
+    break; // Continue writing.
+  case IndexRecordWriter::Result::Failure:
+    return true;
+  case IndexRecordWriter::Result::AlreadyExists:
+    return false;
+  }
+
+  ASTContext &Ctx = getASTContext();
+  SourceManager &SM = Ctx.getSourceManager();
+  FileID FID = IdxRecord.getFileID();
+  auto getLineCol = [&](unsigned Offset) -> std::pair<unsigned, unsigned> {
+    unsigned LineNo = SM.getLineNumber(FID, Offset);
+    unsigned ColNo = SM.getColumnNumber(FID, Offset);
+    return std::make_pair(LineNo, ColNo);
+  };
+
+  for (auto &Occur : IdxRecord.getDeclOccurrences()) {
+    unsigned Line, Col;
+    std::tie(Line, Col) = getLineCol(Occur.Offset);
+    SmallVector<writer::SymbolRelation, 3> Related;
+    Related.reserve(Occur.Relations.size());
+    for (auto &Rel : Occur.Relations)
+      Related.push_back(writer::SymbolRelation{Rel.RelatedSymbol, Rel.Roles});
+
+    Impl.addOccurrence(Occur.Dcl, Occur.Roles, Line, Col, Related);
+  }
+
+  PrintingPolicy Policy(Ctx.getLangOpts());
+  Policy.SuppressTemplateArgsInCXXConstructors = true;
+
+  auto Result = Impl.endRecord(Error,
+      [&](writer::OpaqueDecl OD, SmallVectorImpl<char> &Scratch) {
+    const Decl *D = static_cast<const Decl *>(OD);
+    auto Info = getSymbolInfo(D);
+
+    writer::Symbol Sym;
+    Sym.SymInfo = Info;
+
+    auto *ND = dyn_cast<NamedDecl>(D);
+    if (ND) {
+      llvm::raw_svector_ostream OS(Scratch);
+      DeclarationName DeclName = ND->getDeclName();
+      if (!DeclName.isEmpty())
+        DeclName.print(OS, Policy);
+    }
+    unsigned NameLen = Scratch.size();
+    Sym.Name = StringRef(Scratch.data(), NameLen);
+
+    Sym.USR = getUSR(D);
+    assert(!Sym.USR.empty() && "Recorded decl without USR!");
+
+    if (CGNameGen && ND) {
+      llvm::raw_svector_ostream OS(Scratch);
+      CGNameGen->writeName(ND, OS);
+    }
+    unsigned CGNameLen = Scratch.size() - NameLen;
+    Sym.CodeGenName = StringRef(Scratch.data() + NameLen, CGNameLen);
+    return Sym;
+  });
+
+  switch (Result) {
+  case IndexRecordWriter::Result::Success:
+  case IndexRecordWriter::Result::AlreadyExists:
+    return false;
+  case IndexRecordWriter::Result::Failure:
+    return true;
+  }
+}
diff --git a/lib/Index/ClangIndexRecordWriter.h b/lib/Index/ClangIndexRecordWriter.h
new file mode 100644
index 0000000..b68f987
--- /dev/null
+++ b/lib/Index/ClangIndexRecordWriter.h
@@ -0,0 +1,55 @@
+//===--- ClangIndexRecordWriter.h - Index record serialization ------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_INDEX_CLANGINDEXRECORDWRITER_H
+#define LLVM_CLANG_LIB_INDEX_CLANGINDEXRECORDWRITER_H
+
+#include "IndexRecordHasher.h"
+#include "clang/Index/IndexRecordWriter.h"
+#include "clang/Index/IndexingAction.h"
+#include "clang/Index/CodegenNameGenerator.h"
+#include "llvm/ADT/SmallString.h"
+
+namespace clang {
+  class ASTContext;
+  class Decl;
+
+namespace index {
+  class FileIndexRecord;
+
+class ClangIndexRecordWriter {
+  IndexRecordWriter Impl;
+
+  ASTContext &Ctx;
+  RecordingOptions RecordOpts;
+
+  std::unique_ptr<CodegenNameGenerator> CGNameGen;
+  llvm::BumpPtrAllocator Allocator;
+  llvm::DenseMap<const Decl *, StringRef> USRByDecl;
+  IndexRecordHasher Hasher;
+
+public:
+  ClangIndexRecordWriter(ASTContext &Ctx, RecordingOptions Opts);
+  ~ClangIndexRecordWriter();
+
+  ASTContext &getASTContext() { return Ctx; }
+  CodegenNameGenerator *getCGNameGen() { return CGNameGen.get(); }
+
+  bool writeRecord(StringRef Filename, const FileIndexRecord &Record,
+                   std::string &Error, std::string *RecordFile = nullptr);
+  StringRef getUSR(const Decl *D);
+
+private:
+  StringRef getUSRNonCached(const Decl *D);
+};
+
+} // end namespace index
+} // end namespace clang
+
+#endif
diff --git a/lib/Index/FileIndexRecord.cpp b/lib/Index/FileIndexRecord.cpp
new file mode 100644
index 0000000..98d66b6
--- /dev/null
+++ b/lib/Index/FileIndexRecord.cpp
@@ -0,0 +1,59 @@
+//===--- FileIndexRecord.cpp - Index data per file ------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "FileIndexRecord.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Path.h"
+
+using namespace clang;
+using namespace clang::index;
+
+void FileIndexRecord::addDeclOccurence(SymbolRoleSet Roles,
+                                       unsigned Offset,
+                                       const Decl *D,
+                                       ArrayRef<SymbolRelation> Relations) {
+  assert(D->isCanonicalDecl());
+
+  auto IsNextOccurence = [&]()->bool {
+    if (Decls.empty())
+      return true;
+    auto &Last = Decls.back();
+    return Last.Offset < Offset;
+  };
+
+  if (IsNextOccurence()) {
+    Decls.emplace_back(Roles, Offset, D, Relations);
+    return;
+  }
+
+  DeclOccurrence NewInfo(Roles, Offset, D, Relations);
+  auto It = std::upper_bound(Decls.begin(), Decls.end(), NewInfo);
+  Decls.insert(It, std::move(NewInfo));
+}
+
+void FileIndexRecord::print(llvm::raw_ostream &OS) {
+  OS << "DECLS BEGIN ---\n";
+  for (auto &DclInfo : Decls) {
+    auto D = DclInfo.Dcl;
+    SourceManager &SM = D->getASTContext().getSourceManager();
+    SourceLocation Loc = SM.getFileLoc(D->getLocation());
+    PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+    OS << llvm::sys::path::filename(PLoc.getFilename()) << ':' << PLoc.getLine()
+       << ':' << PLoc.getColumn();
+
+    if (auto ND = dyn_cast<NamedDecl>(D)) {
+      OS << ' ' << ND->getNameAsString();
+    }
+
+    OS << '\n';
+  }
+  OS << "DECLS END ---\n";
+}
diff --git a/lib/Index/FileIndexRecord.h b/lib/Index/FileIndexRecord.h
new file mode 100644
index 0000000..a663173
--- /dev/null
+++ b/lib/Index/FileIndexRecord.h
@@ -0,0 +1,69 @@
+//===--- FileIndexRecord.h - Index data per file --------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_INDEX_FILEINDEXRECORD_H
+#define LLVM_CLANG_LIB_INDEX_FILEINDEXRECORD_H
+
+#include "clang/Index/IndexSymbol.h"
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallVector.h"
+#include <vector>
+
+namespace clang {
+  class IdentifierInfo;
+
+namespace index {
+
+class FileIndexRecord {
+public:
+  struct DeclOccurrence {
+    SymbolRoleSet Roles;
+    unsigned Offset;
+    const Decl *Dcl;
+    SmallVector<SymbolRelation, 3> Relations;
+
+    DeclOccurrence(SymbolRoleSet R,
+                   unsigned Offset,
+                   const Decl *D,
+                   ArrayRef<SymbolRelation> Relations)
+      : Roles(R),
+        Offset(Offset),
+        Dcl(D),
+        Relations(Relations.begin(), Relations.end()) {}
+
+    friend bool operator <(const DeclOccurrence &LHS, const DeclOccurrence &RHS) {
+      return LHS.Offset < RHS.Offset;
+    }
+  };
+
+private:
+  FileID FID;
+  bool IsSystem;
+  std::vector<DeclOccurrence> Decls;
+
+public:
+  FileIndexRecord(FileID FID, bool isSystem) : FID(FID), IsSystem(isSystem) {}
+
+  ArrayRef<DeclOccurrence> getDeclOccurrences() const { return Decls; }
+
+  FileID getFileID() const { return FID; }
+  bool isSystem() const { return IsSystem; }
+
+  void addDeclOccurence(SymbolRoleSet Roles,
+                        unsigned Offset,
+                        const Decl *D,
+                        ArrayRef<SymbolRelation> Relations);
+  void print(llvm::raw_ostream &OS);
+};
+
+} // end namespace index
+} // end namespace clang
+
+#endif
diff --git a/lib/Index/IndexDataStore.cpp b/lib/Index/IndexDataStore.cpp
new file mode 100644
index 0000000..4140392
--- /dev/null
+++ b/lib/Index/IndexDataStore.cpp
@@ -0,0 +1,259 @@
+//===--- IndexDataStore.cpp - Index data store info -----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/IndexDataStore.h"
+#include "IndexDataStoreUtils.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Mutex.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::index;
+using namespace clang::index::store;
+using namespace llvm;
+
+static void appendSubDir(StringRef subdir, SmallVectorImpl<char> &StorePathBuf) {
+  SmallString<10> VersionPath;
+  raw_svector_ostream(VersionPath) << 'v' << STORE_FORMAT_VERSION;
+
+  sys::path::append(StorePathBuf, VersionPath);
+  sys::path::append(StorePathBuf, subdir);
+}
+
+void store::appendInteriorUnitPath(StringRef UnitName,
+                                   SmallVectorImpl<char> &PathBuf) {
+  sys::path::append(PathBuf, UnitName);
+}
+
+void store::appendUnitSubDir(SmallVectorImpl<char> &StorePathBuf) {
+  return appendSubDir("units", StorePathBuf);
+}
+
+void store::appendRecordSubDir(SmallVectorImpl<char> &StorePathBuf) {
+  return appendSubDir("records", StorePathBuf);
+}
+
+void store::appendInteriorRecordPath(StringRef RecordName,
+                                     SmallVectorImpl<char> &PathBuf) {
+  // To avoid putting a huge number of files into the records directory, create
+  // subdirectories based on the last 2 characters from the hash.
+  StringRef hash2chars = RecordName.substr(RecordName.size()-2);
+  sys::path::append(PathBuf, hash2chars);
+  sys::path::append(PathBuf, RecordName);
+}
+
+//===----------------------------------------------------------------------===//
+// IndexDataStore
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class UnitEventHandlerData {
+  mutable sys::Mutex Mtx;
+  IndexDataStore::UnitEventHandler Handler;
+
+public:
+  void setHandler(IndexDataStore::UnitEventHandler handler) {
+    sys::ScopedLock L(Mtx);
+    Handler = std::move(handler);
+  }
+  IndexDataStore::UnitEventHandler getHandler() const {
+    sys::ScopedLock L(Mtx);
+    return Handler;
+  }
+};
+
+class IndexDataStoreImpl {
+  std::string FilePath;
+  std::shared_ptr<UnitEventHandlerData> TheUnitEventHandlerData;
+  std::unique_ptr<AbstractDirectoryWatcher> DirWatcher;
+
+public:
+  explicit IndexDataStoreImpl(StringRef indexStorePath)
+    : FilePath(indexStorePath) {
+    TheUnitEventHandlerData = std::make_shared<UnitEventHandlerData>();
+  }
+
+  StringRef getFilePath() const { return FilePath; }
+  bool foreachUnitName(bool sorted,
+                       llvm::function_ref<bool(StringRef unitName)> receiver);
+  void setUnitEventHandler(IndexDataStore::UnitEventHandler Handler);
+  bool startEventListening(llvm::function_ref<AbstractDirectoryWatcher::CreateFnTy> createFn,
+                           bool waitInitialSync, std::string &Error);
+  void stopEventListening();
+  void discardUnit(StringRef UnitName);
+  void discardRecord(StringRef RecordName);
+  void purgeStaleData();
+};
+
+} // anonymous namespace
+
+bool IndexDataStoreImpl::foreachUnitName(bool sorted,
+                        llvm::function_ref<bool(StringRef unitName)> receiver) {
+  SmallString<128> UnitPath;
+  UnitPath = FilePath;
+  appendUnitSubDir(UnitPath);
+
+  std::vector<std::string> filenames;
+
+  std::error_code EC;
+  for (auto It = sys::fs::directory_iterator(UnitPath, EC),
+           End = sys::fs::directory_iterator();
+       !EC && It != End; It.increment(EC)) {
+    StringRef unitName = sys::path::filename(It->path());
+    if (!sorted) {
+      if (!receiver(unitName))
+        return false;
+    } else {
+      filenames.push_back(unitName);
+    }
+  }
+
+  if (sorted) {
+    llvm::array_pod_sort(filenames.begin(), filenames.end());
+    for (auto &fname : filenames)
+      if (!receiver(fname))
+        return false;
+  }
+  return true;
+}
+
+void IndexDataStoreImpl::setUnitEventHandler(IndexDataStore::UnitEventHandler handler) {
+  TheUnitEventHandlerData->setHandler(std::move(handler));
+}
+
+bool IndexDataStoreImpl::startEventListening(llvm::function_ref<AbstractDirectoryWatcher::CreateFnTy> createFn,
+                                             bool waitInitialSync, std::string &Error) {
+  if (DirWatcher) {
+    Error = "event listener already active";
+    return true;
+  }
+
+  SmallString<128> UnitPath;
+  UnitPath = FilePath;
+  appendUnitSubDir(UnitPath);
+
+  auto localUnitEventHandlerData = TheUnitEventHandlerData;
+  auto OnUnitsChange = [localUnitEventHandlerData](ArrayRef<AbstractDirectoryWatcher::Event> Events, bool isInitial) {
+    SmallVector<IndexDataStore::UnitEvent, 16> UnitEvents;
+    UnitEvents.reserve(Events.size());
+    for (const AbstractDirectoryWatcher::Event &evt : Events) {
+      IndexDataStore::UnitEventKind K;
+      StringRef UnitName = sys::path::filename(evt.Filename);
+      switch (evt.Kind) {
+      case AbstractDirectoryWatcher::EventKind::Added:
+        K = IndexDataStore::UnitEventKind::Added; break;
+      case AbstractDirectoryWatcher::EventKind::Removed:
+        K = IndexDataStore::UnitEventKind::Removed; break;
+      case AbstractDirectoryWatcher::EventKind::Modified:
+        K = IndexDataStore::UnitEventKind::Modified; break;
+      case AbstractDirectoryWatcher::EventKind::DirectoryDeleted:
+        K = IndexDataStore::UnitEventKind::DirectoryDeleted;
+        UnitName = StringRef();
+        break;
+      }
+      UnitEvents.push_back(IndexDataStore::UnitEvent{K, UnitName, evt.ModTime});
+    }
+
+    if (auto handler = localUnitEventHandlerData->getHandler()) {
+      IndexDataStore::UnitEventNotification EventNote{isInitial, UnitEvents};
+      handler(EventNote);
+    }
+  };
+
+  DirWatcher = createFn(UnitPath.str(), OnUnitsChange, waitInitialSync, Error);
+  if (!DirWatcher)
+    return true;
+
+  return false;
+}
+
+void IndexDataStoreImpl::stopEventListening() {
+  DirWatcher.reset();
+}
+
+void IndexDataStoreImpl::discardUnit(StringRef UnitName) {
+  SmallString<128> UnitPath;
+  UnitPath = FilePath;
+  appendUnitSubDir(UnitPath);
+  appendInteriorUnitPath(UnitName, UnitPath);
+  sys::fs::remove(UnitPath);
+}
+
+void IndexDataStoreImpl::discardRecord(StringRef RecordName) {
+  SmallString<128> RecordPath;
+  RecordPath = FilePath;
+  appendRecordSubDir(RecordPath);
+  appendInteriorRecordPath(RecordName, RecordPath);
+  sys::fs::remove(RecordPath);
+}
+
+void IndexDataStoreImpl::purgeStaleData() {
+  // FIXME: Implement.
+}
+
+
+std::unique_ptr<IndexDataStore>
+IndexDataStore::create(StringRef IndexStorePath, std::string &Error) {
+  if (!sys::fs::exists(IndexStorePath)) {
+    raw_string_ostream OS(Error);
+    OS << "index store path does not exist: " << IndexStorePath;
+    return nullptr;
+  }
+
+  return std::unique_ptr<IndexDataStore>(
+    new IndexDataStore(new IndexDataStoreImpl(IndexStorePath)));
+}
+
+#define IMPL static_cast<IndexDataStoreImpl*>(Impl)
+
+IndexDataStore::~IndexDataStore() {
+  delete IMPL;
+}
+
+StringRef IndexDataStore::getFilePath() const {
+  return IMPL->getFilePath();
+}
+
+bool IndexDataStore::foreachUnitName(bool sorted,
+                     llvm::function_ref<bool(StringRef unitName)> receiver) {
+  return IMPL->foreachUnitName(sorted, std::move(receiver));
+}
+
+unsigned IndexDataStore::getFormatVersion() {
+  return STORE_FORMAT_VERSION;
+}
+
+void IndexDataStore::setUnitEventHandler(UnitEventHandler Handler) {
+  return IMPL->setUnitEventHandler(std::move(Handler));
+}
+
+bool IndexDataStore::startEventListening(llvm::function_ref<AbstractDirectoryWatcher::CreateFnTy> createFn,
+                                         bool waitInitialSync, std::string &Error) {
+  return IMPL->startEventListening(std::move(createFn), waitInitialSync, Error);
+}
+
+void IndexDataStore::stopEventListening() {
+  return IMPL->stopEventListening();
+}
+
+void IndexDataStore::discardUnit(StringRef UnitName) {
+  IMPL->discardUnit(UnitName);
+}
+
+void IndexDataStore::discardRecord(StringRef RecordName) {
+  IMPL->discardRecord(RecordName);
+}
+
+void IndexDataStore::purgeStaleData() {
+  IMPL->purgeStaleData();
+}
diff --git a/lib/Index/IndexDataStoreUtils.cpp b/lib/Index/IndexDataStoreUtils.cpp
new file mode 100644
index 0000000..0d9e754
--- /dev/null
+++ b/lib/Index/IndexDataStoreUtils.cpp
@@ -0,0 +1,398 @@
+//===--- IndexDataStoreUtils.cpp - Functions/constants for the data store -===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/IndexDataStoreSymbolUtils.h"
+#include "IndexDataStoreUtils.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+
+using namespace clang;
+using namespace clang::index;
+using namespace clang::index::store;
+using namespace llvm;
+
+void store::emitBlockID(unsigned ID, const char *Name,
+                        BitstreamWriter &Stream, RecordDataImpl &Record) {
+  Record.clear();
+  Record.push_back(ID);
+  Stream.EmitRecord(bitc::BLOCKINFO_CODE_SETBID, Record);
+
+  // Emit the block name if present.
+  if (!Name || Name[0] == 0)
+    return;
+  Record.clear();
+  while (*Name)
+    Record.push_back(*Name++);
+  Stream.EmitRecord(bitc::BLOCKINFO_CODE_BLOCKNAME, Record);
+}
+
+void store::emitRecordID(unsigned ID, const char *Name,
+                         BitstreamWriter &Stream,
+                         RecordDataImpl &Record) {
+  Record.clear();
+  Record.push_back(ID);
+  while (*Name)
+    Record.push_back(*Name++);
+  Stream.EmitRecord(bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+/// Map an indexstore_symbol_kind_t to a SymbolKind, handling unknown values.
+SymbolKind index::getSymbolKind(indexstore_symbol_kind_t K) {
+  switch ((uint64_t)K) {
+  default:
+  case INDEXSTORE_SYMBOL_KIND_UNKNOWN:
+    return SymbolKind::Unknown;
+  case INDEXSTORE_SYMBOL_KIND_MODULE:
+    return SymbolKind::Module;
+  case INDEXSTORE_SYMBOL_KIND_NAMESPACE:
+    return SymbolKind::Namespace;
+  case INDEXSTORE_SYMBOL_KIND_NAMESPACEALIAS:
+    return SymbolKind::NamespaceAlias;
+  case INDEXSTORE_SYMBOL_KIND_MACRO:
+    return SymbolKind::Macro;
+  case INDEXSTORE_SYMBOL_KIND_ENUM:
+    return SymbolKind::Enum;
+  case INDEXSTORE_SYMBOL_KIND_STRUCT:
+    return SymbolKind::Struct;
+  case INDEXSTORE_SYMBOL_KIND_CLASS:
+    return SymbolKind::Class;
+  case INDEXSTORE_SYMBOL_KIND_PROTOCOL:
+    return SymbolKind::Protocol;
+  case INDEXSTORE_SYMBOL_KIND_EXTENSION:
+    return SymbolKind::Extension;
+  case INDEXSTORE_SYMBOL_KIND_UNION:
+    return SymbolKind::Union;
+  case INDEXSTORE_SYMBOL_KIND_TYPEALIAS:
+    return SymbolKind::TypeAlias;
+  case INDEXSTORE_SYMBOL_KIND_FUNCTION:
+    return SymbolKind::Function;
+  case INDEXSTORE_SYMBOL_KIND_VARIABLE:
+    return SymbolKind::Variable;
+  case INDEXSTORE_SYMBOL_KIND_FIELD:
+    return SymbolKind::Field;
+  case INDEXSTORE_SYMBOL_KIND_ENUMCONSTANT:
+    return SymbolKind::EnumConstant;
+  case INDEXSTORE_SYMBOL_KIND_INSTANCEMETHOD:
+    return SymbolKind::InstanceMethod;
+  case INDEXSTORE_SYMBOL_KIND_CLASSMETHOD:
+    return SymbolKind::ClassMethod;
+  case INDEXSTORE_SYMBOL_KIND_STATICMETHOD:
+    return SymbolKind::StaticMethod;
+  case INDEXSTORE_SYMBOL_KIND_INSTANCEPROPERTY:
+    return SymbolKind::InstanceProperty;
+  case INDEXSTORE_SYMBOL_KIND_CLASSPROPERTY:
+    return SymbolKind::ClassProperty;
+  case INDEXSTORE_SYMBOL_KIND_STATICPROPERTY:
+    return SymbolKind::StaticProperty;
+  case INDEXSTORE_SYMBOL_KIND_CONSTRUCTOR:
+    return SymbolKind::Constructor;
+  case INDEXSTORE_SYMBOL_KIND_DESTRUCTOR:
+    return SymbolKind::Destructor;
+  case INDEXSTORE_SYMBOL_KIND_CONVERSIONFUNCTION:
+    return SymbolKind::ConversionFunction;
+  case INDEXSTORE_SYMBOL_KIND_PARAMETER:
+    return SymbolKind::Parameter;
+  case INDEXSTORE_SYMBOL_KIND_COMMENTTAG:
+    return SymbolKind::CommentTag;
+  }
+}
+
+SymbolSubKind index::getSymbolSubKind(indexstore_symbol_subkind_t K) {
+  switch ((uint64_t)K) {
+  default:
+  case INDEXSTORE_SYMBOL_SUBKIND_NONE:
+    return SymbolSubKind::None;
+  case INDEXSTORE_SYMBOL_SUBKIND_CXXCOPYCONSTRUCTOR:
+    return SymbolSubKind::CXXCopyConstructor;
+  case INDEXSTORE_SYMBOL_SUBKIND_CXXMOVECONSTRUCTOR:
+    return SymbolSubKind::CXXMoveConstructor;
+  case INDEXSTORE_SYMBOL_SUBKIND_ACCESSORGETTER:
+      return SymbolSubKind::AccessorGetter;
+  case INDEXSTORE_SYMBOL_SUBKIND_ACCESSORSETTER:
+      return SymbolSubKind::AccessorSetter;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORWILLSET:
+    return SymbolSubKind::SwiftAccessorWillSet;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORDIDSET:
+    return SymbolSubKind::SwiftAccessorDidSet;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORADDRESSOR:
+    return SymbolSubKind::SwiftAccessorAddressor;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMUTABLEADDRESSOR:
+    return SymbolSubKind::SwiftAccessorMutableAddressor;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFSTRUCT:
+    return SymbolSubKind::SwiftExtensionOfStruct;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFCLASS:
+    return SymbolSubKind::SwiftExtensionOfClass;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFENUM:
+    return SymbolSubKind::SwiftExtensionOfEnum;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFPROTOCOL:
+    return SymbolSubKind::SwiftExtensionOfProtocol;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTPREFIXOPERATOR:
+    return SymbolSubKind::SwiftPrefixOperator;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTPOSTFIXOPERATOR:
+    return SymbolSubKind::SwiftPostfixOperator;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTINFIXOPERATOR:
+    return SymbolSubKind::SwiftInfixOperator;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTSUBSCRIPT:
+    return SymbolSubKind::SwiftSubscript;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTASSOCIATEDTYPE:
+    return SymbolSubKind::SwiftAssociatedType;
+  case INDEXSTORE_SYMBOL_SUBKIND_SWIFTGENERICTYPEPARAM:
+    return SymbolSubKind::SwiftGenericTypeParam;
+  }
+}
+
+/// Map an indexstore_symbol_language_t to a SymbolLanguage, handling unknown
+/// values.
+SymbolLanguage index::getSymbolLanguage(indexstore_symbol_language_t L) {
+  switch ((uint64_t)L) {
+  default: // FIXME: add an unknown language?
+  case INDEXSTORE_SYMBOL_LANG_C:
+    return SymbolLanguage::C;
+  case INDEXSTORE_SYMBOL_LANG_OBJC:
+    return SymbolLanguage::ObjC;
+  case INDEXSTORE_SYMBOL_LANG_CXX:
+    return SymbolLanguage::CXX;
+  case INDEXSTORE_SYMBOL_LANG_SWIFT:
+    return SymbolLanguage::Swift;
+  }
+}
+
+/// Map an indexstore representation to a SymbolPropertySet, handling
+/// unknown values.
+SymbolPropertySet index::getSymbolProperties(uint64_t Props) {
+  // FIXME: currently these enums must be kept in sync.
+  return (uint64_t)Props;
+}
+
+/// Map an indexstore representation to a SymbolRoleSet, handling unknown
+/// values.
+SymbolRoleSet index::getSymbolRoles(uint64_t Roles) {
+  // FIXME: currently these enums must be kept in sync.
+  return (uint64_t)Roles;
+}
+
+/// Map a SymbolLanguage to a indexstore_symbol_language_t.
+indexstore_symbol_kind_t index::getIndexStoreKind(SymbolKind K) {
+  switch (K) {
+  case SymbolKind::Unknown:
+    return INDEXSTORE_SYMBOL_KIND_UNKNOWN;
+  case SymbolKind::Module:
+    return INDEXSTORE_SYMBOL_KIND_MODULE;
+  case SymbolKind::Namespace:
+    return INDEXSTORE_SYMBOL_KIND_NAMESPACE;
+  case SymbolKind::NamespaceAlias:
+    return INDEXSTORE_SYMBOL_KIND_NAMESPACEALIAS;
+  case SymbolKind::Macro:
+    return INDEXSTORE_SYMBOL_KIND_MACRO;
+  case SymbolKind::Enum:
+    return INDEXSTORE_SYMBOL_KIND_ENUM;
+  case SymbolKind::Struct:
+    return INDEXSTORE_SYMBOL_KIND_STRUCT;
+  case SymbolKind::Class:
+    return INDEXSTORE_SYMBOL_KIND_CLASS;
+  case SymbolKind::Protocol:
+    return INDEXSTORE_SYMBOL_KIND_PROTOCOL;
+  case SymbolKind::Extension:
+    return INDEXSTORE_SYMBOL_KIND_EXTENSION;
+  case SymbolKind::Union:
+    return INDEXSTORE_SYMBOL_KIND_UNION;
+  case SymbolKind::TypeAlias:
+    return INDEXSTORE_SYMBOL_KIND_TYPEALIAS;
+  case SymbolKind::Function:
+    return INDEXSTORE_SYMBOL_KIND_FUNCTION;
+  case SymbolKind::Variable:
+    return INDEXSTORE_SYMBOL_KIND_VARIABLE;
+  case SymbolKind::Field:
+    return INDEXSTORE_SYMBOL_KIND_FIELD;
+  case SymbolKind::EnumConstant:
+    return INDEXSTORE_SYMBOL_KIND_ENUMCONSTANT;
+  case SymbolKind::InstanceMethod:
+    return INDEXSTORE_SYMBOL_KIND_INSTANCEMETHOD;
+  case SymbolKind::ClassMethod:
+    return INDEXSTORE_SYMBOL_KIND_CLASSMETHOD;
+  case SymbolKind::StaticMethod:
+    return INDEXSTORE_SYMBOL_KIND_STATICMETHOD;
+  case SymbolKind::InstanceProperty:
+    return INDEXSTORE_SYMBOL_KIND_INSTANCEPROPERTY;
+  case SymbolKind::ClassProperty:
+    return INDEXSTORE_SYMBOL_KIND_CLASSPROPERTY;
+  case SymbolKind::StaticProperty:
+    return INDEXSTORE_SYMBOL_KIND_STATICPROPERTY;
+  case SymbolKind::Constructor:
+    return INDEXSTORE_SYMBOL_KIND_CONSTRUCTOR;
+  case SymbolKind::Destructor:
+    return INDEXSTORE_SYMBOL_KIND_DESTRUCTOR;
+  case SymbolKind::ConversionFunction:
+    return INDEXSTORE_SYMBOL_KIND_CONVERSIONFUNCTION;
+  case SymbolKind::Parameter:
+    return INDEXSTORE_SYMBOL_KIND_PARAMETER;
+  case SymbolKind::CommentTag:
+    return INDEXSTORE_SYMBOL_KIND_COMMENTTAG;
+  }
+  llvm_unreachable("unexpected symbol kind");
+}
+
+indexstore_symbol_subkind_t index::getIndexStoreSubKind(SymbolSubKind K) {
+  switch (K) {
+  case SymbolSubKind::None:
+    return INDEXSTORE_SYMBOL_SUBKIND_NONE;
+  case SymbolSubKind::CXXCopyConstructor:
+    return INDEXSTORE_SYMBOL_SUBKIND_CXXCOPYCONSTRUCTOR;
+  case SymbolSubKind::CXXMoveConstructor:
+    return INDEXSTORE_SYMBOL_SUBKIND_CXXMOVECONSTRUCTOR;
+  case SymbolSubKind::AccessorGetter:
+    return INDEXSTORE_SYMBOL_SUBKIND_ACCESSORGETTER;
+  case SymbolSubKind::AccessorSetter:
+    return INDEXSTORE_SYMBOL_SUBKIND_ACCESSORSETTER;
+  case SymbolSubKind::SwiftAccessorWillSet:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORWILLSET;
+  case SymbolSubKind::SwiftAccessorDidSet:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORDIDSET;
+  case SymbolSubKind::SwiftAccessorAddressor:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORADDRESSOR;
+  case SymbolSubKind::SwiftAccessorMutableAddressor:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMUTABLEADDRESSOR;
+  case SymbolSubKind::SwiftExtensionOfStruct:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFSTRUCT;
+  case SymbolSubKind::SwiftExtensionOfClass:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFCLASS;
+  case SymbolSubKind::SwiftExtensionOfEnum:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFENUM;
+  case SymbolSubKind::SwiftExtensionOfProtocol:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFPROTOCOL;
+  case SymbolSubKind::SwiftPrefixOperator:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTPREFIXOPERATOR;
+  case SymbolSubKind::SwiftPostfixOperator:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTPOSTFIXOPERATOR;
+  case SymbolSubKind::SwiftInfixOperator:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTINFIXOPERATOR;
+  case SymbolSubKind::SwiftSubscript:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTSUBSCRIPT;
+  case SymbolSubKind::SwiftAssociatedType:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTASSOCIATEDTYPE;
+  case SymbolSubKind::SwiftGenericTypeParam:
+    return INDEXSTORE_SYMBOL_SUBKIND_SWIFTGENERICTYPEPARAM;
+  }
+  llvm_unreachable("unexpected symbol subkind");
+}
+
+/// Map a SymbolLanguage to a indexstore_symbol_language_t.
+indexstore_symbol_language_t index::getIndexStoreLang(SymbolLanguage L) {
+  switch (L) {
+  case SymbolLanguage::C:
+    return INDEXSTORE_SYMBOL_LANG_C;
+  case SymbolLanguage::ObjC:
+    return INDEXSTORE_SYMBOL_LANG_OBJC;
+  case SymbolLanguage::CXX:
+    return INDEXSTORE_SYMBOL_LANG_CXX;
+  case SymbolLanguage::Swift:
+    return INDEXSTORE_SYMBOL_LANG_SWIFT;
+  }
+  llvm_unreachable("unexpected symbol language");
+}
+
+/// Map a SymbolPropertySet to its indexstore representation.
+uint64_t index::getIndexStoreProperties(SymbolPropertySet Props) {
+  uint64_t storeProp = 0;
+  applyForEachSymbolProperty(Props, [&](SymbolProperty prop) {
+    switch (prop) {
+    case SymbolProperty::Generic:
+      storeProp |= INDEXSTORE_SYMBOL_PROPERTY_GENERIC;
+      break;
+    case SymbolProperty::TemplatePartialSpecialization:
+      storeProp |= INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_PARTIAL_SPECIALIZATION;
+      break;
+    case SymbolProperty::TemplateSpecialization:
+      storeProp |= INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_SPECIALIZATION;
+      break;
+    case SymbolProperty::UnitTest:
+      storeProp |= INDEXSTORE_SYMBOL_PROPERTY_UNITTEST;
+      break;
+    case SymbolProperty::IBAnnotated:
+      storeProp |= INDEXSTORE_SYMBOL_PROPERTY_IBANNOTATED;
+      break;
+    case SymbolProperty::IBOutletCollection:
+      storeProp |= INDEXSTORE_SYMBOL_PROPERTY_IBOUTLETCOLLECTION;
+      break;
+    case SymbolProperty::GKInspectable:
+      storeProp |= INDEXSTORE_SYMBOL_PROPERTY_GKINSPECTABLE;
+      break;
+    case SymbolProperty::Local:
+      storeProp |= INDEXSTORE_SYMBOL_PROPERTY_LOCAL;
+      break;
+    }
+  });
+  return storeProp;
+}
+
+/// Map a SymbolRoleSet to its indexstore representation.
+uint64_t index::getIndexStoreRoles(SymbolRoleSet Roles) {
+  uint64_t storeRoles = 0;
+  applyForEachSymbolRole(Roles, [&](SymbolRole role) {
+    switch (role) {
+    case SymbolRole::Declaration:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_DECLARATION;
+      break;
+    case SymbolRole::Definition:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_DEFINITION;
+      break;
+    case SymbolRole::Reference:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REFERENCE;
+      break;
+    case SymbolRole::Read:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_READ;
+      break;
+    case SymbolRole::Write:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_WRITE;
+      break;
+    case SymbolRole::Call:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_CALL;
+      break;
+    case SymbolRole::Dynamic:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_DYNAMIC;
+      break;
+    case SymbolRole::AddressOf:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_ADDRESSOF;
+      break;
+    case SymbolRole::Implicit:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_IMPLICIT;
+      break;
+    case SymbolRole::RelationChildOf:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_CHILDOF;
+      break;
+    case SymbolRole::RelationBaseOf:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_BASEOF;
+      break;
+    case SymbolRole::RelationOverrideOf:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_OVERRIDEOF;
+      break;
+    case SymbolRole::RelationReceivedBy:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_RECEIVEDBY;
+      break;
+    case SymbolRole::RelationCalledBy:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_CALLEDBY;
+      break;
+    case SymbolRole::RelationExtendedBy:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_EXTENDEDBY;
+      break;
+    case SymbolRole::RelationAccessorOf:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_ACCESSOROF;
+      break;
+    case SymbolRole::RelationContainedBy:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_CONTAINEDBY;
+      break;
+    case SymbolRole::RelationIBTypeOf:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_IBTYPEOF;
+      break;
+    case SymbolRole::RelationSpecializationOf:
+      storeRoles |= INDEXSTORE_SYMBOL_ROLE_REL_SPECIALIZATIONOF;
+      break;
+    }
+  });
+  return storeRoles;
+}
diff --git a/lib/Index/IndexDataStoreUtils.h b/lib/Index/IndexDataStoreUtils.h
new file mode 100644
index 0000000..ad310e1
--- /dev/null
+++ b/lib/Index/IndexDataStoreUtils.h
@@ -0,0 +1,116 @@
+//===--- IndexDataStoreUtils.h - Functions/constants for the data store ---===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_INDEX_INDEXDATASTOREUTILS_H
+#define LLVM_CLANG_LIB_INDEX_INDEXDATASTOREUTILS_H
+
+#include "llvm/Bitcode/BitCodes.h"
+#include "clang/Basic/LLVM.h"
+
+namespace llvm {
+  class BitstreamWriter;
+}
+
+namespace clang {
+namespace index {
+namespace store {
+
+static const unsigned STORE_FORMAT_VERSION = 5;
+
+void appendUnitSubDir(SmallVectorImpl<char> &StorePathBuf);
+void appendInteriorUnitPath(StringRef UnitName,
+                            SmallVectorImpl<char> &PathBuf);
+void appendRecordSubDir(SmallVectorImpl<char> &StorePathBuf);
+void appendInteriorRecordPath(StringRef RecordName,
+                              SmallVectorImpl<char> &PathBuf);
+
+enum RecordBitRecord {
+  REC_VERSION         = 0,
+  REC_DECLINFO        = 1,
+  REC_DECLOFFSETS     = 2,
+  REC_DECLOCCURRENCE  = 3,
+};
+
+enum RecordBitBlock {
+  REC_VERSION_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+  REC_DECLS_BLOCK_ID,
+  REC_DECLOFFSETS_BLOCK_ID,
+  REC_DECLOCCURRENCES_BLOCK_ID,
+};
+
+enum UnitBitRecord {
+  UNIT_VERSION        = 0,
+  UNIT_INFO           = 1,
+  UNIT_DEPENDENCY     = 2,
+  UNIT_INCLUDE        = 3,
+  UNIT_PATH           = 4,
+  UNIT_PATH_BUFFER    = 5,
+  UNIT_MODULE         = 6,
+  UNIT_MODULE_BUFFER  = 7,
+};
+
+enum UnitBitBlock {
+  UNIT_VERSION_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+  UNIT_INFO_BLOCK_ID,
+  UNIT_DEPENDENCIES_BLOCK_ID,
+  UNIT_INCLUDES_BLOCK_ID,
+  UNIT_PATHS_BLOCK_ID,
+  UNIT_MODULES_BLOCK_ID,
+};
+
+enum UnitDependencyKind {
+  UNIT_DEPEND_KIND_FILE = 0,
+  UNIT_DEPEND_KIND_RECORD = 1,
+  UNIT_DEPEND_KIND_UNIT = 2,
+};
+static const unsigned UnitDependencyKindBitNum = 2;
+
+enum UnitFilePathPrefixKind {
+  UNIT_PATH_PREFIX_NONE = 0,
+  UNIT_PATH_PREFIX_WORKDIR = 1,
+  UNIT_PATH_PREFIX_SYSROOT = 2,
+};
+static const unsigned UnitFilePathPrefixKindBitNum = 2;
+
+typedef SmallVector<uint64_t, 64> RecordData;
+typedef SmallVectorImpl<uint64_t> RecordDataImpl;
+
+struct BitPathComponent {
+  size_t Offset = 0;
+  size_t Size = 0;
+  BitPathComponent(size_t Offset, size_t Size) : Offset(Offset), Size(Size) {}
+  BitPathComponent() = default;
+};
+
+struct DirBitPath {
+  UnitFilePathPrefixKind PrefixKind = UNIT_PATH_PREFIX_NONE;
+  BitPathComponent Dir;
+  DirBitPath(UnitFilePathPrefixKind Kind,
+             BitPathComponent Dir) : PrefixKind(Kind), Dir(Dir) {}
+  DirBitPath() = default;
+};
+
+struct FileBitPath : DirBitPath {
+  BitPathComponent Filename;
+  FileBitPath(UnitFilePathPrefixKind Kind, BitPathComponent Dir,
+              BitPathComponent Filename) : DirBitPath(Kind, Dir), Filename(Filename) {}
+  FileBitPath() = default;
+};
+
+void emitBlockID(unsigned ID, const char *Name,
+                 llvm::BitstreamWriter &Stream, RecordDataImpl &Record);
+
+void emitRecordID(unsigned ID, const char *Name,
+                  llvm::BitstreamWriter &Stream, RecordDataImpl &Record);
+
+} // end namespace store
+} // end namespace index
+} // end namespace clang
+
+#endif
diff --git a/lib/Index/IndexRecordHasher.cpp b/lib/Index/IndexRecordHasher.cpp
new file mode 100644
index 0000000..4d47b7f
--- /dev/null
+++ b/lib/Index/IndexRecordHasher.cpp
@@ -0,0 +1,464 @@
+//===--- IndexRecordHasher.cpp - Index record hashing ---------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IndexRecordHasher.h"
+#include "FileIndexRecord.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclVisitor.h"
+#include "llvm/Support/Path.h"
+
+#define INITIAL_HASH 5381
+#define COMBINE_HASH(...) (Hash = hash_combine(Hash, __VA_ARGS__))
+
+using namespace clang;
+using namespace clang::index;
+using namespace llvm;
+
+static hash_code computeHash(const TemplateArgument &Arg,
+                             IndexRecordHasher &Hasher);
+
+namespace {
+class DeclHashVisitor : public ConstDeclVisitor<DeclHashVisitor, hash_code> {
+  IndexRecordHasher &Hasher;
+
+public:
+  DeclHashVisitor(IndexRecordHasher &Hasher) : Hasher(Hasher) {}
+
+  hash_code VisitDecl(const Decl *D) {
+    return VisitDeclContext(D->getDeclContext());
+  }
+
+  hash_code VisitNamedDecl(const NamedDecl *D) {
+    hash_code Hash = VisitDecl(D);
+    if (auto *attr = D->getExternalSourceSymbolAttr()) {
+      COMBINE_HASH(hash_value(attr->getDefinedIn()));
+    }
+    return COMBINE_HASH(Hasher.hash(D->getDeclName()));
+  }
+
+  hash_code VisitTagDecl(const TagDecl *D) {
+    if (D->getDeclName().isEmpty()) {
+      if (const TypedefNameDecl *TD = D->getTypedefNameForAnonDecl())
+        return Visit(TD);
+
+      hash_code Hash = VisitDeclContext(D->getDeclContext());
+      if (D->isEmbeddedInDeclarator() && !D->isFreeStanding()) {
+        COMBINE_HASH(hashLoc(D->getLocation(), /*IncludeOffset=*/true));
+      } else
+        COMBINE_HASH('a');
+      return Hash;
+    }
+
+    hash_code Hash = VisitTypeDecl(D);
+    return COMBINE_HASH('T');
+  }
+
+  hash_code VisitClassTemplateSpecializationDecl(const ClassTemplateSpecializationDecl *D) {
+    hash_code Hash = VisitCXXRecordDecl(D);
+    const TemplateArgumentList &Args = D->getTemplateArgs();
+    COMBINE_HASH('>');
+    for (unsigned I = 0, N = Args.size(); I != N; ++I) {
+      COMBINE_HASH(computeHash(Args.get(I), Hasher));
+    }
+    return Hash;
+  }
+
+  hash_code VisitObjCContainerDecl(const ObjCContainerDecl *D) {
+    hash_code Hash = VisitNamedDecl(D);
+    return COMBINE_HASH('I');
+  }
+
+  hash_code VisitObjCImplDecl(const ObjCImplDecl *D) {
+    if (auto *ID = D->getClassInterface())
+      return VisitObjCInterfaceDecl(ID);
+    else
+      return 0;
+  }
+
+  hash_code VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
+    // FIXME: Differentiate between category and the interface ?
+    if (auto *ID = D->getClassInterface())
+      return VisitObjCInterfaceDecl(ID);
+    else
+      return 0;
+  }
+
+  hash_code VisitFunctionDecl(const FunctionDecl *D) {
+    hash_code Hash = VisitNamedDecl(D);
+    ASTContext &Ctx = Hasher.getASTContext();
+    if ((!Ctx.getLangOpts().CPlusPlus && !D->hasAttr<OverloadableAttr>())
+        || D->isExternC())
+      return Hash;
+
+    for (auto param : D->parameters()) {
+      COMBINE_HASH(Hasher.hash(param->getType()));
+    }
+    return Hash;
+  }
+
+  hash_code VisitDeclContext(const DeclContext *DC) {
+    // FIXME: Add location if this is anonymous namespace ?
+    DC = DC->getRedeclContext();
+    const Decl *D = cast<Decl>(DC)->getCanonicalDecl();
+    if (auto *ND = dyn_cast<NamedDecl>(D))
+      return Hasher.hash(ND);
+    else
+      return 0;
+  }
+
+  hash_code hashLoc(SourceLocation Loc, bool IncludeOffset) {
+    if (Loc.isInvalid()) {
+      return 0;
+    }
+    hash_code Hash = INITIAL_HASH;
+    const SourceManager &SM = Hasher.getASTContext().getSourceManager();
+    Loc = SM.getFileLoc(Loc);
+    const std::pair<FileID, unsigned> &Decomposed = SM.getDecomposedLoc(Loc);
+    const FileEntry *FE = SM.getFileEntryForID(Decomposed.first);
+    if (FE) {
+      COMBINE_HASH(llvm::sys::path::filename(FE->getName()));
+    } else {
+      // This case really isn't interesting.
+      return 0;
+    }
+    if (IncludeOffset) {
+      // Use the offest into the FileID to represent the location.  Using
+      // a line/column can cause us to look back at the original source file,
+      // which is expensive.
+      COMBINE_HASH(Decomposed.second);
+    }
+    return Hash;
+  }
+};
+}
+
+hash_code IndexRecordHasher::hashRecord(const FileIndexRecord &Record) {
+  hash_code Hash = INITIAL_HASH;
+  for (auto &Info : Record.getDeclOccurrences()) {
+    COMBINE_HASH(Info.Roles, Info.Offset, hash(Info.Dcl));
+    for (auto &Rel : Info.Relations) {
+      COMBINE_HASH(hash(Rel.RelatedSymbol));
+    }
+  }
+  return Hash;
+}
+
+hash_code IndexRecordHasher::hash(const Decl *D) {
+  assert(D->isCanonicalDecl());
+
+  if (isa<TagDecl>(D) || isa<ObjCContainerDecl>(D)) {
+    return tryCache(D, D);
+  } else  if (auto *NS = dyn_cast<NamespaceDecl>(D)) {
+    if (NS->isAnonymousNamespace())
+      return hash_value(StringRef("@aN"));
+    return tryCache(D, D);
+  } else {
+    // There's a balance between caching results and not growing the cache too
+    // much. Measurements showed that avoiding caching all decls is beneficial
+    // particularly when including all of Cocoa.
+    return hashImpl(D);
+  }
+}
+
+hash_code IndexRecordHasher::hash(QualType NonCanTy) {
+  CanQualType CanTy = Ctx.getCanonicalType(NonCanTy);
+  return hash(CanTy);
+}
+
+hash_code IndexRecordHasher::hash(CanQualType CT) {
+  // Do some hashing without going to the cache, for example we can avoid
+  // storing the hash for both the type and its const-qualified version.
+  hash_code Hash = INITIAL_HASH;
+
+  auto asCanon = [](QualType Ty) -> CanQualType {
+    return CanQualType::CreateUnsafe(Ty);
+  };
+
+  while (true) {
+    Qualifiers Q = CT.getQualifiers();
+    CT = CT.getUnqualifiedType();
+    const Type *T = CT.getTypePtr();
+    unsigned qVal = 0;
+    if (Q.hasConst())
+      qVal |= 0x1;
+    if (Q.hasVolatile())
+      qVal |= 0x2;
+    if (Q.hasRestrict())
+      qVal |= 0x4;
+    if(qVal)
+      COMBINE_HASH(qVal);
+
+    // Hash in ObjC GC qualifiers?
+
+    if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) {
+      return COMBINE_HASH(BT->getKind());
+    }
+    if (const PointerType *PT = dyn_cast<PointerType>(T)) {
+      COMBINE_HASH('*');
+      CT = asCanon(PT->getPointeeType());
+      continue;
+    }
+    if (const ReferenceType *RT = dyn_cast<ReferenceType>(T)) {
+      COMBINE_HASH('&');
+      CT = asCanon(RT->getPointeeType());
+      continue;
+    }
+    if (const BlockPointerType *BT = dyn_cast<BlockPointerType>(T)) {
+      COMBINE_HASH('B');
+      CT = asCanon(BT->getPointeeType());
+      continue;
+    }
+    if (const ObjCObjectPointerType *OPT = dyn_cast<ObjCObjectPointerType>(T)) {
+      COMBINE_HASH('*');
+      CT = asCanon(OPT->getPointeeType());
+      continue;
+    }
+    if (const TagType *TT = dyn_cast<TagType>(T)) {
+      return COMBINE_HASH('$', hash(TT->getDecl()->getCanonicalDecl()));
+    }
+    if (const ObjCInterfaceType *OIT = dyn_cast<ObjCInterfaceType>(T)) {
+      return COMBINE_HASH('$', hash(OIT->getDecl()->getCanonicalDecl()));
+    }
+    if (const ObjCObjectType *OIT = dyn_cast<ObjCObjectType>(T)) {
+      for (auto *Prot : OIT->getProtocols())
+        COMBINE_HASH(hash(Prot));
+      CT = asCanon(OIT->getBaseType());
+      continue;
+    }
+    if (const TemplateTypeParmType *TTP = dyn_cast<TemplateTypeParmType>(T)) {
+      return COMBINE_HASH('t', TTP->getDepth(), TTP->getIndex());
+    }
+    if (const InjectedClassNameType *InjT = dyn_cast<InjectedClassNameType>(T)) {
+      CT = asCanon(InjT->getInjectedSpecializationType().getCanonicalType());
+      continue;
+    }
+
+    break;
+  }
+
+  return COMBINE_HASH(tryCache(CT.getAsOpaquePtr(), CT));
+}
+
+hash_code IndexRecordHasher::hash(DeclarationName Name) {
+  assert(!Name.isEmpty());
+  // Measurements for using cache or not here, showed significant slowdown when
+  // using the cache for all DeclarationNames when parsing Cocoa, and minor
+  // improvement or no difference for a couple of C++ single translation unit
+  // files. So we avoid caching DeclarationNames.
+  return hashImpl(Name);
+}
+
+hash_code IndexRecordHasher::hash(const NestedNameSpecifier *NNS) {
+  assert(NNS);
+  // Measurements for the C++ single translation unit files did not show much
+  // difference here; choosing to cache them currently.
+  return tryCache(NNS, NNS);
+}
+
+template <typename T>
+hash_code IndexRecordHasher::tryCache(const void *Ptr, T Obj) {
+  auto It = HashByPtr.find(Ptr);
+  if (It != HashByPtr.end())
+    return It->second;
+
+  hash_code Hash = hashImpl(Obj);
+  // hashImpl() may call into tryCache recursively and mutate
+  // HashByPtr, so we use find() earlier and insert the hash with another
+  // lookup here instead of calling insert() earlier and utilizing the iterator
+  // that insert() returns.
+  HashByPtr[Ptr] = Hash;
+  return Hash;
+}
+
+hash_code IndexRecordHasher::hashImpl(const Decl *D) {
+  return DeclHashVisitor(*this).Visit(D);
+}
+
+static hash_code computeHash(const IdentifierInfo *II) {
+  return hash_value(II->getName());
+}
+
+static hash_code computeHash(Selector Sel) {
+  unsigned N = Sel.getNumArgs();
+  if (N == 0)
+    ++N;
+  hash_code Hash = INITIAL_HASH;
+  for (unsigned I = 0; I != N; ++I)
+    if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(I))
+      COMBINE_HASH(computeHash(II));
+  return Hash;
+}
+
+static hash_code computeHash(TemplateName Name, IndexRecordHasher &Hasher) {
+  hash_code Hash = INITIAL_HASH;
+  if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
+    if (TemplateTemplateParmDecl *TTP
+        = dyn_cast<TemplateTemplateParmDecl>(Template)) {
+      return COMBINE_HASH('t', TTP->getDepth(), TTP->getIndex());
+    }
+
+    return COMBINE_HASH(Hasher.hash(Template));
+  }
+
+  // FIXME: Hash dependent template names.
+  return Hash;
+}
+
+static hash_code computeHash(const TemplateArgument &Arg,
+                             IndexRecordHasher &Hasher) {
+  hash_code Hash = INITIAL_HASH;
+
+  switch (Arg.getKind()) {
+  case TemplateArgument::Null:
+    break;
+
+  case TemplateArgument::Declaration:
+    COMBINE_HASH(Hasher.hash(Arg.getAsDecl()));
+    break;
+
+  case TemplateArgument::NullPtr:
+    break;
+
+  case TemplateArgument::TemplateExpansion:
+    COMBINE_HASH('P'); // pack expansion of...
+    // Fall through
+  case TemplateArgument::Template:
+    COMBINE_HASH(computeHash(Arg.getAsTemplateOrTemplatePattern(), Hasher));
+    break;
+      
+  case TemplateArgument::Expression:
+    // FIXME: Hash expressions.
+    break;
+      
+  case TemplateArgument::Pack:
+    COMBINE_HASH('p');
+    for (const auto &P : Arg.pack_elements())
+      COMBINE_HASH(computeHash(P, Hasher));
+    break;
+      
+  case TemplateArgument::Type:
+    COMBINE_HASH(Hasher.hash(Arg.getAsType()));
+    break;
+      
+  case TemplateArgument::Integral:
+    COMBINE_HASH('V', Hasher.hash(Arg.getIntegralType()), Arg.getAsIntegral());
+    break;
+  }
+
+  return Hash;
+}
+
+hash_code IndexRecordHasher::hashImpl(CanQualType CQT) {
+  hash_code Hash = INITIAL_HASH;
+
+  auto asCanon = [](QualType Ty) -> CanQualType {
+    return CanQualType::CreateUnsafe(Ty);
+  };
+
+  const Type *T = CQT.getTypePtr();
+
+  if (const PackExpansionType *Expansion = dyn_cast<PackExpansionType>(T)) {
+    return COMBINE_HASH('P', hash(asCanon(Expansion->getPattern())));
+  }
+  if (const RValueReferenceType *RT = dyn_cast<RValueReferenceType>(T)) {
+    return COMBINE_HASH('%', hash(asCanon(RT->getPointeeType())));
+  }
+  if (const FunctionProtoType *FT = dyn_cast<FunctionProtoType>(T)) {
+    COMBINE_HASH('F', hash(asCanon(FT->getReturnType())));
+    for (const auto &I : FT->param_types())
+      COMBINE_HASH(hash(asCanon(I)));
+    return COMBINE_HASH(FT->isVariadic());
+  }
+  if (const ComplexType *CT = dyn_cast<ComplexType>(T)) {
+    return COMBINE_HASH('<', hash(asCanon(CT->getElementType())));
+  }
+  if (const TemplateSpecializationType *Spec
+      = dyn_cast<TemplateSpecializationType>(T)) {
+    COMBINE_HASH('>', computeHash(Spec->getTemplateName(), *this));
+    for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I)
+      COMBINE_HASH(computeHash(Spec->getArg(I), *this));
+    return Hash;
+  }
+  if (const DependentNameType *DNT = dyn_cast<DependentNameType>(T)) {
+    COMBINE_HASH('^');
+    if (const NestedNameSpecifier *NNS = DNT->getQualifier())
+      COMBINE_HASH(hash(NNS));
+    return COMBINE_HASH(computeHash(DNT->getIdentifier()));
+  }
+
+  // Unhandled type.
+  return Hash;
+}
+
+hash_code IndexRecordHasher::hashImpl(DeclarationName Name) {
+  hash_code Hash = INITIAL_HASH;
+  COMBINE_HASH(Name.getNameKind());
+
+  switch (Name.getNameKind()) {
+    case DeclarationName::Identifier:
+      COMBINE_HASH(computeHash(Name.getAsIdentifierInfo()));
+      break;
+    case DeclarationName::ObjCZeroArgSelector:
+    case DeclarationName::ObjCOneArgSelector:
+    case DeclarationName::ObjCMultiArgSelector:
+      COMBINE_HASH(computeHash(Name.getObjCSelector()));
+      break;
+    case DeclarationName::CXXConstructorName:
+    case DeclarationName::CXXDestructorName:
+    case DeclarationName::CXXConversionFunctionName:
+      break;
+    case DeclarationName::CXXOperatorName:
+      COMBINE_HASH(Name.getCXXOverloadedOperator());
+      break;
+    case DeclarationName::CXXLiteralOperatorName:
+      COMBINE_HASH(computeHash(Name.getCXXLiteralIdentifier()));
+    case DeclarationName::CXXUsingDirective:
+      break;
+  }
+
+  return Hash;
+}
+
+hash_code IndexRecordHasher::hashImpl(const NestedNameSpecifier *NNS) {
+  hash_code Hash = INITIAL_HASH;
+  if (auto *Pre = NNS->getPrefix())
+    COMBINE_HASH(hash(Pre));
+
+  COMBINE_HASH(NNS->getKind());
+
+  switch (NNS->getKind()) {
+  case NestedNameSpecifier::Identifier:
+    COMBINE_HASH(computeHash(NNS->getAsIdentifier()));
+    break;
+
+  case NestedNameSpecifier::Namespace:
+    COMBINE_HASH(hash(NNS->getAsNamespace()->getCanonicalDecl()));
+    break;
+
+  case NestedNameSpecifier::NamespaceAlias:
+    COMBINE_HASH(hash(NNS->getAsNamespaceAlias()->getCanonicalDecl()));
+    break;
+
+  case NestedNameSpecifier::Global:
+    break;
+
+  case NestedNameSpecifier::Super:
+    break;
+
+  case NestedNameSpecifier::TypeSpecWithTemplate:
+    // Fall through to hash the type.
+
+  case NestedNameSpecifier::TypeSpec:
+    COMBINE_HASH(hash(QualType(NNS->getAsType(), 0)));
+    break;
+  }
+
+  return Hash;
+}
diff --git a/lib/Index/IndexRecordHasher.h b/lib/Index/IndexRecordHasher.h
new file mode 100644
index 0000000..af3accc
--- /dev/null
+++ b/lib/Index/IndexRecordHasher.h
@@ -0,0 +1,58 @@
+//===--- IndexRecordHasher.h - Index record hashing -----------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_INDEX_INDEXRECORDHASHER_H
+#define LLVM_CLANG_LIB_INDEX_INDEXRECORDHASHER_H
+
+#include "clang/Basic/LLVM.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
+
+namespace clang {
+  class ASTContext;
+  class Decl;
+  class DeclarationName;
+  class NestedNameSpecifier;
+  class QualType;
+  class Type;
+  template <typename> class CanQual;
+  typedef CanQual<Type> CanQualType;
+
+namespace index {
+  class FileIndexRecord;
+
+class IndexRecordHasher {
+  ASTContext &Ctx;
+  llvm::DenseMap<const void *, llvm::hash_code> HashByPtr;
+
+public:
+  explicit IndexRecordHasher(ASTContext &Ctx) : Ctx(Ctx) {}
+  ASTContext &getASTContext() { return Ctx; }
+
+  llvm::hash_code hashRecord(const FileIndexRecord &Record);
+  llvm::hash_code hash(const Decl *D);
+  llvm::hash_code hash(QualType Ty);
+  llvm::hash_code hash(CanQualType Ty);
+  llvm::hash_code hash(DeclarationName Name);
+  llvm::hash_code hash(const NestedNameSpecifier *NNS);
+
+private:
+  template <typename T>
+  llvm::hash_code tryCache(const void *Ptr, T Obj);
+
+  llvm::hash_code hashImpl(const Decl *D);
+  llvm::hash_code hashImpl(CanQualType Ty);
+  llvm::hash_code hashImpl(DeclarationName Name);
+  llvm::hash_code hashImpl(const NestedNameSpecifier *NNS);
+};
+
+} // end namespace index
+} // end namespace clang
+
+#endif
diff --git a/lib/Index/IndexRecordReader.cpp b/lib/Index/IndexRecordReader.cpp
new file mode 100644
index 0000000..bd2ec1f
--- /dev/null
+++ b/lib/Index/IndexRecordReader.cpp
@@ -0,0 +1,407 @@
+//===--- IndexRecordReader.cpp - Index record deserialization -------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/IndexRecordReader.h"
+#include "IndexDataStoreUtils.h"
+#include "BitstreamVisitor.h"
+#include "clang/Index/IndexDataStoreSymbolUtils.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::index;
+using namespace clang::index::store;
+using namespace llvm;
+
+struct IndexRecordReader::Implementation {
+  BumpPtrAllocator Allocator;
+  std::unique_ptr<MemoryBuffer> Buffer;
+  llvm::BitstreamCursor DeclCursor;
+  llvm::BitstreamCursor OccurCursor;
+  ArrayRef<uint32_t> DeclOffsets;
+  const IndexRecordDecl **Decls;
+
+  void setDeclOffsets(ArrayRef<uint32_t> Offs) {
+    DeclOffsets = Offs;
+    Decls = Allocator.Allocate<const IndexRecordDecl*>(Offs.size());
+    memset(Decls, 0, sizeof(IndexRecordDecl*)*Offs.size());
+  }
+
+  unsigned getNumDecls() const { return DeclOffsets.size(); }
+
+  const IndexRecordDecl *getDeclByID(unsigned DeclID) {
+    if (DeclID == 0)
+      return nullptr;
+    return getDecl(DeclID-1);
+  }
+
+  const IndexRecordDecl *getDecl(unsigned Index) {
+    assert(Index < getNumDecls());
+    if (const IndexRecordDecl *D = Decls[Index])
+      return D;
+
+    IndexRecordDecl *D = Allocator.Allocate<IndexRecordDecl>();
+    readDecl(Index, *D);
+    Decls[Index] = D;
+    return D;
+  }
+
+  /// Goes through the decls and populates a vector of record decls, based on
+  /// what the given function returns.
+  ///
+  /// The advantage of this function is to allocate memory only for the record
+  /// decls that the caller is interested in.
+  bool searchDecls(llvm::function_ref<DeclSearchCheck> Checker,
+                   llvm::function_ref<void(const IndexRecordDecl *)> Receiver) {
+    for (unsigned I = 0, E = getNumDecls(); I != E; ++I) {
+      if (const IndexRecordDecl *D = Decls[I]) {
+        DeclSearchReturn Ret = Checker(*D);
+        if (Ret.AcceptDecl)
+          Receiver(D);
+        if (!Ret.ContinueSearch)
+          return false;
+        continue;
+      }
+
+      IndexRecordDecl LocalD;
+      readDecl(I, LocalD);
+      DeclSearchReturn Ret = Checker(LocalD);
+      if (Ret.AcceptDecl) {
+        IndexRecordDecl *D = Allocator.Allocate<IndexRecordDecl>();
+        *D = LocalD;
+        Decls[I] = D;
+        Receiver(D);
+      }
+      if (!Ret.ContinueSearch)
+        return false;
+    }
+    return true;
+  }
+
+  void readDecl(unsigned Index, IndexRecordDecl &RecD) {
+    RecordData Record;
+    StringRef Blob;
+    DeclCursor.JumpToBit(DeclOffsets[Index]);
+    unsigned Code = DeclCursor.ReadCode();
+    unsigned RecID = DeclCursor.readRecord(Code, Record, &Blob);
+    assert(RecID == REC_DECLINFO);
+    (void)RecID;
+
+    unsigned I = 0;
+    RecD.DeclID = Index+1;
+    RecD.SymInfo.Kind = getSymbolKind((indexstore_symbol_kind_t)read(Record, I));
+    RecD.SymInfo.SubKind = getSymbolSubKind((indexstore_symbol_subkind_t)read(Record, I));
+    RecD.SymInfo.Lang =
+        getSymbolLanguage((indexstore_symbol_language_t)read(Record, I));
+    RecD.SymInfo.Properties = getSymbolProperties(read(Record, I));
+    RecD.Roles = getSymbolRoles(read(Record, I));
+    RecD.RelatedRoles = getSymbolRoles(read(Record, I));
+    size_t NameLen = read(Record, I);
+    size_t USRLen = read(Record, I);
+    RecD.Name = Blob.substr(0, NameLen);
+    RecD.USR = Blob.substr(NameLen, USRLen);
+    RecD.CodeGenName = Blob.substr(NameLen+USRLen);
+  }
+
+  /// Reads occurrence data.
+  /// \param DeclsFilter if non-empty indicates the list of decls that we want
+  /// to get occurrences for. If empty then indicates that we want occurrences
+  /// for all decls.
+  /// \param RelatedDeclsFilter Same as \c DeclsFilter but for related decls.
+  /// \returns true if the occurrence info was filled out, false if occurrence
+  /// was ignored.
+  bool readOccurrence(RecordDataImpl &Record, StringRef Blob,
+                      ArrayRef<const IndexRecordDecl *> DeclsFilter,
+                      ArrayRef<const IndexRecordDecl *> RelatedDeclsFilter,
+                      IndexRecordOccurrence &RecOccur) {
+
+    auto isDeclIDContained = [](unsigned DeclID,
+                                ArrayRef<const IndexRecordDecl *> Ds) -> bool {
+      if (Ds.empty())
+        return true; // empty means accept all.
+      auto pred = [DeclID](const IndexRecordDecl *D) { return D->DeclID == DeclID; };
+      return std::find_if(Ds.begin(), Ds.end(), pred) != Ds.end();
+    };
+
+    unsigned I = 0;
+    unsigned DeclID = read(Record, I);
+    if (!isDeclIDContained(DeclID, DeclsFilter))
+      return false;
+
+    if (!RelatedDeclsFilter.empty()) {
+      unsigned RelI = I+3;
+      unsigned NumRelated = read(Record, RelI);
+      bool FoundRelated = false;
+      while (NumRelated--) {
+        ++RelI; // roles;
+        unsigned RelDID = read(Record, RelI);
+        if (isDeclIDContained(RelDID, RelatedDeclsFilter)) {
+          FoundRelated = true;
+          break;
+        }
+      }
+      if (!FoundRelated)
+        return false;
+    }
+
+    RecOccur.Dcl = getDeclByID(DeclID);
+    RecOccur.Roles = getSymbolRoles(read(Record, I));
+    RecOccur.Line = read(Record, I);
+    RecOccur.Column = read(Record, I);
+
+    unsigned NumRelated = read(Record, I);
+    while (NumRelated--) {
+      SymbolRoleSet RelRoles = getSymbolRoles(read(Record, I));
+      const IndexRecordDecl *RelD = getDeclByID(read(Record, I));
+      RecOccur.Relations.emplace_back(RelRoles, RelD);
+    }
+
+    return true;
+  }
+
+  bool foreachDecl(bool NoCache,
+                   function_ref<bool(const IndexRecordDecl *)> Receiver) {
+    for (unsigned I = 0, E = getNumDecls(); I != E; ++I) {
+      if (const IndexRecordDecl *D = Decls[I]) {
+        if (!Receiver(D))
+          return false;
+        continue;
+      }
+
+      if (NoCache) {
+        IndexRecordDecl LocalD;
+        readDecl(I, LocalD);
+        if (!Receiver(&LocalD))
+          return false;
+      } else {
+        if (!Receiver(getDecl(I)))
+          return false;
+      }
+    }
+    return true;
+  }
+
+  bool foreachOccurrence(ArrayRef<const IndexRecordDecl *> DeclsFilter,
+                         ArrayRef<const IndexRecordDecl *> RelatedDeclsFilter,
+                         function_ref<bool(const IndexRecordOccurrence &)> Receiver) {
+    class OccurBitVisitor : public BitstreamVisitor<OccurBitVisitor> {
+      IndexRecordReader::Implementation &Reader;
+      ArrayRef<const IndexRecordDecl *> DeclsFilter;
+      ArrayRef<const IndexRecordDecl *> RelatedDeclsFilter;
+      function_ref<bool(const IndexRecordOccurrence &)> Receiver;
+
+    public:
+      OccurBitVisitor(llvm::BitstreamCursor &Stream,
+                      IndexRecordReader::Implementation &Reader,
+                      ArrayRef<const IndexRecordDecl *> DeclsFilter,
+                      ArrayRef<const IndexRecordDecl *> RelatedDeclsFilter,
+                      function_ref<bool(const IndexRecordOccurrence &)> Receiver)
+        : BitstreamVisitor(Stream),
+          Reader(Reader),
+          DeclsFilter(DeclsFilter),
+          RelatedDeclsFilter(RelatedDeclsFilter),
+          Receiver(std::move(Receiver)) {}
+
+      StreamVisit visitRecord(unsigned BlockID, unsigned RecID,
+                              RecordDataImpl &Record, StringRef Blob) {
+        assert(RecID == REC_DECLOCCURRENCE);
+        IndexRecordOccurrence RecOccur;
+        if (Reader.readOccurrence(Record, Blob, DeclsFilter, RelatedDeclsFilter,
+                                   RecOccur))
+          if (!Receiver(RecOccur))
+            return StreamVisit::Abort;
+        return StreamVisit::Continue;
+      }
+    };
+
+    SavedStreamPosition SavedPosition(OccurCursor);
+    OccurBitVisitor Visitor(OccurCursor, *this, DeclsFilter, RelatedDeclsFilter,
+                            Receiver);
+    std::string Error;
+    return Visitor.visit(Error);
+  }
+
+  bool foreachOccurrenceInLineRange(unsigned lineStart, unsigned lineCount,
+            llvm::function_ref<bool(const IndexRecordOccurrence &)> receiver) {
+    // FIXME: Use binary search and make this more efficient.
+    unsigned lineEnd = lineStart+lineCount;
+    return foreachOccurrence(None, None, [&](const IndexRecordOccurrence &occur) -> bool {
+      if (occur.Line > lineEnd)
+        return false; // we're done.
+      if (occur.Line >= lineStart) {
+        if (!receiver(occur))
+          return false;
+      }
+      return true;
+    });
+  }
+
+  static uint64_t read(RecordDataImpl &Record, unsigned &I) {
+    return Record[I++];
+  }
+};
+
+namespace {
+
+class IndexBitstreamVisitor : public BitstreamVisitor<IndexBitstreamVisitor> {
+  IndexRecordReader::Implementation &Reader;
+
+public:
+  IndexBitstreamVisitor(llvm::BitstreamCursor &Stream,
+                        IndexRecordReader::Implementation &Reader)
+    : BitstreamVisitor(Stream), Reader(Reader) {}
+
+  StreamVisit visitBlock(unsigned ID) {
+    switch ((RecordBitBlock)ID) {
+    case REC_VERSION_BLOCK_ID:
+    case REC_DECLOFFSETS_BLOCK_ID:
+      return StreamVisit::Continue;
+
+    case REC_DECLS_BLOCK_ID:
+      Reader.DeclCursor = Stream;
+      if (Reader.DeclCursor.EnterSubBlock(ID)) {
+        *Error = "malformed block record";
+        return StreamVisit::Abort;
+      }
+      readBlockAbbrevs(Reader.DeclCursor);
+      return StreamVisit::Skip;
+
+    case REC_DECLOCCURRENCES_BLOCK_ID:
+      Reader.OccurCursor = Stream;
+      if (Reader.OccurCursor.EnterSubBlock(ID)) {
+        *Error = "malformed block record";
+        return StreamVisit::Abort;
+      }
+      readBlockAbbrevs(Reader.OccurCursor);
+      return StreamVisit::Skip;
+    }
+
+    // Some newly introduced block in a minor version update that we cannot
+    // handle.
+    return StreamVisit::Skip;
+  }
+
+  StreamVisit visitRecord(unsigned BlockID, unsigned RecID,
+                          RecordDataImpl &Record, StringRef Blob) {
+    switch (BlockID) {
+    case REC_VERSION_BLOCK_ID: {
+      unsigned StoreFormatVersion = Record[0];
+      if (StoreFormatVersion != STORE_FORMAT_VERSION) {
+        llvm::raw_string_ostream OS(*Error);
+        OS << "Store format version mismatch: " << StoreFormatVersion;
+        OS << " , expected: " << STORE_FORMAT_VERSION;
+        return StreamVisit::Abort;
+      }
+      break;
+    }
+    case REC_DECLOFFSETS_BLOCK_ID:
+      assert(RecID == REC_DECLOFFSETS);
+      Reader.setDeclOffsets(makeArrayRef((uint32_t*)Blob.data(), Record[0]));
+      break;
+
+    case REC_DECLS_BLOCK_ID:
+    case REC_DECLOCCURRENCES_BLOCK_ID:
+      llvm_unreachable("shouldn't visit this block'");
+    }
+    return StreamVisit::Continue;
+  }
+};
+
+} // anonymous namespace
+
+std::unique_ptr<IndexRecordReader>
+IndexRecordReader::createWithRecordFilename(StringRef RecordFilename,
+                                            StringRef StorePath,
+                                            std::string &Error) {
+  SmallString<128> PathBuf = StorePath;
+  appendRecordSubDir(PathBuf);
+  appendInteriorRecordPath(RecordFilename, PathBuf);
+  return createWithFilePath(PathBuf.str(), Error);
+}
+
+std::unique_ptr<IndexRecordReader>
+IndexRecordReader::createWithFilePath(StringRef FilePath, std::string &Error) {
+  auto ErrOrBuf = MemoryBuffer::getFile(FilePath, /*FileSize=*/-1,
+                                        /*RequiresNullTerminator=*/false);
+  if (!ErrOrBuf) {
+    raw_string_ostream(Error) << "failed opening index record '"
+      << FilePath << "': " << ErrOrBuf.getError().message();
+    return nullptr;
+  }
+  return createWithBuffer(std::move(*ErrOrBuf), Error);
+}
+
+std::unique_ptr<IndexRecordReader>
+IndexRecordReader::createWithBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer,
+                                    std::string &Error) {
+
+  std::unique_ptr<IndexRecordReader> Reader;
+  Reader.reset(new IndexRecordReader());
+  auto &Impl = Reader->Impl;
+  Impl.Buffer = std::move(Buffer);
+  llvm::BitstreamCursor Stream(*Impl.Buffer);
+
+  // Sniff for the signature.
+  if (Stream.Read(8) != 'I' ||
+      Stream.Read(8) != 'D' ||
+      Stream.Read(8) != 'X' ||
+      Stream.Read(8) != 'R') {
+    Error = "not a serialized index record file";
+    return nullptr;
+  }
+
+  IndexBitstreamVisitor BitVisitor(Stream, Impl);
+  if (!BitVisitor.visit(Error))
+    return nullptr;
+
+  return Reader;
+}
+
+IndexRecordReader::IndexRecordReader()
+  : Impl(*new Implementation()) {
+
+}
+
+IndexRecordReader::~IndexRecordReader() {
+  delete &Impl;
+}
+
+bool IndexRecordReader::searchDecls(
+                        llvm::function_ref<DeclSearchCheck> Checker,
+                  llvm::function_ref<void(const IndexRecordDecl *)> Receiver) {
+  return Impl.searchDecls(std::move(Checker), std::move(Receiver));
+}
+
+bool IndexRecordReader::foreachDecl(bool NoCache,
+                                    function_ref<bool(const IndexRecordDecl *)> Receiver) {
+  return Impl.foreachDecl(NoCache, std::move(Receiver));
+}
+
+bool IndexRecordReader::foreachOccurrence(
+                  ArrayRef<const IndexRecordDecl *> DeclsFilter,
+                  ArrayRef<const IndexRecordDecl *> RelatedDeclsFilter,
+                  function_ref<bool(const IndexRecordOccurrence &)> Receiver) {
+  return Impl.foreachOccurrence(DeclsFilter, RelatedDeclsFilter,
+                                std::move(Receiver));
+}
+
+bool IndexRecordReader::foreachOccurrence(
+            llvm::function_ref<bool(const IndexRecordOccurrence &)> Receiver) {
+  return foreachOccurrence(None, None, std::move(Receiver));
+}
+
+bool IndexRecordReader::foreachOccurrenceInLineRange(unsigned lineStart,
+                                                     unsigned lineCount,
+             llvm::function_ref<bool(const IndexRecordOccurrence &)> Receiver) {
+  return Impl.foreachOccurrenceInLineRange(lineStart, lineCount, Receiver);
+}
diff --git a/lib/Index/IndexRecordWriter.cpp b/lib/Index/IndexRecordWriter.cpp
new file mode 100644
index 0000000..c4e6d50
--- /dev/null
+++ b/lib/Index/IndexRecordWriter.cpp
@@ -0,0 +1,366 @@
+//===--- IndexRecordWriter.cpp - Index record serialization ---------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/IndexRecordWriter.h"
+#include "IndexDataStoreUtils.h"
+#include "indexstore/indexstore.h"
+#include "clang/Index/IndexDataStoreSymbolUtils.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::index;
+using namespace clang::index::store;
+using namespace llvm;
+
+using writer::OpaqueDecl;
+
+namespace {
+struct DeclInfo {
+  OpaqueDecl D;
+  SymbolRoleSet Roles;
+  SymbolRoleSet RelatedRoles;
+};
+
+struct OccurrenceInfo {
+  unsigned DeclID;
+  OpaqueDecl D;
+  SymbolRoleSet Roles;
+  unsigned Line;
+  unsigned Column;
+  SmallVector<std::pair<writer::SymbolRelation, unsigned>, 4> Related;
+};
+
+struct RecordState {
+  std::string RecordPath;
+  SmallString<512> Buffer;
+  BitstreamWriter Stream;
+
+  DenseMap<OpaqueDecl, unsigned> IndexForDecl;
+  std::vector<DeclInfo> Decls;
+  std::vector<OccurrenceInfo> Occurrences;
+
+  RecordState(std::string &&RecordPath)
+      : RecordPath(std::move(RecordPath)), Stream(Buffer) {}
+};
+} // end anonymous namespace
+
+static void writeBlockInfo(BitstreamWriter &Stream) {
+  RecordData Record;
+
+  Stream.EnterBlockInfoBlock();
+#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)
+#define RECORD(X) emitRecordID(X, #X, Stream, Record)
+
+  BLOCK(REC_VERSION_BLOCK);
+  RECORD(REC_VERSION);
+
+  BLOCK(REC_DECLS_BLOCK);
+  RECORD(REC_DECLINFO);
+
+  BLOCK(REC_DECLOFFSETS_BLOCK);
+  RECORD(REC_DECLOFFSETS);
+
+  BLOCK(REC_DECLOCCURRENCES_BLOCK);
+  RECORD(REC_DECLOCCURRENCE);
+
+#undef RECORD
+#undef BLOCK
+  Stream.ExitBlock();
+}
+
+static void writeVersionInfo(BitstreamWriter &Stream) {
+  using namespace llvm::sys;
+
+  Stream.EnterSubblock(REC_VERSION_BLOCK_ID, 3);
+
+  auto Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(REC_VERSION));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Store format version
+  unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
+
+  RecordData Record;
+  Record.push_back(REC_VERSION);
+  Record.push_back(STORE_FORMAT_VERSION);
+  Stream.EmitRecordWithAbbrev(AbbrevCode, Record);
+
+  Stream.ExitBlock();
+}
+
+template <typename T, typename Allocator>
+static StringRef data(const std::vector<T, Allocator> &v) {
+  if (v.empty())
+    return StringRef();
+  return StringRef(reinterpret_cast<const char *>(&v[0]), sizeof(T) * v.size());
+}
+
+template <typename T> static StringRef data(const SmallVectorImpl<T> &v) {
+  return StringRef(reinterpret_cast<const char *>(v.data()),
+                   sizeof(T) * v.size());
+}
+
+static void writeDecls(BitstreamWriter &Stream, ArrayRef<DeclInfo> Decls,
+                       ArrayRef<OccurrenceInfo> Occurrences,
+                       writer::SymbolWriterCallback GetSymbolForDecl) {
+  SmallVector<uint32_t, 32> DeclOffsets;
+  DeclOffsets.reserve(Decls.size());
+
+  //===--------------------------------------------------------------------===//
+  // DECLS_BLOCK_ID
+  //===--------------------------------------------------------------------===//
+
+  Stream.EnterSubblock(REC_DECLS_BLOCK_ID, 3);
+
+  auto Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(REC_DECLINFO));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // Kind
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // SubKind
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // Language
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, SymbolPropertyBitNum)); // Properties
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, SymbolRoleBitNum)); // Roles
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, SymbolRoleBitNum)); // Related Roles
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Length of name in block
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Length of USR in block
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + USR + CodeGen symbol name
+  unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
+
+#ifndef NDEBUG
+  StringSet<> USRSet;
+#endif
+
+  RecordData Record;
+  llvm::SmallString<256> Blob;
+  llvm::SmallString<256> Scratch;
+  for (auto &Info : Decls) {
+    DeclOffsets.push_back(Stream.GetCurrentBitNo());
+    Blob.clear();
+    Scratch.clear();
+
+    writer::Symbol SymInfo = GetSymbolForDecl(Info.D, Scratch);
+    assert(SymInfo.SymInfo.Kind != SymbolKind::Unknown);
+    assert(!SymInfo.USR.empty() && "Recorded decl without USR!");
+
+    Blob += SymInfo.Name;
+    Blob += SymInfo.USR;
+    Blob += SymInfo.CodeGenName;
+
+#ifndef NDEBUG
+    bool IsNew = USRSet.insert(SymInfo.USR).second;
+    if (!IsNew) {
+      llvm::errs() << "Index: Duplicate USR! " << SymInfo.USR << "\n";
+      // FIXME: print more information so it's easier to find the declaration.
+    }
+#endif
+
+    Record.clear();
+    Record.push_back(REC_DECLINFO);
+    Record.push_back(getIndexStoreKind(SymInfo.SymInfo.Kind));
+    Record.push_back(getIndexStoreSubKind(SymInfo.SymInfo.SubKind));
+    Record.push_back(getIndexStoreLang(SymInfo.SymInfo.Lang));
+    Record.push_back(getIndexStoreProperties(SymInfo.SymInfo.Properties));
+    Record.push_back(getIndexStoreRoles(Info.Roles));
+    Record.push_back(getIndexStoreRoles(Info.RelatedRoles));
+    Record.push_back(SymInfo.Name.size());
+    Record.push_back(SymInfo.USR.size());
+    Stream.EmitRecordWithBlob(AbbrevCode, Record, Blob);
+  }
+
+  Stream.ExitBlock();
+
+  //===--------------------------------------------------------------------===//
+  // DECLOFFSETS_BLOCK_ID
+  //===--------------------------------------------------------------------===//
+
+  Stream.EnterSubblock(REC_DECLOFFSETS_BLOCK_ID, 3);
+
+  Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(REC_DECLOFFSETS));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // Number of Decls
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Offsets array
+  AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
+
+  Record.clear();
+  Record.push_back(REC_DECLOFFSETS);
+  Record.push_back(DeclOffsets.size());
+  Stream.EmitRecordWithBlob(AbbrevCode, Record, data(DeclOffsets));
+
+  Stream.ExitBlock();
+
+  //===--------------------------------------------------------------------===//
+  // DECLOCCURRENCES_BLOCK_ID
+  //===--------------------------------------------------------------------===//
+
+  Stream.EnterSubblock(REC_DECLOCCURRENCES_BLOCK_ID, 3);
+
+  Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(REC_DECLOCCURRENCE));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Decl ID
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, SymbolRoleBitNum)); // Roles
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Line
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Column
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 4)); // Num related
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); // Related Roles/IDs
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // Roles or ID
+  AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
+
+  for (auto &Occur : Occurrences) {
+    Record.clear();
+    Record.push_back(REC_DECLOCCURRENCE);
+    Record.push_back(Occur.DeclID);
+    Record.push_back(getIndexStoreRoles(Occur.Roles));
+    Record.push_back(Occur.Line);
+    Record.push_back(Occur.Column);
+    Record.push_back(Occur.Related.size());
+    for (auto &Rel : Occur.Related) {
+      Record.push_back(getIndexStoreRoles(Rel.first.Roles));
+      Record.push_back(Rel.second);
+    }
+    Stream.EmitRecordWithAbbrev(AbbrevCode, Record);
+  }
+  Stream.ExitBlock();
+}
+
+IndexRecordWriter::IndexRecordWriter(StringRef IndexPath)
+    : RecordsPath(IndexPath) {
+  store::appendRecordSubDir(RecordsPath);
+}
+
+IndexRecordWriter::Result
+IndexRecordWriter::beginRecord(StringRef Filename, hash_code RecordHash,
+                               std::string &Error, std::string *OutRecordFile) {
+  using namespace llvm::sys;
+  assert(!Record && "called beginRecord before calling endRecord on previous");
+
+  std::string RecordName;
+  {
+    llvm::raw_string_ostream RN(RecordName);
+    RN << path::filename(Filename);
+    RN << "-" << APInt(64, RecordHash).toString(36, /*Signed=*/false);
+  }
+  SmallString<256> RecordPath = RecordsPath.str();
+  appendInteriorRecordPath(RecordName, RecordPath);
+
+  if (OutRecordFile)
+    *OutRecordFile = RecordName;
+
+  if (std::error_code EC =
+          fs::access(RecordPath.c_str(), fs::AccessMode::Exist)) {
+    if (EC != errc::no_such_file_or_directory) {
+      llvm::raw_string_ostream Err(Error);
+      Err << "could not access record '" << RecordPath
+          << "': " << EC.message();
+      return Result::Failure;
+    }
+  } else {
+    return Result::AlreadyExists;
+  }
+
+  // Write the record header.
+  auto *State = new RecordState(RecordPath.str());
+  Record = State;
+  llvm::BitstreamWriter &Stream = State->Stream;
+  Stream.Emit('I', 8);
+  Stream.Emit('D', 8);
+  Stream.Emit('X', 8);
+  Stream.Emit('R', 8);
+
+  writeBlockInfo(Stream);
+  writeVersionInfo(Stream);
+
+  return Result::Success;
+}
+
+IndexRecordWriter::Result
+IndexRecordWriter::endRecord(std::string &Error,
+                             writer::SymbolWriterCallback GetSymbolForDecl) {
+  assert(Record && "called endRecord without calling beginRecord");
+  auto &State = *static_cast<RecordState *>(Record);
+  Record = nullptr;
+  struct ScopedDelete {
+    RecordState *S;
+    ScopedDelete(RecordState *S) : S(S) {}
+    ~ScopedDelete() { delete S; }
+  } Deleter(&State);
+
+  if (!State.Decls.empty()) {
+    writeDecls(State.Stream, State.Decls, State.Occurrences, GetSymbolForDecl);
+  }
+
+  if (std::error_code EC = sys::fs::create_directory(sys::path::parent_path(State.RecordPath))) {
+    llvm::raw_string_ostream Err(Error);
+    Err << "failed to create directory '" << sys::path::parent_path(State.RecordPath) << "': " << EC.message();
+    return Result::Failure;
+  }
+
+  // Create a unique file to write to so that we can move the result into place
+  // atomically. If this process crashes we don't want to interfere with any
+  // other concurrent processes.
+  SmallString<128> TempPath(State.RecordPath);
+  TempPath += "-temp-%%%%%%%%";
+  int TempFD;
+  if (sys::fs::createUniqueFile(TempPath.str(), TempFD, TempPath)) {
+    llvm::raw_string_ostream Err(Error);
+    Err << "failed to create temporary file: " << TempPath;
+    return Result::Failure;
+  }
+
+  raw_fd_ostream OS(TempFD, /*shouldClose=*/true);
+  OS.write(State.Buffer.data(), State.Buffer.size());
+  OS.close();
+
+  // Atomically move the unique file into place.
+  if (std::error_code EC =
+          sys::fs::rename(TempPath.c_str(), State.RecordPath.c_str())) {
+    llvm::raw_string_ostream Err(Error);
+    Err << "failed to rename '" << TempPath << "' to '" << State.RecordPath << "': " << EC.message();
+    return Result::Failure;
+  }
+
+  return Result::Success;
+}
+
+void IndexRecordWriter::addOccurrence(
+    OpaqueDecl D, SymbolRoleSet Roles, unsigned Line, unsigned Column,
+    ArrayRef<writer::SymbolRelation> Related) {
+  assert(Record && "called addOccurrence without calling beginRecord");
+  auto &State = *static_cast<RecordState *>(Record);
+
+  auto insertDecl = [&](OpaqueDecl D, SymbolRoleSet Roles,
+                        SymbolRoleSet RelatedRoles) -> unsigned {
+    auto Insert =
+        State.IndexForDecl.insert(std::make_pair(D, State.Decls.size()));
+    unsigned Index = Insert.first->second;
+
+    if (Insert.second) {
+      State.Decls.push_back(DeclInfo{D, Roles, RelatedRoles});
+    } else {
+      State.Decls[Index].Roles |= Roles;
+      State.Decls[Index].RelatedRoles |= RelatedRoles;
+    }
+    return Index + 1;
+  };
+
+  unsigned DeclID = insertDecl(D, Roles, SymbolRoleSet());
+
+  decltype(OccurrenceInfo::Related) RelatedDecls;
+  RelatedDecls.reserve(Related.size());
+  for (auto &Rel : Related) {
+    unsigned ID = insertDecl(Rel.RelatedSymbol, SymbolRoleSet(), Rel.Roles);
+    RelatedDecls.emplace_back(Rel, ID);
+  }
+
+  State.Occurrences.push_back(
+      OccurrenceInfo{DeclID, D, Roles, Line, Column, std::move(RelatedDecls)});
+}
diff --git a/lib/Index/IndexUnitReader.cpp b/lib/Index/IndexUnitReader.cpp
new file mode 100644
index 0000000..12a9056
--- /dev/null
+++ b/lib/Index/IndexUnitReader.cpp
@@ -0,0 +1,516 @@
+//===--- IndexUnitReader.cpp - Index unit deserialization -----------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/IndexUnitReader.h"
+#include "IndexDataStoreUtils.h"
+#include "BitstreamVisitor.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Bitcode/BitstreamReader.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <unistd.h>
+
+using namespace clang;
+using namespace clang::index;
+using namespace clang::index::store;
+using namespace llvm;
+
+namespace {
+
+typedef function_ref<bool(const IndexUnitReader::DependencyInfo &)> DependencyReceiver;
+typedef function_ref<bool(const IndexUnitReader::IncludeInfo &)> IncludeReceiver;
+
+class IndexUnitReaderImpl {
+  sys::TimePoint<> ModTime;
+  std::unique_ptr<MemoryBuffer> MemBuf;
+
+public:
+  StringRef ProviderIdentifier;
+  StringRef ProviderVersion;
+  llvm::BitstreamCursor DependCursor;
+  llvm::BitstreamCursor IncludeCursor;
+  bool IsSystemUnit;
+  bool IsModuleUnit;
+  bool IsDebugCompilation;
+  StringRef WorkingDir;
+  StringRef OutputFile;
+  StringRef SysrootPath;
+  StringRef ModuleName;
+  SmallString<128> MainFilePath;
+  StringRef Target;
+  std::vector<FileBitPath> Paths;
+  StringRef PathsBuffer;
+
+  struct ModuleInfo {
+    unsigned NameOffset;
+    unsigned NameSize;
+  };
+  std::vector<ModuleInfo> Modules;
+  StringRef ModuleNamesBuffer;
+
+  bool init(std::unique_ptr<MemoryBuffer> Buf, sys::TimePoint<> ModTime,
+            std::string &Error);
+
+  StringRef getProviderIdentifier() const { return ProviderIdentifier; }
+  StringRef getProviderVersion() const { return ProviderVersion; }
+
+  sys::TimePoint<> getModificationTime() const { return ModTime; }
+  StringRef getWorkingDirectory() const { return WorkingDir; }
+  StringRef getOutputFile() const { return OutputFile; }
+  StringRef getSysrootPath() const { return SysrootPath; }
+  StringRef getTarget() const { return Target; }
+
+  StringRef getModuleName() const { return ModuleName; }
+  StringRef getMainFilePath() const { return MainFilePath.str(); }
+  bool hasMainFile() const { return !MainFilePath.empty(); }
+  bool isSystemUnit() const { return IsSystemUnit; }
+  bool isModuleUnit() const { return IsModuleUnit; }
+  bool isDebugCompilation() const { return IsDebugCompilation; }
+
+  /// Unit dependencies are provided ahead of record ones, record ones
+  /// ahead of the file ones.
+  bool foreachDependency(DependencyReceiver Receiver);
+
+  bool foreachInclude(IncludeReceiver Receiver);
+
+  StringRef getPathFromBuffer(size_t Offset, size_t Size) {
+    return PathsBuffer.substr(Offset, Size);
+  }
+
+  void constructFilePath(SmallVectorImpl<char> &Path, int PathIndex);
+
+  StringRef getModuleName(int ModuleIndex);
+};
+
+class IndexUnitBitstreamVisitor : public BitstreamVisitor<IndexUnitBitstreamVisitor> {
+  IndexUnitReaderImpl &Reader;
+  size_t WorkDirOffset;
+  size_t WorkDirSize;
+  size_t OutputFileOffset;
+  size_t OutputFileSize;
+  size_t SysrootOffset;
+  size_t SysrootSize;
+  int MainPathIndex;
+
+public:
+  IndexUnitBitstreamVisitor(llvm::BitstreamCursor &Stream,
+                            IndexUnitReaderImpl &Reader)
+    : BitstreamVisitor(Stream), Reader(Reader) {}
+
+  StreamVisit visitBlock(unsigned ID) {
+    switch ((UnitBitBlock)ID) {
+    case UNIT_VERSION_BLOCK_ID:
+    case UNIT_INFO_BLOCK_ID:
+    case UNIT_PATHS_BLOCK_ID:
+    case UNIT_MODULES_BLOCK_ID:
+      return StreamVisit::Continue;
+
+    case UNIT_DEPENDENCIES_BLOCK_ID:
+      Reader.DependCursor = Stream;
+      if (Reader.DependCursor.EnterSubBlock(ID)) {
+        *Error = "malformed unit dependencies block record";
+        return StreamVisit::Abort;
+      }
+      readBlockAbbrevs(Reader.DependCursor);
+      return StreamVisit::Skip;
+    case UNIT_INCLUDES_BLOCK_ID:
+      Reader.IncludeCursor = Stream;
+      if (Reader.IncludeCursor.EnterSubBlock(ID)) {
+        *Error = "malformed unit includes block record";
+        return StreamVisit::Abort;
+      }
+      readBlockAbbrevs(Reader.IncludeCursor);
+      return StreamVisit::Skip;
+    }
+
+    // Some newly introduced block in a minor version update that we cannot
+    // handle.
+    return StreamVisit::Skip;
+  }
+
+  StreamVisit visitRecord(unsigned BlockID, unsigned RecID,
+                          RecordDataImpl &Record, StringRef Blob) {
+    switch (BlockID) {
+    case UNIT_VERSION_BLOCK_ID: {
+      unsigned StoreFormatVersion = Record[0];
+      if (StoreFormatVersion != STORE_FORMAT_VERSION) {
+        llvm::raw_string_ostream OS(*Error);
+        OS << "Store format version mismatch: " << StoreFormatVersion;
+        OS << " , expected: " << STORE_FORMAT_VERSION;
+        return StreamVisit::Abort;
+      }
+      break;
+    }
+
+    case UNIT_INFO_BLOCK_ID: {
+      assert(RecID == UNIT_INFO);
+      unsigned I = 0;
+      Reader.IsSystemUnit = Record[I++];
+
+      // Save these to lookup them up after we get the paths buffer.
+      WorkDirOffset = Record[I++];
+      WorkDirSize = Record[I++];
+      OutputFileOffset = Record[I++];
+      OutputFileSize = Record[I++];
+      SysrootOffset = Record[I++];
+      SysrootSize = Record[I++];
+      MainPathIndex = (int)Record[I++] - 1;
+      Reader.IsDebugCompilation = Record[I++];
+      Reader.IsModuleUnit = Record[I++];
+
+      size_t moduleNameSize = Record[I++];
+      size_t providerIdentifierSize = Record[I++];
+      size_t providerVersionSize = Record[I++];
+      I++; // Reserved for ProviderDataVersion.
+      Reader.ModuleName = Blob.substr(0, moduleNameSize);
+      Blob = Blob.drop_front(moduleNameSize);
+      Reader.ProviderIdentifier = Blob.substr(0, providerIdentifierSize);
+      Blob = Blob.drop_front(providerIdentifierSize);
+      Reader.ProviderVersion = Blob.substr(0, providerVersionSize);
+      Reader.Target = Blob.drop_front(providerVersionSize);
+      break;
+    }
+
+    case UNIT_PATHS_BLOCK_ID:
+      switch (RecID) {
+      case UNIT_PATH:
+        {
+          unsigned I = 0;
+          UnitFilePathPrefixKind Kind = (UnitFilePathPrefixKind)Record[I++];
+          size_t DirOffset = Record[I++];
+          size_t DirSize = Record[I++];
+          size_t FilenameOffset = Record[I++];
+          size_t FilenameSize = Record[I++];
+
+          Reader.Paths.emplace_back(Kind, BitPathComponent(DirOffset, DirSize),
+                                  BitPathComponent(FilenameOffset, FilenameSize));
+        }
+        break;
+      case UNIT_PATH_BUFFER:
+        Reader.PathsBuffer = Blob;
+        Reader.WorkingDir = Reader.getPathFromBuffer(WorkDirOffset, WorkDirSize);
+        Reader.OutputFile = Reader.getPathFromBuffer(OutputFileOffset, OutputFileSize);
+        Reader.SysrootPath = Reader.getPathFromBuffer(SysrootOffset, SysrootSize);
+
+        // now we can populate the main file's path
+        Reader.constructFilePath(Reader.MainFilePath, MainPathIndex);
+        break;
+      default:
+          llvm_unreachable("shouldn't visit this record");
+      }
+      break;
+
+    case UNIT_MODULES_BLOCK_ID:
+      switch (RecID) {
+      case UNIT_MODULE:
+        {
+          unsigned I = 0;
+          unsigned NameOffset = Record[I++];
+          unsigned NameSize = Record[I++];
+          Reader.Modules.push_back({NameOffset, NameSize});
+        }
+        break;
+      case UNIT_MODULE_BUFFER:
+        Reader.ModuleNamesBuffer = Blob;
+        break;
+      default:
+          llvm_unreachable("shouldn't visit this record");
+      }
+      break;
+
+    case UNIT_DEPENDENCIES_BLOCK_ID:
+    case UNIT_INCLUDES_BLOCK_ID:
+      llvm_unreachable("shouldn't visit this block'");
+    }
+    return StreamVisit::Continue;
+  }
+};
+
+typedef std::function<bool(RecordDataImpl& Record, StringRef Blob)>
+  BlockVisitorCallback;
+
+class IndexUnitBlockBitstreamVisitor : public BitstreamVisitor<IndexUnitBlockBitstreamVisitor> {
+  unsigned RecID;
+  BlockVisitorCallback Visit;
+
+public:
+  IndexUnitBlockBitstreamVisitor(unsigned RecID,
+                                 llvm::BitstreamCursor &BlockStream,
+                                 BlockVisitorCallback Visit)
+  : BitstreamVisitor(BlockStream), RecID(RecID), Visit(std::move(Visit)) {}
+
+  StreamVisit visitRecord(unsigned BlockID, unsigned RecID,
+                          RecordDataImpl &Record, StringRef Blob) {
+    if (RecID != this->RecID)
+      llvm_unreachable("shouldn't be called with this RecID");
+
+    if (Visit(Record, Blob))
+      return StreamVisit::Continue;
+    return StreamVisit::Abort;
+  }
+};
+
+} // anonymous namespace
+
+bool IndexUnitReaderImpl::init(std::unique_ptr<MemoryBuffer> Buf,
+                               sys::TimePoint<> ModTime, std::string &Error) {
+  this->ModTime = ModTime;
+  this->MemBuf = std::move(Buf);
+  llvm::BitstreamCursor Stream(*MemBuf);
+
+  // Sniff for the signature.
+  if (Stream.Read(8) != 'I' ||
+      Stream.Read(8) != 'D' ||
+      Stream.Read(8) != 'X' ||
+      Stream.Read(8) != 'U') {
+    Error = "not a serialized index unit file";
+    return true;
+  }
+
+  IndexUnitBitstreamVisitor BitVisitor(Stream, *this);
+  return !BitVisitor.visit(Error);
+}
+
+/// Unit dependencies are provided ahead of record ones, record ones
+/// ahead of the file ones.
+bool IndexUnitReaderImpl::foreachDependency(DependencyReceiver Receiver) {
+  store::SavedStreamPosition SavedDepPosition(DependCursor);
+  IndexUnitBlockBitstreamVisitor Visitor(UNIT_DEPENDENCY, DependCursor,
+  [&](RecordDataImpl& Record, StringRef Blob) {
+    unsigned I = 0;
+    UnitDependencyKind UnitDepKind = (UnitDependencyKind)Record[I++];
+    bool IsSystem = Record[I++];
+    int PathIndex = (int)Record[I++] - 1;
+    int ModuleIndex = (int)Record[I++] - 1;
+    time_t ModTime = (time_t)Record[I++];
+    size_t FileSize = Record[I++];
+    StringRef Name = Blob;
+
+    IndexUnitReader::DependencyKind DepKind;
+    switch (UnitDepKind) {
+      case UNIT_DEPEND_KIND_UNIT:
+        DepKind = IndexUnitReader::DependencyKind::Unit; break;
+      case UNIT_DEPEND_KIND_RECORD:
+        DepKind = IndexUnitReader::DependencyKind::Record; break;
+      case UNIT_DEPEND_KIND_FILE:
+        DepKind = IndexUnitReader::DependencyKind::File; break;
+    }
+
+    SmallString<512> PathBuf;
+    this->constructFilePath(PathBuf, PathIndex);
+    StringRef ModuleName = this->getModuleName(ModuleIndex);
+
+    return Receiver(IndexUnitReader::DependencyInfo{DepKind, IsSystem, Name,
+      PathBuf.str(), ModuleName, FileSize, ModTime});
+  });
+
+  std::string Error;
+  return Visitor.visit(Error);
+}
+
+bool IndexUnitReaderImpl::foreachInclude(IncludeReceiver Receiver) {
+  store::SavedStreamPosition SavedIncPosition(IncludeCursor);
+  IndexUnitBlockBitstreamVisitor Visitor(UNIT_INCLUDE, IncludeCursor,
+  [&](RecordDataImpl& Record, StringRef Blob) {
+    unsigned I = 0;
+    int SourcePathIndex = (int)Record[I++] - 1;
+    unsigned Line = Record[I++];
+    int TargetPathIndex = (int)Record[I++] - 1;
+
+    SmallString<512> SourceBuf, TargetBuf;
+    this->constructFilePath(SourceBuf, SourcePathIndex);
+    this->constructFilePath(TargetBuf, TargetPathIndex);
+    return Receiver(IndexUnitReader::IncludeInfo{SourceBuf.str(), Line, TargetBuf.str()});
+  });
+
+  std::string Error;
+  return Visitor.visit(Error);
+}
+
+
+void IndexUnitReaderImpl::constructFilePath(SmallVectorImpl<char> &PathBuf,
+                       int PathIndex) {
+
+  if (PathIndex < 0) return;
+  FileBitPath &Path = Paths[PathIndex];
+  StringRef Prefix;
+  switch (Path.PrefixKind) {
+  case UNIT_PATH_PREFIX_NONE:
+    break;
+  case UNIT_PATH_PREFIX_WORKDIR:
+    Prefix = getWorkingDirectory();
+    break;
+  case UNIT_PATH_PREFIX_SYSROOT:
+    Prefix = getSysrootPath();
+    break;
+  }
+  PathBuf.append(Prefix.begin(), Prefix.end());
+  sys::path::append(PathBuf,
+                    getPathFromBuffer(Path.Dir.Offset, Path.Dir.Size),
+                    getPathFromBuffer(Path.Filename.Offset, Path.Filename.Size));
+}
+
+StringRef IndexUnitReaderImpl::getModuleName(int ModuleIndex) {
+  if (ModuleIndex < 0)
+    return StringRef();
+  auto &ModInfo = Modules[ModuleIndex];
+  return StringRef(ModuleNamesBuffer.data()+ModInfo.NameOffset, ModInfo.NameSize);
+}
+
+
+//===----------------------------------------------------------------------===//
+// IndexUnitReader
+//===----------------------------------------------------------------------===//
+
+std::unique_ptr<IndexUnitReader>
+IndexUnitReader::createWithUnitFilename(StringRef UnitFilename,
+                                        StringRef StorePath,
+                                        std::string &Error) {
+  SmallString<128> PathBuf = StorePath;
+  appendUnitSubDir(PathBuf);
+  sys::path::append(PathBuf, UnitFilename);
+  return createWithFilePath(PathBuf.str(), Error);
+}
+
+std::unique_ptr<IndexUnitReader>
+IndexUnitReader::createWithFilePath(StringRef FilePath, std::string &Error) {
+  int FD;
+  std::error_code EC = sys::fs::openFileForRead(FilePath, FD);
+  if (EC) {
+    raw_string_ostream(Error) << "Failed opening '" << FilePath << "': "
+      << EC.message();
+    return nullptr;
+  }
+
+  assert(FD != -1);
+  struct AutoFDClose {
+    int FD;
+    AutoFDClose(int FD) : FD(FD) {}
+    ~AutoFDClose() {
+      ::close(FD);
+    }
+  } AutoFDClose(FD);
+
+  sys::fs::file_status FileStat;
+  EC = sys::fs::status(FD, FileStat);
+  if (EC) {
+    Error = EC.message();
+    return nullptr;
+  }
+
+  auto ErrOrBuf = MemoryBuffer::getOpenFile(FD, FilePath, /*FileSize=*/-1,
+                                            /*RequiresNullTerminator=*/false);
+  if (!ErrOrBuf) {
+    raw_string_ostream(Error) << "Failed opening '" << FilePath << "': "
+      << ErrOrBuf.getError().message();
+    return nullptr;
+  }
+
+  std::unique_ptr<IndexUnitReaderImpl> Impl(new IndexUnitReaderImpl());
+  bool Err = Impl->init(std::move(*ErrOrBuf), FileStat.getLastModificationTime(),
+                        Error);
+  if (Err)
+    return nullptr;
+
+  std::unique_ptr<IndexUnitReader> Reader;
+  Reader.reset(new IndexUnitReader(Impl.release()));
+  return Reader;
+}
+
+Optional<sys::TimePoint<>>
+IndexUnitReader::getModificationTimeForUnit(StringRef UnitFilename,
+                                            StringRef StorePath,
+                                            std::string &Error) {
+  SmallString<128> PathBuf = StorePath;
+  appendUnitSubDir(PathBuf);
+  sys::path::append(PathBuf, UnitFilename);
+
+  sys::fs::file_status FileStat;
+  std::error_code EC = sys::fs::status(PathBuf.str(), FileStat);
+  if (EC) {
+    Error = EC.message();
+    return None;
+  }
+  return FileStat.getLastModificationTime();
+}
+
+#define IMPL static_cast<IndexUnitReaderImpl*>(Impl)
+
+IndexUnitReader::~IndexUnitReader() {
+  delete IMPL;
+}
+
+StringRef IndexUnitReader::getProviderIdentifier() const {
+  return IMPL->getProviderIdentifier();
+}
+
+StringRef IndexUnitReader::getProviderVersion() const {
+  return IMPL->getProviderVersion();
+}
+
+llvm::sys::TimePoint<> IndexUnitReader::getModificationTime() const {
+  return IMPL->getModificationTime();
+}
+
+StringRef IndexUnitReader::getWorkingDirectory() const {
+  return IMPL->getWorkingDirectory();
+}
+
+StringRef IndexUnitReader::getOutputFile() const {
+  return IMPL->getOutputFile();
+}
+
+StringRef IndexUnitReader::getSysrootPath() const {
+  return IMPL->getSysrootPath();
+}
+
+StringRef IndexUnitReader::getMainFilePath() const {
+  return IMPL->getMainFilePath();
+}
+
+StringRef IndexUnitReader::getModuleName() const {
+  return IMPL->getModuleName();
+}
+
+StringRef IndexUnitReader::getTarget() const {
+  return IMPL->getTarget();
+}
+
+bool IndexUnitReader::hasMainFile() const {
+  return IMPL->hasMainFile();
+}
+
+bool IndexUnitReader::isSystemUnit() const {
+  return IMPL->isSystemUnit();
+}
+
+bool IndexUnitReader::isModuleUnit() const {
+  return IMPL->isModuleUnit();
+}
+
+bool IndexUnitReader::isDebugCompilation() const {
+  return IMPL->isDebugCompilation();
+}
+
+/// \c Index is the index in the \c getDependencies array.
+/// Unit dependencies are provided ahead of record ones.
+bool IndexUnitReader::foreachDependency(DependencyReceiver Receiver) {
+  return IMPL->foreachDependency(std::move(Receiver));
+}
+
+bool IndexUnitReader::foreachInclude(IncludeReceiver Receiver) {
+  return IMPL->foreachInclude(std::move(Receiver));
+}
diff --git a/lib/Index/IndexUnitWriter.cpp b/lib/Index/IndexUnitWriter.cpp
new file mode 100644
index 0000000..7c981ae
--- /dev/null
+++ b/lib/Index/IndexUnitWriter.cpp
@@ -0,0 +1,628 @@
+//===--- IndexUnitWriter.cpp - Index unit serialization -------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Index/IndexUnitWriter.h"
+#include "IndexDataStoreUtils.h"
+#include "clang/Basic/FileManager.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::index;
+using namespace clang::index::store;
+using namespace llvm;
+
+
+class IndexUnitWriter::PathStorage {
+  std::string WorkDir;
+  std::string SysrootPath;
+  SmallString<512> PathsBuf;
+  StringMap<DirBitPath, BumpPtrAllocator> Dirs;
+  std::vector<FileBitPath> FileBitPaths;
+  DenseMap<const FileEntry *, size_t> FileToIndex;
+
+public:
+  PathStorage(StringRef workDir, StringRef sysrootPath) {
+    WorkDir = workDir;
+    if (sysrootPath == "/")
+      sysrootPath = StringRef();
+    SysrootPath = sysrootPath;
+  }
+
+  StringRef getPathsBuffer() const { return PathsBuf.str(); }
+
+  ArrayRef<FileBitPath> getBitPaths() const { return FileBitPaths; }
+
+  int getPathIndex(const FileEntry *FE) {
+    if (!FE)
+      return -1;
+    auto Pair = FileToIndex.insert(std::make_pair(FE, FileBitPaths.size()));
+    bool IsNew = Pair.second;
+    size_t Index = Pair.first->getSecond();
+
+    if (IsNew) {
+      StringRef Filename = sys::path::filename(FE->getName());
+      DirBitPath Dir = getDirBitPath(sys::path::parent_path(FE->getName()));
+      FileBitPaths.emplace_back(Dir.PrefixKind, Dir.Dir,
+                                BitPathComponent(getPathOffset(Filename),
+                                                 Filename.size()));
+    }
+    return Index;
+  }
+
+  size_t getPathOffset(StringRef Path) {
+    if (Path.empty())
+      return 0;
+    size_t offset = PathsBuf.size();
+    PathsBuf += Path;
+    return offset;
+  }
+  
+private:
+  DirBitPath getDirBitPath(StringRef dirStr) {
+    auto pair = Dirs.insert(std::make_pair(dirStr, DirBitPath()));
+    bool isNew = pair.second;
+    auto &dirPath = pair.first->second;
+
+    if (isNew) {
+      if (isPathInDir(SysrootPath, dirStr)) {
+        dirPath.PrefixKind = UNIT_PATH_PREFIX_SYSROOT;
+        dirStr = dirStr.drop_front(SysrootPath.size());
+        while (!dirStr.empty() && dirStr[0] == '/')
+          dirStr = dirStr.drop_front();
+      } else if (isPathInDir(WorkDir, dirStr)) {
+        dirPath.PrefixKind = UNIT_PATH_PREFIX_WORKDIR;
+        dirStr = dirStr.drop_front(WorkDir.size());
+        while (!dirStr.empty() && dirStr[0] == '/')
+          dirStr = dirStr.drop_front();
+      }
+      dirPath.Dir.Offset = getPathOffset(dirStr);
+      dirPath.Dir.Size = dirStr.size();
+    }
+    return dirPath;
+  }
+
+  static bool isPathInDir(StringRef dir, StringRef path) {
+    if (dir.empty() || !path.startswith(dir))
+      return false;
+    StringRef rest = path.drop_front(dir.size());
+    return !rest.empty() && sys::path::is_separator(rest.front());
+  }
+};
+
+IndexUnitWriter::IndexUnitWriter(FileManager &FileMgr,
+                                 StringRef StorePath,
+                                 StringRef ProviderIdentifier,
+                                 StringRef ProviderVersion,
+                                 StringRef OutputFile,
+                                 StringRef ModuleName,
+                                 const FileEntry *MainFile,
+                                 bool IsSystem,
+                                 bool IsModuleUnit,
+                                 bool IsDebugCompilation,
+                                 StringRef TargetTriple,
+                                 StringRef SysrootPath,
+                                 writer::ModuleInfoWriterCallback GetInfoForModule)
+: FileMgr(FileMgr) {
+  this->UnitsPath = StorePath;
+  store::appendUnitSubDir(this->UnitsPath);
+  this->ProviderIdentifier = ProviderIdentifier;
+  this->ProviderVersion = ProviderVersion;
+  this->OutputFile = OutputFile;
+  this->ModuleName = ModuleName;
+  this->MainFile = MainFile;
+  this->IsSystemUnit = IsSystem;
+  this->IsModuleUnit = IsModuleUnit;
+  this->IsDebugCompilation = IsDebugCompilation;
+  this->TargetTriple = TargetTriple;
+  this->SysrootPath = SysrootPath;
+  this->GetInfoForModuleFn = GetInfoForModule;
+}
+
+IndexUnitWriter::~IndexUnitWriter() {}
+
+int IndexUnitWriter::addModule(writer::OpaqueModule Mod) {
+  if (!Mod)
+    return -1;
+
+  auto Pair = IndexByModule.insert(std::make_pair(Mod, Modules.size()));
+  bool WasInserted = Pair.second;
+  if (WasInserted) {
+    Modules.push_back(Mod);
+  }
+  return Pair.first->second;
+}
+
+int IndexUnitWriter::addFileDependency(const FileEntry *File, bool IsSystem,
+                                       writer::OpaqueModule Mod) {
+  assert(File);
+  auto Pair = IndexByFile.insert(std::make_pair(File, Files.size()));
+  bool WasInserted = Pair.second;
+  if (WasInserted) {
+    Files.push_back(FileEntryData{File, IsSystem, addModule(Mod), {}});
+  }
+  return Pair.first->second;
+}
+
+void IndexUnitWriter::addRecordFile(StringRef RecordFile, const FileEntry *File,
+                                    bool IsSystem, writer::OpaqueModule Mod) {
+  int Dep = File ? addFileDependency(File, IsSystem, /*module=*/nullptr) : -1;
+  Records.push_back(RecordOrUnitData{RecordFile, Dep, addModule(Mod), IsSystem});
+}
+
+void IndexUnitWriter::addASTFileDependency(const FileEntry *File, bool IsSystem,
+                                           writer::OpaqueModule Mod,
+                                           bool withoutUnitName) {
+  assert(File);
+  if (!SeenASTFiles.insert(File).second)
+    return;
+
+  SmallString<64> UnitName;
+  if (!withoutUnitName)
+    getUnitNameForOutputFile(File->getName(), UnitName);
+  addUnitDependency(UnitName.str(), File, IsSystem, Mod);
+}
+
+void IndexUnitWriter::addUnitDependency(StringRef UnitFile,
+                                        const FileEntry *File, bool IsSystem,
+                                        writer::OpaqueModule Mod) {
+  int Dep = File ? addFileDependency(File, IsSystem, /*module=*/nullptr) : -1;
+  ASTFileUnits.emplace_back(RecordOrUnitData{UnitFile, Dep, addModule(Mod), IsSystem});
+}
+
+bool IndexUnitWriter::addInclude(const FileEntry *Source, unsigned Line,
+                                 const FileEntry *Target) {
+  // FIXME: This will ignore includes of headers that resolve to module imports
+  // because the 'target' header has not been added as a file dependency earlier
+  // so it is missing from \c IndexByFile.
+
+  auto It = IndexByFile.find(Source);
+  if (It == IndexByFile.end())
+    return false;
+  int SourceIndex = It->getSecond();
+  It = IndexByFile.find(Target);
+  if (It == IndexByFile.end())
+    return false;
+  int TargetIndex = It->getSecond();
+  Files[SourceIndex].Includes.emplace_back(FileInclude{TargetIndex, Line});
+  return true;
+};
+
+void IndexUnitWriter::getUnitNameForOutputFile(StringRef FilePath,
+                                               SmallVectorImpl<char> &Str) {
+  SmallString<256> AbsPath(FilePath);
+  FileMgr.makeAbsolutePath(AbsPath);
+  return getUnitNameForAbsoluteOutputFile(AbsPath, Str);
+}
+
+void IndexUnitWriter::getUnitPathForOutputFile(StringRef FilePath,
+                                               SmallVectorImpl<char> &Str) {
+  Str.append(UnitsPath.begin(), UnitsPath.end());
+  Str.push_back('/');
+  return getUnitNameForOutputFile(FilePath, Str);
+}
+
+Optional<bool> IndexUnitWriter::isUnitUpToDateForOutputFile(StringRef FilePath,
+                                                            Optional<StringRef> TimeCompareFilePath,
+                                                            std::string &Error) {
+  SmallString<256> UnitPath;
+  getUnitPathForOutputFile(FilePath, UnitPath);
+
+  llvm::sys::fs::file_status UnitStat;
+  if (std::error_code EC = llvm::sys::fs::status(UnitPath.c_str(), UnitStat)) {
+    if (EC != llvm::errc::no_such_file_or_directory) {
+      llvm::raw_string_ostream Err(Error);
+      Err << "could not access path '" << UnitPath
+          << "': " << EC.message();
+      return None;
+    }
+    return false;
+  }
+
+  if (!TimeCompareFilePath.hasValue())
+    return true;
+
+  llvm::sys::fs::file_status CompareStat;
+  if (std::error_code EC = llvm::sys::fs::status(*TimeCompareFilePath, CompareStat)) {
+    if (EC != llvm::errc::no_such_file_or_directory) {
+      llvm::raw_string_ostream Err(Error);
+      Err << "could not access path '" << *TimeCompareFilePath
+          << "': " << EC.message();
+      return None;
+    }
+    return true;
+  }
+
+  // Return true (unit is up-to-date) if the file to compare is older than the
+  // unit file.
+  return CompareStat.getLastModificationTime() <= UnitStat.getLastModificationTime();
+}
+
+void IndexUnitWriter::getUnitNameForAbsoluteOutputFile(StringRef FilePath,
+                                                   SmallVectorImpl<char> &Str) {
+  StringRef Fname = sys::path::filename(FilePath);
+  Str.append(Fname.begin(), Fname.end());
+  Str.push_back('-');
+  llvm::hash_code PathHashVal = llvm::hash_value(FilePath);
+  llvm::APInt(64, PathHashVal).toString(Str, 36, /*Signed=*/false);
+}
+
+static void writeBlockInfo(BitstreamWriter &Stream) {
+  RecordData Record;
+
+  Stream.EnterBlockInfoBlock();
+#define BLOCK(X) emitBlockID(X ## _ID, #X, Stream, Record)
+#define RECORD(X) emitRecordID(X, #X, Stream, Record)
+
+  BLOCK(UNIT_VERSION_BLOCK);
+  RECORD(UNIT_VERSION);
+
+  BLOCK(UNIT_INFO_BLOCK);
+  RECORD(UNIT_INFO);
+
+  BLOCK(UNIT_DEPENDENCIES_BLOCK);
+  RECORD(UNIT_DEPENDENCY);
+
+  BLOCK(UNIT_INCLUDES_BLOCK);
+  RECORD(UNIT_INCLUDE);
+
+  BLOCK(UNIT_PATHS_BLOCK);
+  RECORD(UNIT_PATH);
+  RECORD(UNIT_PATH_BUFFER);
+
+  BLOCK(UNIT_MODULES_BLOCK);
+  RECORD(UNIT_MODULE);
+  RECORD(UNIT_MODULE_BUFFER);
+
+#undef RECORD
+#undef BLOCK
+  Stream.ExitBlock();
+}
+
+static void writeVersionInfo(BitstreamWriter &Stream) {
+  using namespace llvm::sys;
+
+  Stream.EnterSubblock(UNIT_VERSION_BLOCK_ID, 3);
+
+  auto Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(UNIT_VERSION));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Store format version
+  unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
+
+  RecordData Record;
+  Record.push_back(UNIT_VERSION);
+  Record.push_back(STORE_FORMAT_VERSION);
+  Stream.EmitRecordWithAbbrev(AbbrevCode, Record);
+
+  Stream.ExitBlock();
+}
+
+bool IndexUnitWriter::write(std::string &Error) {
+  using namespace llvm::sys;
+
+  // Determine the working directory.
+  SmallString<128> CWDPath;
+  if (!FileMgr.getFileSystemOpts().WorkingDir.empty()) {
+    CWDPath = FileMgr.getFileSystemOpts().WorkingDir;
+    if (!path::is_absolute(CWDPath)) {
+      fs::make_absolute(CWDPath);
+    }
+  } else {
+    std::error_code EC = sys::fs::current_path(CWDPath);
+    if (EC) {
+      llvm::raw_string_ostream Err(Error);
+      Err << "failed to determine current working directory: " << EC.message();
+      return true;
+    }
+  }
+  WorkDir = CWDPath.str();
+
+  SmallString<512> Buffer;
+  BitstreamWriter Stream(Buffer);
+  Stream.Emit('I', 8);
+  Stream.Emit('D', 8);
+  Stream.Emit('X', 8);
+  Stream.Emit('U', 8);
+
+  PathStorage PathStore(WorkDir, SysrootPath);
+
+  writeBlockInfo(Stream);
+  writeVersionInfo(Stream);
+  writeUnitInfo(Stream, PathStore);
+  writeDependencies(Stream, PathStore);
+  writeIncludes(Stream, PathStore);
+  writePaths(Stream, PathStore);
+  writeModules(Stream);
+
+  SmallString<256> UnitPath;
+  getUnitPathForOutputFile(OutputFile, UnitPath);
+
+  SmallString<128> TempPath;
+  TempPath = path::parent_path(UnitsPath);
+  TempPath += '/';
+  TempPath += path::filename(UnitPath);
+  TempPath += "-%%%%%%%%";
+  int TempFD;
+  if (llvm::sys::fs::createUniqueFile(TempPath.str(), TempFD, TempPath)) {
+    llvm::raw_string_ostream Err(Error);
+    Err << "failed to create temporary file: " << TempPath;
+    return true;
+  }
+
+  raw_fd_ostream OS(TempFD, /*shouldClose=*/true);
+  OS.write(Buffer.data(), Buffer.size());
+  OS.close();
+
+  std::error_code EC = fs::rename(/*from=*/TempPath.c_str(), /*to=*/UnitPath.c_str());
+  if (EC) {
+    llvm::raw_string_ostream Err(Error);
+    Err << "failed to rename '" << TempPath << "' to '" << UnitPath << "': " << EC.message();
+    return true;
+  }
+
+  return false;
+}
+
+void IndexUnitWriter::writeUnitInfo(llvm::BitstreamWriter &Stream,
+                                    PathStorage &PathStore) {
+  Stream.EnterSubblock(UNIT_INFO_BLOCK_ID, 3);
+
+  auto Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(UNIT_INFO));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystemUnit
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // WorkDir offset
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // WorkDir size
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // OutputFile offset
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // OutputFile size
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // Sysroot offset
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // Sysroot size
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // Main path id
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsDebugCompilation
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsModuleUnit
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // Module name size
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // ProviderIdentifier size
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // ProviderVersion size
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 5)); // ProviderDataVersion
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Module name + ProviderIdentifier + ProviderVersion + target triple
+  unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
+
+  RecordData Record;
+  Record.push_back(UNIT_INFO);
+  Record.push_back(IsSystemUnit);
+  Record.push_back(PathStore.getPathOffset(WorkDir));
+  Record.push_back(WorkDir.size());
+  Record.push_back(PathStore.getPathOffset(OutputFile));
+  Record.push_back(OutputFile.size());
+  Record.push_back(PathStore.getPathOffset(SysrootPath));
+  Record.push_back(SysrootPath.size());
+  Record.push_back(PathStore.getPathIndex(MainFile) + 1); // Make 1-based with 0=invalid
+  Record.push_back(IsDebugCompilation);
+  Record.push_back(IsModuleUnit);
+  Record.push_back(ModuleName.size());
+  Record.push_back(ProviderIdentifier.size());
+  Record.push_back(ProviderVersion.size());
+  // ProviderDataVersion is reserved. Not sure it is a good to idea to have
+  // clients consider the specifics of a 'provider data version', but reserving
+  // to avoid store format version change in case there is a use case in the
+  // future.
+  Record.push_back(0); // ProviderDataVersion
+  SmallString<128> InfoStrings;
+  InfoStrings += ModuleName;
+  InfoStrings += ProviderIdentifier;
+  InfoStrings += ProviderVersion;
+  InfoStrings += TargetTriple;
+  Stream.EmitRecordWithBlob(AbbrevCode, Record, InfoStrings);
+
+  Stream.ExitBlock();
+}
+
+void IndexUnitWriter::writeDependencies(llvm::BitstreamWriter &Stream,
+                                        PathStorage &PathStore) {
+  std::vector<bool> FileUsedForRecordOrUnit;
+  FileUsedForRecordOrUnit.resize(Files.size());
+
+  Stream.EnterSubblock(UNIT_DEPENDENCIES_BLOCK_ID, 3);
+
+  auto Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(UNIT_DEPENDENCY));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, UnitDependencyKindBitNum)); // Dependency kind
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // IsSystem
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // PathIndex (1-based, 0 = none)
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // ModuleIndex (1-based, 0 = none)
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // time_t
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // file size
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name
+  unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
+
+  RecordData Record;
+
+  auto addRecordOrUnitData = [&](UnitDependencyKind K, const RecordOrUnitData &Data) {
+    Record.push_back(UNIT_DEPENDENCY);
+    Record.push_back(K);
+    Record.push_back(Data.IsSystem);
+    if (Data.FileIndex != -1) {
+      Record.push_back(PathStore.getPathIndex(Files[Data.FileIndex].File) + 1);
+      FileUsedForRecordOrUnit[Data.FileIndex] = true;
+    } else {
+      Record.push_back(0);
+    }
+    if (Data.ModuleIndex != -1) {
+      Record.push_back(Data.ModuleIndex + 1);
+    } else {
+      Record.push_back(0);
+    }
+    if (Data.FileIndex != -1) {
+      Record.push_back(Files[Data.FileIndex].File->getModificationTime());
+      Record.push_back(Files[Data.FileIndex].File->getSize());
+    } else {
+      Record.push_back(0);
+      Record.push_back(0);
+    }
+    Stream.EmitRecordWithBlob(AbbrevCode, Record, Data.Name);
+  };
+
+  for (auto &ASTData : ASTFileUnits) {
+    Record.clear();
+    addRecordOrUnitData(UNIT_DEPEND_KIND_UNIT, ASTData);
+  }
+  for (auto &recordData : Records) {
+    Record.clear();
+    addRecordOrUnitData(UNIT_DEPEND_KIND_RECORD, recordData);
+  }
+  size_t FileIndex = 0;
+  for (auto &File : Files) {
+    if (FileUsedForRecordOrUnit[FileIndex++])
+      continue;
+    Record.clear();
+    Record.push_back(UNIT_DEPENDENCY);
+    Record.push_back(UNIT_DEPEND_KIND_FILE);
+    Record.push_back(File.IsSystem);
+    Record.push_back(PathStore.getPathIndex(File.File) + 1);
+    if (File.ModuleIndex != -1) {
+      Record.push_back(File.ModuleIndex + 1);
+    } else {
+      Record.push_back(0);
+    }
+    Record.push_back(File.File->getModificationTime());
+    Record.push_back(File.File->getSize());
+    Stream.EmitRecordWithBlob(AbbrevCode, Record, StringRef());
+  }
+
+  Stream.ExitBlock();
+}
+
+void IndexUnitWriter::writeIncludes(llvm::BitstreamWriter &Stream,
+                                    PathStorage &PathStore) {
+  Stream.EnterSubblock(UNIT_INCLUDES_BLOCK_ID, 3);
+
+  auto Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(UNIT_INCLUDE));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // source path index (1-based, 0 = no path)
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // source include line
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // target path index (1-based, 0 = no path)
+  unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
+
+  RecordData Record;
+
+  for (auto &Including : Files) {
+    for(auto &Included: Including.Includes) {
+      Record.clear();
+      Record.push_back(UNIT_INCLUDE);
+      Record.push_back(PathStore.getPathIndex(Including.File) + 1);
+      Record.push_back(Included.Line);
+      Record.push_back(PathStore.getPathIndex(Files[Included.Index].File) + 1);
+      Stream.EmitRecordWithAbbrev(AbbrevCode, Record);
+    }
+  }
+  Stream.ExitBlock();
+}
+
+void IndexUnitWriter::writePaths(llvm::BitstreamWriter &Stream,
+                                 PathStorage &PathStore) {
+  Stream.EnterSubblock(UNIT_PATHS_BLOCK_ID, 3);
+
+  auto PathAbbrev = std::make_shared<BitCodeAbbrev>();
+  PathAbbrev->Add(BitCodeAbbrevOp(UNIT_PATH));
+  PathAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, UnitFilePathPrefixKindBitNum)); // Path prefix kind
+  PathAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // DirPath offset
+  PathAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // DirPath size
+  PathAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 10)); // Filename offset
+  PathAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Filename size
+  unsigned PathAbbrevCode = Stream.EmitAbbrev(std::move(PathAbbrev));
+
+  auto PathBufferAbbrev = std::make_shared<BitCodeAbbrev>();
+  PathBufferAbbrev->Add(BitCodeAbbrevOp(UNIT_PATH_BUFFER));
+  PathBufferAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Paths buffer
+  unsigned PathBufferAbbrevCode = Stream.EmitAbbrev(PathBufferAbbrev);
+
+  RecordData Record;
+  for(auto &BitPath: PathStore.getBitPaths()) {
+    Record.push_back(UNIT_PATH);
+    Record.push_back(BitPath.PrefixKind);
+    Record.push_back(BitPath.Dir.Offset);
+    Record.push_back(BitPath.Dir.Size);
+    Record.push_back(BitPath.Filename.Offset);
+    Record.push_back(BitPath.Filename.Size);
+    Stream.EmitRecordWithAbbrev(PathAbbrevCode, Record);
+    Record.clear();
+  }
+
+  Record.push_back(UNIT_PATH_BUFFER);
+  Stream.EmitRecordWithBlob(PathBufferAbbrevCode, Record, PathStore.getPathsBuffer());
+
+  Stream.ExitBlock();
+}
+
+void IndexUnitWriter::writeModules(llvm::BitstreamWriter &Stream) {
+  Stream.EnterSubblock(UNIT_MODULES_BLOCK_ID, 3);
+
+  auto Abbrev = std::make_shared<BitCodeAbbrev>();
+  Abbrev->Add(BitCodeAbbrevOp(UNIT_MODULE));
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 9)); // Module name offset
+  Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Module name size
+  unsigned AbbrevCode = Stream.EmitAbbrev(std::move(Abbrev));
+
+  auto BufferAbbrev = std::make_shared<BitCodeAbbrev>();
+  BufferAbbrev->Add(BitCodeAbbrevOp(UNIT_MODULE_BUFFER));
+  BufferAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Module names buffer
+  unsigned BufferAbbrevCode = Stream.EmitAbbrev(BufferAbbrev);
+
+  SmallString<512> ModuleNamesBuf;
+
+  RecordData Record;
+  for (auto &Mod : Modules) {
+    SmallString<64> ModuleName;
+    StringRef name = GetInfoForModuleFn(Mod, ModuleName).Name;
+    size_t offset = ModuleNamesBuf.size();
+    ModuleNamesBuf += name;
+
+    Record.push_back(UNIT_MODULE);
+    Record.push_back(offset);
+    Record.push_back(name.size());
+    Stream.EmitRecordWithAbbrev(AbbrevCode, Record);
+    Record.clear();
+  }
+
+  Record.push_back(UNIT_MODULE_BUFFER);
+  Stream.EmitRecordWithBlob(BufferAbbrevCode, Record, ModuleNamesBuf.str());
+
+  Stream.ExitBlock();
+}
+
+bool IndexUnitWriter::initIndexDirectory(StringRef StorePath,
+                                         std::string &Error) {
+  using namespace llvm::sys;
+  SmallString<128> SubPath = StorePath;
+  store::appendRecordSubDir(SubPath);
+  std::error_code EC = fs::create_directories(SubPath);
+  if (EC) {
+    llvm::raw_string_ostream Err(Error);
+    Err << "failed to create directory '" << SubPath << "': " << EC.message();
+    return true;
+  }
+
+  SubPath = StorePath;
+  store::appendUnitSubDir(SubPath);
+  EC = fs::create_directory(SubPath);
+  if (EC) {
+    llvm::raw_string_ostream Err(Error);
+    Err << "failed to create directory '" << SubPath << "': " << EC.message();
+    return true;
+  }
+
+  return false;
+}
diff --git a/lib/Index/IndexingAction.cpp b/lib/Index/IndexingAction.cpp
index cac24d4..32da362 100644
--- a/lib/Index/IndexingAction.cpp
+++ b/lib/Index/IndexingAction.cpp
@@ -9,9 +9,16 @@
 
 #include "clang/Index/IndexingAction.h"
 #include "clang/Index/IndexDataConsumer.h"
+#include "FileIndexRecord.h"
 #include "IndexingContext.h"
+#include "ClangIndexRecordWriter.h"
+#include "IndexDataStoreUtils.h"
+#include "clang/Index/IndexUnitWriter.h"
+#include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/MultiplexConsumer.h"
+#include "clang/Frontend/Utils.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Serialization/ASTReader.h"
 
@@ -80,7 +87,8 @@
     : DataConsumer(std::move(dataConsumer)),
       IndexCtx(Opts, *DataConsumer) {}
 
-  std::unique_ptr<IndexASTConsumer> createIndexASTConsumer() {
+  std::unique_ptr<IndexASTConsumer> createIndexASTConsumer(CompilerInstance &CI) {
+    IndexCtx.setSysrootPath(CI.getHeaderSearchOpts().Sysroot);
     return llvm::make_unique<IndexASTConsumer>(IndexCtx);
   }
 
@@ -98,7 +106,7 @@
 protected:
   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
                                                  StringRef InFile) override {
-    return createIndexASTConsumer();
+    return createIndexASTConsumer(CI);
   }
 
   void EndSourceFileAction() override {
@@ -108,7 +116,7 @@
 };
 
 class WrappingIndexAction : public WrapperFrontendAction, IndexActionBase {
-  bool IndexActionFailed = false;
+  bool CreatedASTConsumer = false;
 
 public:
   WrappingIndexAction(std::unique_ptr<FrontendAction> WrappedAction,
@@ -128,21 +136,20 @@
 void WrappingIndexAction::EndSourceFileAction() {
   // Invoke wrapped action's method.
   WrapperFrontendAction::EndSourceFileAction();
-  if (!IndexActionFailed)
+  if (CreatedASTConsumer)
     finish();
 }
 
 std::unique_ptr<ASTConsumer>
 WrappingIndexAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
   auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
-  if (!OtherConsumer) {
-    IndexActionFailed = true;
+  if (!OtherConsumer)
     return nullptr;
-  }
 
+  CreatedASTConsumer = true;
   std::vector<std::unique_ptr<ASTConsumer>> Consumers;
   Consumers.push_back(std::move(OtherConsumer));
-  Consumers.push_back(createIndexASTConsumer());
+  Consumers.push_back(createIndexASTConsumer(CI));
   return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
 }
 
@@ -191,3 +198,628 @@
   }
   DataConsumer->finish();
 }
+
+//===----------------------------------------------------------------------===//
+// Index Data Recording
+//===----------------------------------------------------------------------===//
+
+namespace {
+
+class IndexDataRecorder : public IndexDataConsumer {
+  IndexingContext *IndexCtx = nullptr;
+  const Preprocessor *PP = nullptr;
+  typedef llvm::DenseMap<FileID, std::unique_ptr<FileIndexRecord>> RecordByFileTy;
+  RecordByFileTy RecordByFile;
+
+public:
+  void init(IndexingContext *idxCtx, const CompilerInstance &CI) {
+    IndexCtx = idxCtx;
+    PP = &CI.getPreprocessor();
+    initialize(CI.getASTContext());
+  }
+
+  RecordByFileTy::const_iterator record_begin() const { return RecordByFile.begin(); }
+  RecordByFileTy::const_iterator record_end() const { return RecordByFile.end(); }
+  bool record_empty() const { return RecordByFile.empty(); }
+
+private:
+  bool handleDeclOccurence(const Decl *D, SymbolRoleSet Roles,
+                           ArrayRef<SymbolRelation> Relations,
+                           FileID FID, unsigned Offset,
+                           ASTNodeInfo ASTNode) override {
+    // Ignore the predefines buffer.
+    if (FID == PP->getPredefinesFileID())
+      return true;
+
+    FileIndexRecord &Rec = getFileIndexRecord(FID);
+    Rec.addDeclOccurence(Roles, Offset, D, Relations);
+    return true;
+  }
+
+  FileIndexRecord &getFileIndexRecord(FileID FID) {
+    auto &Entry = RecordByFile[FID];
+    if (!Entry) {
+      Entry.reset(new FileIndexRecord(FID, IndexCtx->isSystemFile(FID)));
+    }
+    return *Entry;
+  }
+};
+
+struct IncludeLocation {
+  const FileEntry *Source;
+  const FileEntry *Target;
+  unsigned Line;
+};
+
+class IncludePPCallbacks : public PPCallbacks {
+  IndexingContext &IndexCtx;
+  RecordingOptions RecordOpts;
+  std::vector<IncludeLocation> &Includes;
+  SourceManager &SourceMgr;
+
+public:
+  IncludePPCallbacks(IndexingContext &indexCtx, RecordingOptions recordOpts,
+                     std::vector<IncludeLocation> &IncludesForFile,
+                     SourceManager &SourceMgr) :
+    IndexCtx(indexCtx), RecordOpts(recordOpts),
+    Includes(IncludesForFile), SourceMgr(SourceMgr) {}
+
+private:
+  void addInclude(SourceLocation From, const FileEntry *To) {
+    assert(To);
+    if (RecordOpts.RecordIncludes == RecordingOptions::IncludesRecordingKind::None)
+      return;
+
+    std::pair<FileID, unsigned> LocInfo = SourceMgr.getDecomposedExpansionLoc(From);
+    switch (RecordOpts.RecordIncludes) {
+      case RecordingOptions::IncludesRecordingKind::None:
+        llvm_unreachable("should have already checked in the beginning");
+      case RecordingOptions::IncludesRecordingKind::UserOnly:
+        if (IndexCtx.isSystemFile(LocInfo.first))
+          return; // Ignore includes of system headers.
+        break;
+      case RecordingOptions::IncludesRecordingKind::All:
+        break;
+    }
+    auto *FE = SourceMgr.getFileEntryForID(LocInfo.first);
+    if (!FE)
+      return;
+    auto lineNo = SourceMgr.getLineNumber(LocInfo.first, LocInfo.second);
+    Includes.push_back({FE, To, lineNo});
+  }
+
+  virtual void InclusionDirective(SourceLocation HashLoc,
+                                  const Token &IncludeTok,
+                                  StringRef FileName,
+                                  bool IsAngled,
+                                  CharSourceRange FilenameRange,
+                                  const FileEntry *File,
+                                  StringRef SearchPath,
+                                  StringRef RelativePath,
+                                  const Module *Imported) override {
+    if (HashLoc.isFileID() && File && File->isValid())
+      addInclude(HashLoc, File);
+  }
+};
+
+class IndexDependencyProvider {
+public:
+  virtual ~IndexDependencyProvider() {}
+
+  virtual void visitFileDependencies(const CompilerInstance &CI,
+      llvm::function_ref<void(const FileEntry *FE, bool isSystem)> visitor) = 0;
+  virtual void visitIncludes(
+                 llvm::function_ref<void(const FileEntry *Source, unsigned Line,
+                                         const FileEntry *Target)> visitor) = 0;
+  virtual void visitModuleImports(const CompilerInstance &CI,
+                 llvm::function_ref<void(serialization::ModuleFile &Mod,
+                                         bool isSystem)> visitor) = 0;
+};
+
+class SourceFilesIndexDependencyCollector : public DependencyCollector, public IndexDependencyProvider {
+  IndexingContext &IndexCtx;
+  RecordingOptions RecordOpts;
+  llvm::SetVector<const FileEntry *> Entries;
+  llvm::BitVector IsSystemByUID;
+  std::vector<IncludeLocation> Includes;
+  SourceManager *SourceMgr = nullptr;
+  std::string SysrootPath;
+
+public:
+  SourceFilesIndexDependencyCollector(IndexingContext &indexCtx, RecordingOptions recordOpts)
+    : IndexCtx(indexCtx), RecordOpts(recordOpts) {}
+
+  virtual void attachToPreprocessor(Preprocessor &PP) override {
+    DependencyCollector::attachToPreprocessor(PP);
+    PP.addPPCallbacks(llvm::make_unique<IncludePPCallbacks>(IndexCtx,
+                                                            RecordOpts,
+                                                            Includes,
+                                                            PP.getSourceManager()));
+  }
+
+  void setSourceManager(SourceManager *SourceMgr) {
+    this->SourceMgr = SourceMgr;
+  }
+  void setSysrootPath(StringRef sysroot) { SysrootPath = sysroot; }
+
+  void visitFileDependencies(const CompilerInstance &CI,
+      llvm::function_ref<void(const FileEntry *FE, bool isSystem)> visitor) override {
+    for (auto *FE : getEntries()) {
+      visitor(FE, isSystemFile(FE));
+    }
+  }
+
+  void visitIncludes(
+                 llvm::function_ref<void(const FileEntry *Source, unsigned Line,
+                                         const FileEntry *Target)> visitor) override {
+    for (auto &Include : Includes) {
+      visitor(Include.Source, Include.Line, Include.Target);
+    }
+  }
+
+  void visitModuleImports(const CompilerInstance &CI,
+                 llvm::function_ref<void(serialization::ModuleFile &Mod,
+                                         bool isSystem)> visitor) override {
+    HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+
+    if (auto Reader = CI.getModuleManager()) {
+      Reader->getModuleManager().visit([&](serialization::ModuleFile &Mod) -> bool {
+        bool isSystemMod = false;
+        if (Mod.isModule()) {
+          if (auto *M = HS.lookupModule(Mod.ModuleName, /*AllowSearch=*/false))
+            isSystemMod = M->IsSystem;
+        }
+        if (!isSystemMod || needSystemDependencies())
+          visitor(Mod, isSystemMod);
+        return true; // skip module dependencies.
+      });
+    }
+  }
+
+private:
+  bool isSystemFile(const FileEntry *FE) {
+    auto UID = FE->getUID();
+    return IsSystemByUID.size() > UID && IsSystemByUID[UID];
+  }
+
+  ArrayRef<const FileEntry *> getEntries() const {
+    return Entries.getArrayRef();
+  }
+
+  bool needSystemDependencies() override {
+    return RecordOpts.RecordSystemDependencies;
+  }
+
+  bool sawDependency(StringRef Filename, bool FromModule,
+                     bool IsSystem, bool IsModuleFile, bool IsMissing) override {
+    bool sawIt = DependencyCollector::sawDependency(Filename, FromModule,
+                                                    IsSystem, IsModuleFile,
+                                                    IsMissing);
+    if (auto *FE = SourceMgr->getFileManager().getFile(Filename)) {
+      if (sawIt)
+        Entries.insert(FE);
+      // Record system-ness for all files that we pass through.
+      if (IsSystemByUID.size() < FE->getUID()+1)
+        IsSystemByUID.resize(FE->getUID()+1);
+        IsSystemByUID[FE->getUID()] = IsSystem || isInSysroot(Filename);
+    }
+    return sawIt;
+  }
+
+  bool isInSysroot(StringRef Filename) {
+    return !SysrootPath.empty() && Filename.startswith(SysrootPath);
+  }
+};
+
+class IndexRecordActionBase {
+protected:
+  RecordingOptions RecordOpts;
+  IndexDataRecorder Recorder;
+  IndexingContext IndexCtx;
+  SourceFilesIndexDependencyCollector DepCollector;
+
+  IndexRecordActionBase(IndexingOptions IndexOpts, RecordingOptions recordOpts)
+    : RecordOpts(std::move(recordOpts)),
+      IndexCtx(IndexOpts, Recorder),
+      DepCollector(IndexCtx, RecordOpts) {
+  }
+
+  std::unique_ptr<IndexASTConsumer>
+  createIndexASTConsumer(CompilerInstance &CI) {
+    IndexCtx.setSysrootPath(CI.getHeaderSearchOpts().Sysroot);
+    Recorder.init(&IndexCtx, CI);
+
+    Preprocessor &PP = CI.getPreprocessor();
+    DepCollector.setSourceManager(&CI.getSourceManager());
+    DepCollector.setSysrootPath(IndexCtx.getSysrootPath());
+    DepCollector.attachToPreprocessor(PP);
+
+    return llvm::make_unique<IndexASTConsumer>(IndexCtx);
+  }
+
+  void finish(CompilerInstance &CI);
+};
+
+class IndexRecordAction : public ASTFrontendAction, IndexRecordActionBase {
+public:
+  IndexRecordAction(IndexingOptions IndexOpts, RecordingOptions RecordOpts)
+    : IndexRecordActionBase(std::move(IndexOpts), std::move(RecordOpts)) {}
+
+protected:
+  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+                                                 StringRef InFile) override {
+    return createIndexASTConsumer(CI);
+  }
+
+  void EndSourceFileAction() override {
+    FrontendAction::EndSourceFileAction();
+    finish(getCompilerInstance());
+  }
+};
+
+class WrappingIndexRecordAction : public WrapperFrontendAction, IndexRecordActionBase {
+  bool CreatedASTConsumer = false;
+
+public:
+  WrappingIndexRecordAction(std::unique_ptr<FrontendAction> WrappedAction,
+                            IndexingOptions IndexOpts,
+                            RecordingOptions RecordOpts)
+    : WrapperFrontendAction(std::move(WrappedAction)),
+      IndexRecordActionBase(std::move(IndexOpts), std::move(RecordOpts)) {}
+
+protected:
+  std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
+                                                 StringRef InFile) override {
+    auto OtherConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile);
+    if (!OtherConsumer)
+      return nullptr;
+
+    CreatedASTConsumer = true;
+    std::vector<std::unique_ptr<ASTConsumer>> Consumers;
+    Consumers.push_back(std::move(OtherConsumer));
+    Consumers.push_back(createIndexASTConsumer(CI));
+    return llvm::make_unique<MultiplexConsumer>(std::move(Consumers));
+  }
+
+  void EndSourceFileAction() override {
+    // Invoke wrapped action's method.
+    WrapperFrontendAction::EndSourceFileAction();
+    if (CreatedASTConsumer)
+      finish(getCompilerInstance());
+  }
+};
+
+} // anonymous namespace
+
+static std::string getClangVersion() {
+  // Try picking the version from an Apple Clang tag.
+  std::string RepositoryPath = getClangRepositoryPath();
+  StringRef BuildNumber = StringRef(RepositoryPath);
+  size_t DashOffset = BuildNumber.find('-');
+  if (BuildNumber.startswith("clang") && DashOffset != StringRef::npos) {
+    BuildNumber = BuildNumber.substr(DashOffset + 1);
+    return BuildNumber;
+  }
+  // Fallback to the generic version.
+  return CLANG_VERSION_STRING;
+}
+
+static void writeUnitData(const CompilerInstance &CI,
+                          IndexDataRecorder &Recorder,
+                          IndexDependencyProvider &DepProvider,
+                          IndexingOptions IndexOpts,
+                          RecordingOptions RecordOpts,
+                          StringRef OutputFile,
+                          const FileEntry *RootFile,
+                          Module *UnitModule,
+                          StringRef SysrootPath);
+
+void IndexRecordActionBase::finish(CompilerInstance &CI) {
+  // We may emit more diagnostics so do the begin/end source file invocations
+  // on the diagnostic client.
+  // FIXME: FrontendAction::EndSourceFile() should probably not call
+  // CI.getDiagnosticClient().EndSourceFile()' until after it has called
+  // 'EndSourceFileAction()', so that code executing during EndSourceFileAction()
+  // can emit diagnostics. If this is fixed, DiagClientBeginEndRAII can go away.
+  struct DiagClientBeginEndRAII {
+    CompilerInstance &CI;
+    DiagClientBeginEndRAII(CompilerInstance &CI) : CI(CI) {
+      CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts());
+    }
+    ~DiagClientBeginEndRAII() {
+      CI.getDiagnosticClient().EndSourceFile();
+    }
+  } diagClientBeginEndRAII(CI);
+
+  SourceManager &SM = CI.getSourceManager();
+  DiagnosticsEngine &Diag = CI.getDiagnostics();
+  HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+  StringRef DataPath = RecordOpts.DataDirPath;
+
+  std::string Error;
+  if (IndexUnitWriter::initIndexDirectory(DataPath, Error)) {
+    unsigned DiagID = Diag.getCustomDiagID(
+        DiagnosticsEngine::Error, "failed creating index directory %0");
+    Diag.Report(DiagID) << Error;
+    return;
+  }
+
+  std::string OutputFile = CI.getFrontendOpts().OutputFile;
+  if (OutputFile.empty()) {
+    OutputFile = CI.getFrontendOpts().Inputs[0].getFile();
+    OutputFile += ".o";
+  }
+
+  const FileEntry *RootFile = nullptr;
+  Module *UnitMod = nullptr;
+  bool isModuleGeneration = CI.getLangOpts().isCompilingModule();
+  if (!isModuleGeneration &&
+      CI.getFrontendOpts().ProgramAction != frontend::GeneratePCH) {
+    RootFile = SM.getFileEntryForID(SM.getMainFileID());
+  }
+  if (isModuleGeneration) {
+    UnitMod = HS.lookupModule(CI.getLangOpts().CurrentModule,
+                              /*AllowSearch=*/false);
+  }
+
+  writeUnitData(CI, Recorder, DepCollector, IndexCtx.getIndexOpts(), RecordOpts,
+                OutputFile, RootFile, UnitMod,
+                IndexCtx.getSysrootPath());
+}
+
+/// Checks if the unit file exists for module file, if it doesn't it generates
+/// index data for it.
+static bool produceIndexDataForModuleFile(
+                                      serialization::ModuleFile &Mod,
+                                      const CompilerInstance &CI,
+                                      IndexingOptions IndexOpts,
+                                      RecordingOptions RecordOpts,
+                                      IndexUnitWriter &ParentUnitWriter);
+
+static void writeUnitData(const CompilerInstance &CI,
+                          IndexDataRecorder &Recorder,
+                          IndexDependencyProvider &DepProvider,
+                          IndexingOptions IndexOpts,
+                          RecordingOptions RecordOpts,
+                          StringRef OutputFile,
+                          const FileEntry *RootFile,
+                          Module *UnitModule,
+                          StringRef SysrootPath) {
+
+  SourceManager &SM = CI.getSourceManager();
+  DiagnosticsEngine &Diag = CI.getDiagnostics();
+  HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+  StringRef DataPath = RecordOpts.DataDirPath;
+  bool IsSystemUnit = UnitModule ? UnitModule->IsSystem : false;
+  bool IsModuleUnit = UnitModule != nullptr;
+  bool IsDebugCompilation = CI.getCodeGenOpts().OptimizationLevel == 0;
+  std::string ModuleName = UnitModule ? UnitModule->getFullModuleName() : std::string();
+
+  auto getModuleInfo = [](writer::OpaqueModule mod, SmallVectorImpl<char> &Scratch) -> writer::ModuleInfo {
+    assert(mod);
+    writer::ModuleInfo info;
+    std::string fullName = static_cast<const Module*>(mod)->getFullModuleName();
+    unsigned offset = Scratch.size();
+    Scratch.append(fullName.begin(), fullName.end());
+    info.Name = StringRef(Scratch.data()+offset, fullName.size());
+    return info;
+  };
+
+  auto findModuleForHeader = [&](const FileEntry *FE) -> Module * {
+    if (!UnitModule)
+      return nullptr;
+    if (auto Mod = HS.findModuleForHeader(FE).getModule())
+      if (Mod->isSubModuleOf(UnitModule))
+        return Mod;
+    return nullptr;
+  };
+
+  IndexUnitWriter UnitWriter(CI.getFileManager(),
+                             DataPath,
+                             "clang", getClangVersion(),
+                             OutputFile,
+                             ModuleName,
+                             RootFile,
+                             IsSystemUnit,
+                             IsModuleUnit,
+                             IsDebugCompilation,
+                             CI.getTargetOpts().Triple,
+                             SysrootPath,
+                             getModuleInfo);
+
+  DepProvider.visitFileDependencies(CI, [&](const FileEntry *FE, bool isSystemFile) {
+    UnitWriter.addFileDependency(FE, isSystemFile, findModuleForHeader(FE));
+  });
+  DepProvider.visitIncludes([&](const FileEntry *Source, unsigned Line, const FileEntry *Target) {
+    UnitWriter.addInclude(Source, Line, Target);
+  });
+  DepProvider.visitModuleImports(CI, [&](serialization::ModuleFile &Mod, bool isSystemMod) {
+    Module *UnitMod = HS.lookupModule(Mod.ModuleName, /*AllowSearch=*/false);
+    UnitWriter.addASTFileDependency(Mod.File, isSystemMod, UnitMod);
+    if (Mod.isModule()) {
+      produceIndexDataForModuleFile(Mod, CI, IndexOpts, RecordOpts, UnitWriter);
+    }
+  });
+
+  ClangIndexRecordWriter RecordWriter(CI.getASTContext(), RecordOpts);
+  for (auto I = Recorder.record_begin(), E = Recorder.record_end(); I != E; ++I) {
+    FileID FID = I->first;
+    const FileIndexRecord &Rec = *I->second;
+    const FileEntry *FE = SM.getFileEntryForID(FID);
+    std::string RecordFile;
+    std::string Error;
+
+    if (RecordWriter.writeRecord(FE->getName(), Rec, Error, &RecordFile)) {
+      unsigned DiagID = Diag.getCustomDiagID(DiagnosticsEngine::Error,
+                                             "failed writing record '%0': %1");
+      Diag.Report(DiagID) << RecordFile << Error;
+      return;
+    }
+    UnitWriter.addRecordFile(RecordFile, FE, Rec.isSystem(),
+                             findModuleForHeader(FE));
+  }
+
+  std::string Error;
+  if (UnitWriter.write(Error)) {
+    unsigned DiagID = Diag.getCustomDiagID(DiagnosticsEngine::Error,
+                                           "failed writing unit data: %0");
+    Diag.Report(DiagID) << Error;
+    return;
+  }
+}
+
+namespace {
+class ModuleFileIndexDependencyCollector : public IndexDependencyProvider {
+  serialization::ModuleFile &ModFile;
+  RecordingOptions RecordOpts;
+
+public:
+  ModuleFileIndexDependencyCollector(serialization::ModuleFile &Mod,
+                                     RecordingOptions recordOpts)
+  : ModFile(Mod), RecordOpts(recordOpts) {}
+
+  void visitFileDependencies(const CompilerInstance &CI,
+      llvm::function_ref<void(const FileEntry *FE, bool isSystem)> visitor) override {
+    auto Reader = CI.getModuleManager();
+    Reader->visitInputFiles(ModFile, RecordOpts.RecordSystemDependencies,
+                            /*Complain=*/false,
+                        [&](const serialization::InputFile &IF, bool isSystem) {
+      auto *FE = IF.getFile();
+      if (!FE)
+        return;
+      // Ignore module map files, they are not as important to track as source
+      // files and they may be auto-generated which would create an undesirable
+      // dependency on an intermediate build byproduct.
+      if (FE->getName().endswith("module.modulemap"))
+        return;
+
+      visitor(FE, isSystem);
+    });
+  }
+
+  void visitIncludes(
+           llvm::function_ref<void(const FileEntry *Source, unsigned Line,
+                                   const FileEntry *Target)> visitor) override {
+   // FIXME: Module files without a preprocessing record do not have info about
+   // include locations. Serialize enough data to be able to retrieve such info.
+  }
+
+  void visitModuleImports(const CompilerInstance &CI,
+                 llvm::function_ref<void(serialization::ModuleFile &Mod,
+                                         bool isSystem)> visitor) override {
+    HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+    for (auto *Mod : ModFile.Imports) {
+      bool isSystemMod = false;
+      if (auto *M = HS.lookupModule(Mod->ModuleName, /*AllowSearch=*/false))
+        isSystemMod = M->IsSystem;
+      if (!isSystemMod || RecordOpts.RecordSystemDependencies)
+        visitor(*Mod, isSystemMod);
+    }
+  }
+};
+} // anonymous namespace.
+
+static void indexModule(serialization::ModuleFile &Mod,
+                        const CompilerInstance &CI,
+                        IndexingOptions IndexOpts,
+                        RecordingOptions RecordOpts) {
+  DiagnosticsEngine &Diag = CI.getDiagnostics();
+  Diag.Report(Mod.ImportLoc, diag::remark_index_producing_module_file_data)
+    << Mod.FileName;
+
+  StringRef SysrootPath = CI.getHeaderSearchOpts().Sysroot;
+  HeaderSearch &HS = CI.getPreprocessor().getHeaderSearchInfo();
+  Module *UnitMod = HS.lookupModule(Mod.ModuleName, /*AllowSearch=*/false);
+
+  IndexDataRecorder Recorder;
+  IndexingContext IndexCtx(IndexOpts, Recorder);
+
+  IndexCtx.setASTContext(CI.getASTContext());
+  IndexCtx.setSysrootPath(SysrootPath);
+  Recorder.init(&IndexCtx, CI);
+
+  for (const Decl *D : CI.getModuleManager()->getModuleFileLevelDecls(Mod)) {
+    IndexCtx.indexTopLevelDecl(D);
+  }
+  Recorder.finish();
+
+  ModuleFileIndexDependencyCollector DepCollector(Mod, RecordOpts);
+  writeUnitData(CI, Recorder, DepCollector, IndexOpts, RecordOpts,
+                Mod.FileName, /*RootFile=*/nullptr, UnitMod, SysrootPath);
+
+}
+
+static bool produceIndexDataForModuleFile(
+                                      serialization::ModuleFile &Mod,
+                                      const CompilerInstance &CI,
+                                      IndexingOptions IndexOpts,
+                                      RecordingOptions RecordOpts,
+                                      IndexUnitWriter &ParentUnitWriter) {
+  DiagnosticsEngine &Diag = CI.getDiagnostics();
+  std::string Error;
+  // We don't do timestamp check with the PCM file, on purpose. The PCM may get
+  // touched for various reasons which would cause unnecessary work to emit
+  // index data. User modules normally will get rebuilt and their index data
+  // re-emitted, and system modules are generally stable (and they can also can
+  // get rebuilt along with their index data).
+  auto IsUptodateOpt = ParentUnitWriter.isUnitUpToDateForOutputFile(Mod.FileName, None, Error);
+  if (!IsUptodateOpt.hasValue()) {
+    unsigned DiagID = Diag.getCustomDiagID(DiagnosticsEngine::Error,
+                                           "failed file status check: %0");
+    Diag.Report(DiagID) << Error;
+    return false;
+  }
+  if (*IsUptodateOpt)
+    return false;
+
+  indexModule(Mod, CI, IndexOpts, RecordOpts);
+  return true;
+}
+
+static std::unique_ptr<FrontendAction>
+createIndexDataRecordingAction(IndexingOptions IndexOpts,
+                               RecordingOptions RecordOpts,
+                               std::unique_ptr<FrontendAction> WrappedAction) {
+  if (WrappedAction)
+    return llvm::make_unique<WrappingIndexRecordAction>(std::move(WrappedAction),
+                                                        std::move(IndexOpts),
+                                                        std::move(RecordOpts));
+  return llvm::make_unique<IndexRecordAction>(std::move(IndexOpts),
+                                              std::move(RecordOpts));
+}
+
+static std::pair<IndexingOptions, RecordingOptions>
+getIndexOptionsFromFrontendOptions(const FrontendOptions &FEOpts) {
+  index::IndexingOptions IndexOpts;
+  index::RecordingOptions RecordOpts;
+  RecordOpts.DataDirPath = FEOpts.IndexStorePath;
+  if (FEOpts.IndexIgnoreSystemSymbols) {
+    IndexOpts.SystemSymbolFilter =
+    index::IndexingOptions::SystemSymbolFilterKind::None;
+  }
+  RecordOpts.RecordSymbolCodeGenName = FEOpts.IndexRecordCodegenName;
+  return { IndexOpts, RecordOpts };
+}
+
+std::unique_ptr<FrontendAction>
+index::createIndexDataRecordingAction(const FrontendOptions &FEOpts,
+                                std::unique_ptr<FrontendAction> WrappedAction) {
+  index::IndexingOptions IndexOpts;
+  index::RecordingOptions RecordOpts;
+  std::tie(IndexOpts, RecordOpts) = getIndexOptionsFromFrontendOptions(FEOpts);
+  return ::createIndexDataRecordingAction(IndexOpts, RecordOpts,
+                                          std::move(WrappedAction));
+}
+
+bool index::emitIndexDataForModuleFile(const Module *Mod,
+                                       const CompilerInstance &CI,
+                                       IndexUnitWriter &ParentUnitWriter) {
+  index::IndexingOptions IndexOpts;
+  index::RecordingOptions RecordOpts;
+  std::tie(IndexOpts, RecordOpts) = getIndexOptionsFromFrontendOptions(CI.getFrontendOpts());
+
+  auto astReader = CI.getModuleManager();
+  serialization::ModuleFile *ModFile = astReader->getModuleManager().lookup(Mod->getASTFile());
+  assert(ModFile && "no module file loaded for module ?");
+  return produceIndexDataForModuleFile(*ModFile, CI, IndexOpts, RecordOpts, ParentUnitWriter);
+}
diff --git a/lib/Index/IndexingContext.cpp b/lib/Index/IndexingContext.cpp
index 9995a22..8a6e7fd 100644
--- a/lib/Index/IndexingContext.cpp
+++ b/lib/Index/IndexingContext.cpp
@@ -93,12 +93,7 @@
   if (FID.isInvalid())
     return true;
 
-  bool Invalid = false;
-  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
-  if (Invalid || !SEntry.isFile())
-    return true;
-
-  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
+  if (isSystemFile(FID)) {
     switch (IndexOpts.SystemSymbolFilter) {
     case IndexingOptions::SystemSymbolFilterKind::None:
       return true;
@@ -161,6 +156,56 @@
   return true;
 }
 
+void IndexingContext::setSysrootPath(StringRef path) {
+  // Ignore sysroot path if it points to root, otherwise every header will be
+  // treated as system one.
+  if (path == "/")
+    path = StringRef();
+  SysrootPath = path;
+}
+
+bool IndexingContext::isSystemFile(FileID FID) {
+  if (LastFileCheck.first == FID)
+    return LastFileCheck.second;
+
+  auto result = [&](bool res) -> bool {
+    LastFileCheck = { FID, res };
+    return res;
+  };
+
+  bool Invalid = false;
+  const SrcMgr::SLocEntry &SEntry =
+    Ctx->getSourceManager().getSLocEntry(FID, &Invalid);
+  if (Invalid || !SEntry.isFile())
+    return result(false);
+
+  const SrcMgr::FileInfo &FI = SEntry.getFile();
+  if (FI.getFileCharacteristic() != SrcMgr::C_User)
+    return result(true);
+
+  auto *CC = FI.getContentCache();
+  if (!CC)
+    return result(false);
+  auto *FE = CC->OrigEntry;
+  if (!FE)
+    return result(false);
+
+  if (SysrootPath.empty())
+    return result(false);
+
+  // Check if directory is in sysroot so that we can consider system headers
+  // even the headers found via a user framework search path, pointing inside
+  // sysroot.
+  auto dirEntry = FE->getDir();
+  auto pair = DirEntries.insert(std::make_pair(dirEntry, false));
+  bool &isSystemDir = pair.first->second;
+  bool wasInserted = pair.second;
+  if (wasInserted) {
+    isSystemDir = StringRef(dirEntry->getName()).startswith(SysrootPath);
+  }
+  return result(isSystemDir);
+}
+
 static const CXXRecordDecl *
 getDeclContextForTemplateInstationPattern(const Decl *D) {
   if (const auto *CTSD =
@@ -312,7 +357,7 @@
                                            const Expr *OrigE,
                                            const Decl *OrigD,
                                            const DeclContext *ContainerDC) {
-  if (D->isImplicit() && !isa<ObjCMethodDecl>(D))
+  if (D->isImplicit() && !(isa<ObjCMethodDecl>(D) || isa<ObjCIvarDecl>(D)))
     return true;
   if (!isa<NamedDecl>(D) ||
       (cast<NamedDecl>(D)->getDeclName().isEmpty() &&
@@ -330,12 +375,7 @@
   if (FID.isInvalid())
     return true;
 
-  bool Invalid = false;
-  const SrcMgr::SLocEntry &SEntry = SM.getSLocEntry(FID, &Invalid);
-  if (Invalid || !SEntry.isFile())
-    return true;
-
-  if (SEntry.getFile().getFileCharacteristic() != SrcMgr::C_User) {
+  if (isSystemFile(FID)) {
     switch (IndexOpts.SystemSymbolFilter) {
     case IndexingOptions::SystemSymbolFilterKind::None:
       return true;
diff --git a/lib/Index/IndexingContext.h b/lib/Index/IndexingContext.h
index 566651c..70e72e1 100644
--- a/lib/Index/IndexingContext.h
+++ b/lib/Index/IndexingContext.h
@@ -11,9 +11,11 @@
 #define LLVM_CLANG_LIB_INDEX_INDEXINGCONTEXT_H
 
 #include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
 #include "clang/Index/IndexSymbol.h"
 #include "clang/Index/IndexingAction.h"
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 
 namespace clang {
   class ASTContext;
@@ -29,7 +31,7 @@
   class Stmt;
   class Expr;
   class TypeLoc;
-  class SourceLocation;
+  class DirectoryEntry;
 
 namespace index {
   class IndexDataConsumer;
@@ -38,6 +40,13 @@
   IndexingOptions IndexOpts;
   IndexDataConsumer &DataConsumer;
   ASTContext *Ctx = nullptr;
+  std::string SysrootPath;
+
+  // Records whether a directory entry is system or not.
+  llvm::DenseMap<const DirectoryEntry *, bool> DirEntries;
+  // Keeps track of the last check for whether a FileID is system or
+  // not. This is used to speed up isSystemFile() call.
+  std::pair<FileID, bool> LastFileCheck;
 
 public:
   IndexingContext(IndexingOptions IndexOpts, IndexDataConsumer &DataConsumer)
@@ -47,6 +56,10 @@
   IndexDataConsumer &getDataConsumer() { return DataConsumer; }
 
   void setASTContext(ASTContext &ctx) { Ctx = &ctx; }
+  void setSysrootPath(StringRef path);
+  StringRef getSysrootPath() const { return SysrootPath; }
+
+  bool isSystemFile(FileID FID);
 
   bool shouldIndex(const Decl *D);
 
diff --git a/test/Index/Store/Inputs/head.h b/test/Index/Store/Inputs/head.h
new file mode 100644
index 0000000..6ac174d
--- /dev/null
+++ b/test/Index/Store/Inputs/head.h
@@ -0,0 +1,3 @@
+
+extern void test1_func(void);
+extern void test2_func(void);
diff --git a/test/Index/Store/Inputs/json.c.json b/test/Index/Store/Inputs/json.c.json
new file mode 100644
index 0000000..498022d
--- /dev/null
+++ b/test/Index/Store/Inputs/json.c.json
@@ -0,0 +1,151 @@
+{
+  "files": [
+    "/test1.o",
+    "/Inputs/test1.c",
+    "/Inputs/head.h",
+    "/test2.o",
+    "/Inputs/test2.c",
+    "/test3.o",
+    "/Inputs/test3.cpp"
+  ],
+  "symbols": [
+    {
+      "kind": "function",
+      "lang": "C",
+      "usr": "c:@F@test1_func",
+      "name": "test1_func",
+      "codegen": "_test1_func",
+      "roles": "Decl,Def"
+    },
+    {
+      "kind": "function",
+      "lang": "C",
+      "usr": "c:@F@test2_func",
+      "name": "test2_func",
+      "codegen": "_test2_func",
+      "roles": "Decl,Def"
+    },
+    {
+      "kind": "class",
+      "lang": "C++",
+      "usr": "c:@S@Base",
+      "name": "Base",
+      "roles": "Def,Ref,RelBase,RelCont"
+    },
+    {
+      "kind": "class",
+      "lang": "C++",
+      "usr": "c:@S@Sub",
+      "name": "Sub",
+      "roles": "Def",
+      "rel-roles": "RelBase,RelCont"
+    }
+  ],
+  "records": [
+    {
+      "occurrences": [
+        {
+          "symbol": 0,
+          "line": 3,
+          "col": 6,
+          "roles": "Def"
+        }
+      ]
+    },
+    {
+      "occurrences": [
+        {
+          "symbol": 0,
+          "line": 2,
+          "col": 13,
+          "roles": "Decl"
+        },
+        {
+          "symbol": 1,
+          "line": 3,
+          "col": 13,
+          "roles": "Decl"
+        }
+      ]
+    },
+    {
+      "occurrences": [
+        {
+          "symbol": 1,
+          "line": 3,
+          "col": 6,
+          "roles": "Def"
+        }
+      ]
+    },
+    {
+      "occurrences": [
+        {
+          "symbol": 2,
+          "line": 1,
+          "col": 7,
+          "roles": "Def"
+        },
+        {
+          "symbol": 3,
+          "line": 2,
+          "col": 7,
+          "roles": "Def"
+        },
+        {
+          "symbol": 2,
+          "line": 2,
+          "col": 20,
+          "roles": "Ref,RelBase,RelCont",
+          "relations": [
+            {
+              "symbol": 3,
+              "rel-roles": "RelBase,RelCont"
+            }
+          ]
+
+        }
+      ]
+    }
+  ],
+  "units": [
+    {
+      "triple": "x86_64-apple-macosx10.7.0",
+      "out-file": 0,
+      "sources": [
+        {
+          "file": 1,
+          "records": [0]
+        },
+        {
+          "file": 2,
+          "records": [1]
+        }
+      ]
+    },
+    {
+      "triple": "x86_64-apple-macosx10.7.0",
+      "out-file": 3,
+      "sources": [
+        {
+          "file": 4,
+          "records": [2]
+        },
+        {
+          "file": 2,
+          "records": [1]
+        }
+      ]
+    },
+    {
+      "triple": "x86_64-apple-macosx10.7.0",
+      "out-file": 5,
+      "sources": [
+        {
+          "file": 6,
+          "records": [3]
+        }
+      ]
+    }
+  ]
+}
diff --git a/test/Index/Store/Inputs/module/ModDep.h b/test/Index/Store/Inputs/module/ModDep.h
new file mode 100644
index 0000000..e96ef54
--- /dev/null
+++ b/test/Index/Store/Inputs/module/ModDep.h
@@ -0,0 +1,3 @@
+#include "ModTop.h"
+
+void ModDep_func(ModTopStruct s);
diff --git a/test/Index/Store/Inputs/module/ModSystem.h b/test/Index/Store/Inputs/module/ModSystem.h
new file mode 100644
index 0000000..0419f97
--- /dev/null
+++ b/test/Index/Store/Inputs/module/ModSystem.h
@@ -0,0 +1,4 @@
+
+typedef struct {} ModSystemStruct;
+
+void ModSystem_func(void);
diff --git a/test/Index/Store/Inputs/module/ModTop.h b/test/Index/Store/Inputs/module/ModTop.h
new file mode 100644
index 0000000..60c5686
--- /dev/null
+++ b/test/Index/Store/Inputs/module/ModTop.h
@@ -0,0 +1,4 @@
+
+typedef struct {} ModTopStruct;
+
+void ModTop_func(void);
diff --git a/test/Index/Store/Inputs/module/ModTopSub1.h b/test/Index/Store/Inputs/module/ModTopSub1.h
new file mode 100644
index 0000000..e1e3cf3
--- /dev/null
+++ b/test/Index/Store/Inputs/module/ModTopSub1.h
@@ -0,0 +1 @@
+void ModTopSub1_func(void);
diff --git a/test/Index/Store/Inputs/module/ModTopSub2.h b/test/Index/Store/Inputs/module/ModTopSub2.h
new file mode 100644
index 0000000..39d37f1
--- /dev/null
+++ b/test/Index/Store/Inputs/module/ModTopSub2.h
@@ -0,0 +1 @@
+// This header has no symbols, intended to show up as file dependency.
diff --git a/test/Index/Store/Inputs/module/module.modulemap b/test/Index/Store/Inputs/module/module.modulemap
new file mode 100644
index 0000000..ada2f38
--- /dev/null
+++ b/test/Index/Store/Inputs/module/module.modulemap
@@ -0,0 +1,12 @@
+module ModTop {
+  header "ModTop.h"
+  export *
+  module Sub1 {
+    header "ModTopSub1.h"
+  }
+  module Sub2 {
+    header "ModTopSub2.h"
+  }
+}
+module ModDep { header "ModDep.h" export * }
+module ModSystem [system] { header "ModSystem.h" export * }
diff --git a/test/Index/Store/Inputs/overlay.yaml b/test/Index/Store/Inputs/overlay.yaml
new file mode 100644
index 0000000..7b55b30
--- /dev/null
+++ b/test/Index/Store/Inputs/overlay.yaml
@@ -0,0 +1,6 @@
+{
+  'version': 0,
+  'roots': [{ 'type': 'file', 'name': 'OUT_DIR/using-overlay.h',
+             'external-contents': 'INPUT_DIR/using-overlay.h'
+           }]
+}
diff --git a/test/Index/Store/Inputs/print-unit.h b/test/Index/Store/Inputs/print-unit.h
new file mode 100644
index 0000000..62039c4
--- /dev/null
+++ b/test/Index/Store/Inputs/print-unit.h
@@ -0,0 +1,2 @@
+#include "head.h"
+#include "using-overlay.h"
diff --git a/test/Index/Store/Inputs/sys/another.h b/test/Index/Store/Inputs/sys/another.h
new file mode 100644
index 0000000..555b99b
--- /dev/null
+++ b/test/Index/Store/Inputs/sys/another.h
@@ -0,0 +1,2 @@
+
+extern void sys_another_func(void);
diff --git a/test/Index/Store/Inputs/sys/syshead.h b/test/Index/Store/Inputs/sys/syshead.h
new file mode 100644
index 0000000..8941fd6
--- /dev/null
+++ b/test/Index/Store/Inputs/sys/syshead.h
@@ -0,0 +1,4 @@
+
+#include "another.h"
+
+extern void sys_test1_func(void);
diff --git a/test/Index/Store/Inputs/test1.c b/test/Index/Store/Inputs/test1.c
new file mode 100644
index 0000000..505711d
--- /dev/null
+++ b/test/Index/Store/Inputs/test1.c
@@ -0,0 +1,3 @@
+#include "head.h"
+
+void test1_func(void) {}
diff --git a/test/Index/Store/Inputs/test2.c b/test/Index/Store/Inputs/test2.c
new file mode 100644
index 0000000..333b8ae
--- /dev/null
+++ b/test/Index/Store/Inputs/test2.c
@@ -0,0 +1,3 @@
+#include "head.h"
+
+void test2_func(void) {}
diff --git a/test/Index/Store/Inputs/test3.cpp b/test/Index/Store/Inputs/test3.cpp
new file mode 100644
index 0000000..06334a1
--- /dev/null
+++ b/test/Index/Store/Inputs/test3.cpp
@@ -0,0 +1,2 @@
+class Base {};
+class Sub : public Base {};
diff --git a/test/Index/Store/Inputs/using-overlay.h b/test/Index/Store/Inputs/using-overlay.h
new file mode 100644
index 0000000..bb361c3
--- /dev/null
+++ b/test/Index/Store/Inputs/using-overlay.h
@@ -0,0 +1 @@
+void using_overlay(void);
diff --git a/test/Index/Store/assembly-invocation.c b/test/Index/Store/assembly-invocation.c
new file mode 100644
index 0000000..ab9c197
--- /dev/null
+++ b/test/Index/Store/assembly-invocation.c
@@ -0,0 +1,3 @@
+// Make sure it doesn't crash.
+// RUN: %clang -target x86_64-apple-macosx10.7 -S %s -o %t.s
+// RUN: env CLANG_PROJECT_INDEX_PATH=%t.idx %clang -target x86_64-apple-macosx10.7 -c %t.s -o %t.o
diff --git a/test/Index/Store/external-source-symbol-hash.m b/test/Index/Store/external-source-symbol-hash.m
new file mode 100644
index 0000000..243616d
--- /dev/null
+++ b/test/Index/Store/external-source-symbol-hash.m
@@ -0,0 +1,47 @@
+// RUN: rm -rf %t.idx
+// RUN: %clang_cc1 %s -index-store-path %t.idx -D USE_EXTERNAL
+// RUN: c-index-test core -print-record %t.idx | FileCheck %s
+// RUN: %clang_cc1 %s -index-store-path %t.idx
+// RUN: find %t.idx/*/records -name "external-source-symbol-hash*" | count 2
+
+#ifdef USE_EXTERNAL
+#  define EXT_DECL(mod_name) __attribute__((external_source_symbol(language="Swift", defined_in=mod_name)))
+#else
+#  define EXT_DECL(mod_name)
+#endif
+
+#define NS_ENUM(_name, _type) enum _name:_type _name; enum _name : _type
+
+// Forward declarations should pick up the attribute from later decls
+@protocol P1;
+// CHECK: [[@LINE-1]]:11 | protocol/Swift | c:@M@some_module@objc(pl)P1 | Ref | rel: 0
+@class I2;
+// CHECK: [[@LINE-1]]:8 | class/Swift | c:@M@other_module@objc(cs)I2 | Ref | rel: 0
+enum E3: int;
+// CHECK: [[@LINE-1]]:6 | enum/Swift | c:@M@third_module@E@E3 | Ref | rel: 0
+
+void test(id<P1> first, I2 *second, enum E3 third) {}
+// CHECK: [[@LINE-1]]:14 | protocol/Swift | c:@M@some_module@objc(pl)P1 | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-2]]:25 | class/Swift | c:@M@other_module@objc(cs)I2 | Ref,RelCont | rel: 1
+// CHECK: [[@LINE-3]]:42 | enum/Swift | c:@M@third_module@E@E3 | Ref,RelCont | rel: 1
+
+EXT_DECL("some_module")
+@protocol P1
+// CHECK: [[@LINE-1]]:11 | protocol/Swift | c:@M@some_module@objc(pl)P1 | Decl | rel: 0
+-(void)method;
+// CHECK: [[@LINE-1]]:8 | instance-method/Swift | c:@M@some_module@objc(pl)P1(im)method | Decl,Dyn,RelChild | rel: 1
+@end
+
+EXT_DECL("other_module")
+@interface I2
+// CHECK: [[@LINE-1]]:12 | class/Swift | c:@M@other_module@objc(cs)I2 | Decl | rel: 0
+-(void)method;
+// CHECK: [[@LINE-1]]:8 | instance-method/Swift | c:@M@other_module@objc(cs)I2(im)method | Decl,Dyn,RelChild | rel: 1
+@end
+
+
+typedef NS_ENUM(E3, int) {
+// CHECK: [[@LINE-1]]:17 | enum/Swift | c:@M@third_module@E@E3 | Def | rel: 0
+  firstCase = 1,
+  // CHECK: [[@LINE-1]]:3 | enumerator/Swift | c:@M@third_module@E@E3@firstCase | Def,RelChild | rel: 1
+} EXT_DECL("third_module");
diff --git a/test/Index/Store/handle-prebuilt-module.m b/test/Index/Store/handle-prebuilt-module.m
new file mode 100644
index 0000000..f6a0c42
--- /dev/null
+++ b/test/Index/Store/handle-prebuilt-module.m
@@ -0,0 +1,25 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %clang -arch x86_64 -mmacosx-version-min=10.7 -fsyntax-only %s -o %t.o -index-store-path %t/idx1 -fmodules -fmodules-cache-path=%t/mcp -I %S/Inputs/module -Rindex-store 2> %t.err1
+// RUN: %clang -arch x86_64 -mmacosx-version-min=10.7 -fsyntax-only %s -o %t.o -index-store-path %t/idx2 -fmodules -fmodules-cache-path=%t/mcp -I %S/Inputs/module -Rindex-store 2> %t.err2
+// RUN: %clang -arch x86_64 -mmacosx-version-min=10.7 -fsyntax-only %s -o %t.o -index-store-path %t/idx2 -fmodules -fmodules-cache-path=%t/mcp -I %S/Inputs/module -Rindex-store 2> %t.err3
+// RUN: FileCheck -input-file=%t.err1 -check-prefix=CREATING_MODULES %s -allow-empty
+// RUN: FileCheck -input-file=%t.err2 -check-prefix=CREATING_INDEX_DATA_FROM_MODULE_FILES %s
+// RUN: FileCheck -input-file=%t.err3 -check-prefix=EXISTING_INDEX_DATA_FROM_MODULE_FILES %s -allow-empty
+// RUN: c-index-test core -print-unit %t/idx1 > %t/all-units1.txt
+// RUN: c-index-test core -print-unit %t/idx2 > %t/all-units2.txt
+// RUN: c-index-test core -print-record %t/idx1 > %t/all-records1.txt
+// RUN: c-index-test core -print-record %t/idx2 > %t/all-records2.txt
+// RUN: diff -u %t/all-units1.txt %t/all-units2.txt
+// RUN: diff -u %t/all-records1.txt %t/all-records2.txt
+
+@import ModDep;
+
+// CREATING_MODULES-NOT: remark:
+
+// CREATING_INDEX_DATA_FROM_MODULE_FILES: remark: producing index data for module file {{.*}}ModDep{{.*}}.pcm
+// CREATING_INDEX_DATA_FROM_MODULE_FILES: remark: producing index data for module file {{.*}}ModTop{{.*}}.pcm
+
+// EXISTING_INDEX_DATA_FROM_MODULE_FILES-NOT: remark:
diff --git a/test/Index/Store/json-with-module.m b/test/Index/Store/json-with-module.m
new file mode 100644
index 0000000..1ef6969
--- /dev/null
+++ b/test/Index/Store/json-with-module.m
@@ -0,0 +1,9 @@
+// RUN: rm -rf %t.idx %t.mcp
+// RUN: %clang -arch x86_64 -mmacosx-version-min=10.7 -c %s -o %t.o -index-store-path %t.idx -fmodules -fmodules-cache-path=%t.mcp -Xclang -fdisable-module-hash -I %S/Inputs/module
+// RUN: c-index-test core -aggregate-json %t.idx -o %t.json
+// RUN: sed -e "s:%S::g" -e "s:%T::g" %t.json > %t.final.json
+// RUN: diff -u %s.json %t.final.json
+
+// XFAIL: linux
+
+@import ModDep;
diff --git a/test/Index/Store/json-with-module.m.json b/test/Index/Store/json-with-module.m.json
new file mode 100644
index 0000000..bb020cc
--- /dev/null
+++ b/test/Index/Store/json-with-module.m.json
@@ -0,0 +1,151 @@
+{
+  "files": [
+    "/json-with-module.m.tmp.mcp/ModDep.pcm",
+    "/json-with-module.m.tmp.mcp/ModTop.pcm",
+    "/Inputs/module/ModDep.h",
+    "/Inputs/module/ModTop.h",
+    "/Inputs/module/ModTopSub1.h",
+    "/Inputs/module/ModTopSub2.h",
+    "/json-with-module.m.tmp.o",
+    "/json-with-module.m",
+    "/Inputs/module/module.modulemap"
+  ],
+  "symbols": [
+    {
+      "kind": "function",
+      "lang": "C",
+      "usr": "c:@F@ModDep_func",
+      "name": "ModDep_func",
+      "roles": "Decl",
+      "rel-roles": "RelCont"
+    },
+    {
+      "kind": "type-alias",
+      "lang": "C",
+      "usr": "c:ModTop.h@T@ModTopStruct",
+      "name": "ModTopStruct",
+      "roles": "Def,Ref,RelCont"
+    },
+    {
+      "kind": "struct",
+      "lang": "C",
+      "usr": "c:@SA@ModTopStruct",
+      "name": "",
+      "roles": "Def"
+    },
+    {
+      "kind": "function",
+      "lang": "C",
+      "usr": "c:@F@ModTop_func",
+      "name": "ModTop_func",
+      "roles": "Decl"
+    },
+    {
+      "kind": "function",
+      "lang": "C",
+      "usr": "c:@F@ModTopSub1_func",
+      "name": "ModTopSub1_func",
+      "roles": "Decl"
+    }
+  ],
+  "records": [
+    {
+      "occurrences": [
+        {
+          "symbol": 0,
+          "line": 3,
+          "col": 6,
+          "roles": "Decl"
+        },
+        {
+          "symbol": 1,
+          "line": 3,
+          "col": 18,
+          "roles": "Ref,RelCont",
+          "relations": [
+            {
+              "symbol": 0,
+              "rel-roles": "RelCont"
+            }
+          ]
+
+        }
+      ]
+    },
+    {
+      "occurrences": [
+        {
+          "symbol": 2,
+          "line": 2,
+          "col": 9,
+          "roles": "Def"
+        },
+        {
+          "symbol": 1,
+          "line": 2,
+          "col": 19,
+          "roles": "Def"
+        },
+        {
+          "symbol": 3,
+          "line": 4,
+          "col": 6,
+          "roles": "Decl"
+        }
+      ]
+    },
+    {
+      "occurrences": [
+        {
+          "symbol": 4,
+          "line": 1,
+          "col": 6,
+          "roles": "Decl"
+        }
+      ]
+    }
+  ],
+  "units": [
+    {
+      "triple": "x86_64-apple-macosx10.7.0",
+      "out-file": 0,
+      "unit-dependencies": [1],
+      "sources": [
+        {
+          "file": 2,
+          "records": [0]
+        }
+      ]
+    },
+    {
+      "triple": "x86_64-apple-macosx10.7.0",
+      "out-file": 1,
+      "sources": [
+        {
+          "file": 3,
+          "records": [1]
+        },
+        {
+          "file": 4,
+          "records": [2]
+        },
+        {
+          "file": 5
+        }
+      ]
+    },
+    {
+      "triple": "x86_64-apple-macosx10.7.0",
+      "out-file": 6,
+      "unit-dependencies": [0],
+      "sources": [
+        {
+          "file": 7
+        },
+        {
+          "file": 8
+        }
+      ]
+    }
+  ]
+}
diff --git a/test/Index/Store/json-with-pch.c b/test/Index/Store/json-with-pch.c
new file mode 100644
index 0000000..9ffe80f
--- /dev/null
+++ b/test/Index/Store/json-with-pch.c
@@ -0,0 +1,10 @@
+// RUN: rm -rf %t.idx
+// RUN: %clang -arch x86_64 -mmacosx-version-min=10.7 -x c-header %S/Inputs/head.h -o %t.h.pch -index-store-path %t.idx
+// RUN: %clang -arch x86_64 -mmacosx-version-min=10.7 -c %s -o %t.o -index-store-path %t.idx -include %t.h -Werror
+// RUN: c-index-test core -aggregate-json %t.idx -o %t.json
+// RUN: sed -e "s:%S::g" -e "s:%T::g" %t.json > %t.final.json
+// RUN: diff -u %s.json %t.final.json
+// XFAIL: linux
+int main() {
+  test1_func();
+}
diff --git a/test/Index/Store/json-with-pch.c.json b/test/Index/Store/json-with-pch.c.json
new file mode 100644
index 0000000..605f33e
--- /dev/null
+++ b/test/Index/Store/json-with-pch.c.json
@@ -0,0 +1,96 @@
+{
+  "files": [
+    "/json-with-pch.c.tmp.h.pch",
+    "/Inputs/head.h",
+    "/json-with-pch.c.tmp.o",
+    "/json-with-pch.c"
+  ],
+  "symbols": [
+    {
+      "kind": "function",
+      "lang": "C",
+      "usr": "c:@F@test1_func",
+      "name": "test1_func",
+      "roles": "Decl,Ref,Call,RelCall,RelCont"
+    },
+    {
+      "kind": "function",
+      "lang": "C",
+      "usr": "c:@F@test2_func",
+      "name": "test2_func",
+      "roles": "Decl"
+    },
+    {
+      "kind": "function",
+      "lang": "C",
+      "usr": "c:@F@main",
+      "name": "main",
+      "roles": "Def",
+      "rel-roles": "RelCall,RelCont"
+    }
+  ],
+  "records": [
+    {
+      "occurrences": [
+        {
+          "symbol": 0,
+          "line": 2,
+          "col": 13,
+          "roles": "Decl"
+        },
+        {
+          "symbol": 1,
+          "line": 3,
+          "col": 13,
+          "roles": "Decl"
+        }
+      ]
+    },
+    {
+      "occurrences": [
+        {
+          "symbol": 2,
+          "line": 8,
+          "col": 5,
+          "roles": "Def"
+        },
+        {
+          "symbol": 0,
+          "line": 9,
+          "col": 3,
+          "roles": "Ref,Call,RelCall,RelCont",
+          "relations": [
+            {
+              "symbol": 2,
+              "rel-roles": "RelCall,RelCont"
+            }
+          ]
+
+        }
+      ]
+    }
+  ],
+  "units": [
+    {
+      "triple": "x86_64-apple-macosx10.7.0",
+      "out-file": 0,
+      "sources": [
+        {
+          "file": 1,
+          "records": [0]
+        }
+      ]
+    },
+    {
+      "triple": "x86_64-apple-macosx10.7.0",
+      "out-file": 2,
+      "unit-dependencies": [0],
+      "sources": [
+        {
+          "file": 3,
+          "records": [1]
+        }
+      ]
+    }
+  ]
+}
diff --git a/test/Index/Store/json.c b/test/Index/Store/json.c
new file mode 100644
index 0000000..c4ea965
--- /dev/null
+++ b/test/Index/Store/json.c
@@ -0,0 +1,10 @@
+// RUN: rm -rf %t.idx
+// RUN: mkdir -p %t.o
+// RUN: env CLANG_PROJECT_INDEX_PATH=%t.idx %clang -target x86_64-apple-macosx10.7 -arch x86_64 -mmacosx-version-min=10.7 -c %S/Inputs/test1.c -o %t.o/test1.o
+// RUN: env CLANG_PROJECT_INDEX_PATH=%t.idx %clang -target x86_64-apple-macosx10.7 -arch x86_64 -mmacosx-version-min=10.7 -c %S/Inputs/test2.c -o %t.o/test2.o
+// RUN: env CLANG_PROJECT_INDEX_PATH=%t.idx %clang -target x86_64-apple-macosx10.7 -arch x86_64 -mmacosx-version-min=10.7 -c %S/Inputs/test3.cpp -o %t.o/test3.o
+// RUN: c-index-test core -aggregate-json %t.idx -o %t.json
+// RUN: sed -e "s:%S::g" -e "s:%t.o::g" %t.json > %t.final.json
+// RUN: diff -u %S/Inputs/json.c.json %t.final.json
+
+// XFAIL: linux
diff --git a/test/Index/Store/print-record.mm b/test/Index/Store/print-record.mm
new file mode 100644
index 0000000..ce24983
--- /dev/null
+++ b/test/Index/Store/print-record.mm
@@ -0,0 +1,28 @@
+// RUN: rm -rf %t.idx
+// RUN: %clang_cc1 %s -index-store-path %t.idx
+// RUN: c-index-test core -print-record %t.idx | FileCheck %s
+
+// XFAIL: linux
+
+@class MyCls;
+
+@interface MyCls
+@end
+
+// CHECK: [[@LINE+2]]:6 | function/C | c:@F@foo#*$objc(cs)MyCls# | Decl | rel: 0
+// CHECK: [[@LINE+1]]:10 | class/ObjC | c:objc(cs)MyCls | Ref,RelCont | rel: 1
+void foo(MyCls *p);
+
+
+// RANGE-NOT: before_range
+void before_range();
+
+// RANGE: [[@LINE+1]]:6 | function/C | c:@F@in_range1# | Decl
+void in_range1();
+// RANGE: [[@LINE+1]]:6 | function/C | c:@F@in_range2# | Decl
+void in_range2();
+
+// RANGE-NOT: after_range
+void after_range();
+
+// RUN: c-index-test core -print-record %t.idx -filepath %s:21:23 | FileCheck -check-prefix=RANGE %s
diff --git a/test/Index/Store/print-unit.c b/test/Index/Store/print-unit.c
new file mode 100644
index 0000000..19254a1
--- /dev/null
+++ b/test/Index/Store/print-unit.c
@@ -0,0 +1,39 @@
+// XFAIL: linux
+
+#include "print-unit.h"
+#include "syshead.h"
+
+void foo(int i);
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -I %S/Inputs -isystem %S/Inputs/sys -index-store-path %t/idx %s -triple x86_64-apple-macosx10.8
+// RUN: c-index-test core -print-unit %t/idx | FileCheck %s
+// RUN: %clang_cc1 -I %S/Inputs -isystem %S/Inputs/sys -index-store-path %t/idx_opt1 %s -triple x86_64-apple-macosx10.8 -O2
+// RUN: c-index-test core -print-unit %t/idx_opt1 | FileCheck %s -check-prefix=OPT
+// RUN: %clang_cc1 -I %S/Inputs -isystem %S/Inputs/sys -index-store-path %t/idx_opt2 %s -triple x86_64-apple-macosx10.8 -Os
+// RUN: c-index-test core -print-unit %t/idx_opt2 | FileCheck %s -check-prefix=OPT
+
+// CHECK: print-unit.c.o
+// CHECK: provider: clang-
+// CHECK: is-system: 0
+// CHECK: has-main: 1
+// CHECK: main-path: {{.*}}/print-unit.c
+// CHECK: out-file: {{.*}}/print-unit.c.o
+// CHECK: target: x86_64-apple-macosx10.8
+// CHECK: is-debug: 1
+// CHECK: DEPEND START
+// CHECK: Record | user | {{.*}}/print-unit.c | print-unit.c-
+// CHECK: Record | user | {{.*}}/Inputs/head.h | head.h-
+// CHECK: Record | user | {{.*}}/Inputs/using-overlay.h | using-overlay.h-
+// CHECK: Record | system | {{.*}}/Inputs/sys/syshead.h | syshead.h-
+// CHECK: Record | system | {{.*}}/Inputs/sys/another.h | another.h-
+// CHECK: File | user | {{.*}}/Inputs/print-unit.h | | {{[0-9]*$}}
+// CHECK: DEPEND END (6)
+// CHECK: INCLUDE START
+// CHECK: {{.*}}/print-unit.c:3 | {{.*}}/Inputs/print-unit.h
+// CHECK: {{.*}}/print-unit.c:4 | {{.*}}/Inputs/sys/syshead.h
+// CHECK: {{.*}}/Inputs/print-unit.h:1 | {{.*}}/Inputs/head.h
+// CHECK: {{.*}}/Inputs/print-unit.h:2 | {{.*}}/Inputs/using-overlay.h
+// CHECK: INCLUDE END (4)
+
+// OPT: is-debug: 0
diff --git a/test/Index/Store/print-units-with-modules.m b/test/Index/Store/print-units-with-modules.m
new file mode 100644
index 0000000..cedfe2c
--- /dev/null
+++ b/test/Index/Store/print-units-with-modules.m
@@ -0,0 +1,59 @@
+// RUN: rm -rf %t.idx %t.mcp
+// RUN: %clang -arch x86_64 -mmacosx-version-min=10.7 -c %s -o %t.o -index-store-path %t.idx -fmodules -fmodules-cache-path=%t.mcp -Xclang -fdisable-module-hash -I %S/Inputs/module
+// RUN: c-index-test core -print-unit %t.idx | FileCheck %s
+
+// XFAIL: linux
+
+@import ModDep;
+@import ModSystem;
+
+// CHECK: ModDep.pcm
+// CHECK: provider: clang-
+// CHECK: is-system: 0
+// CHECK: is-module: 1
+// CHECK: module-name: ModDep
+// CHECK: has-main: 0
+// CHECK: main-path: {{$}}
+// CHECK: out-file: {{.*}}/ModDep.pcm
+// CHECK: DEPEND START
+// CHECK: Unit | user | ModTop | {{.*}}/ModTop.pcm | ModTop.pcm
+// CHECK: Record | user | ModDep | {{.*}}/Inputs/module/ModDep.h | ModDep.h
+// CHECK: DEPEND END (2)
+
+// CHECK: ModSystem.pcm
+// CHECK: is-system: 1
+// CHECK: is-module: 1
+// CHECK: module-name: ModSystem
+// CHECK: has-main: 0
+// CHECK: main-path: {{$}}
+// CHECK: out-file: {{.*}}/ModSystem.pcm
+// CHECK: DEPEND START
+// CHECK: Record | system | ModSystem | {{.*}}/Inputs/module/ModSystem.h | ModSystem.h
+// CHECK: DEPEND END (1)
+
+// CHECK: ModTop.pcm
+// CHECK: is-system: 0
+// CHECK: is-module: 1
+// CHECK: module-name: ModTop
+// CHECK: has-main: 0
+// CHECK: main-path: {{$}}
+// CHECK: out-file: {{.*}}/ModTop.pcm
+// CHECK: DEPEND START
+// CHECK: Record | user | ModTop | {{.*}}/Inputs/module/ModTop.h | ModTop.h
+// CHECK: Record | user | ModTop.Sub1 | {{.*}}/Inputs/module/ModTopSub1.h | ModTopSub1.h
+// CHECK: File | user | ModTop.Sub2 | {{.*}}/Inputs/module/ModTopSub2.h | | {{[0-9]*$}}
+// CHECK: DEPEND END (3)
+
+// CHECK: print-units-with-modules.m.tmp.o
+// CHECK: is-system: 0
+// CHECK: is-module: 0
+// CHECK: module-name: <none>
+// CHECK: has-main: 1
+// CHECK: main-path: {{.*}}/print-units-with-modules.m
+// CHECK: out-file: {{.*}}/print-units-with-modules.m.tmp.o
+// CHECK: DEPEND START
+// CHECK: Unit | user | ModDep | {{.*}}/ModDep.pcm | ModDep.pcm
+// CHECK: Unit | system | ModSystem | {{.*}}/ModSystem.pcm | ModSystem.pcm
+// CHECK: File | user | {{.*}}/print-units-with-modules.m | | {{[0-9]*$}}
+// CHECK: File | user | {{.*}}/Inputs/module/module.modulemap | | {{[0-9]*$}}
+// CHECK: DEPEND END (4)
diff --git a/test/Index/Store/print-units-with-pch.c b/test/Index/Store/print-units-with-pch.c
new file mode 100644
index 0000000..1e533a2
--- /dev/null
+++ b/test/Index/Store/print-units-with-pch.c
@@ -0,0 +1,29 @@
+// RUN: rm -rf %t.idx
+// RUN: %clang -arch x86_64 -mmacosx-version-min=10.7 -x c-header %S/Inputs/head.h -o %t.h.pch -index-store-path %t.idx
+// RUN: %clang -arch x86_64 -mmacosx-version-min=10.7 -c %s -o %t.o -index-store-path %t.idx -include %t.h -Werror
+// RUN: c-index-test core -print-unit %t.idx | FileCheck %s
+
+// XFAIL: linux
+
+int main() {
+  test1_func();
+}
+
+// CHECK: print-units-with-pch.c.tmp.h.pch
+// CHECK: is-system: 0
+// CHECK: has-main: 0
+// CHECK: main-path: {{$}}
+// CHECK: out-file: {{.*}}/print-units-with-pch.c.tmp.h.pch
+// CHECK: DEPEND START
+// CHECK: Record | user | {{.*}}/Inputs/head.h | head.h
+// CHECK: DEPEND END (1)
+
+// CHECK: print-units-with-pch.c.tmp.o
+// CHECK: is-system: 0
+// CHECK: has-main: 1
+// CHECK: main-path: {{.*}}/print-units-with-pch.c
+// CHECK: out-file: {{.*}}/print-units-with-pch.c.tmp.o
+// CHECK: DEPEND START
+// CHECK: Unit | user | {{.*}}/print-units-with-pch.c.tmp.h.pch | print-units-with-pch.c.tmp.h.pch
+// CHECK: Record | user | {{.*}}/print-units-with-pch.c | print-units-with-pch.c
+// CHECK: DEPEND END (2)
diff --git a/test/Index/Store/record-hash-crash.cpp b/test/Index/Store/record-hash-crash.cpp
new file mode 100644
index 0000000..8239901
--- /dev/null
+++ b/test/Index/Store/record-hash-crash.cpp
@@ -0,0 +1,12 @@
+// Makes sure it doesn't crash.
+
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 %s -index-store-path %t/idx -std=c++14
+// RUN: c-index-test core -print-record %t/idx | FileCheck %s
+
+namespace crash1 {
+// CHECK: [[@LINE+1]]:6 | function/C
+auto getit() { return []() {}; }
+}
diff --git a/test/Index/Store/record-hash.cpp b/test/Index/Store/record-hash.cpp
new file mode 100644
index 0000000..21a4dc4
--- /dev/null
+++ b/test/Index/Store/record-hash.cpp
@@ -0,0 +1,12 @@
+// XFAIL: linux
+
+// RUN: rm -rf %t
+// RUN: %clang_cc1 %s -index-store-path %t/idx -D THE_TYPE=long
+// RUN: %clang_cc1 %s -index-store-path %t/idx -D THE_TYPE=char
+// RUN: find %t/idx/*/records -name "record-hash*" | count 2
+
+template<typename T>
+class TC {};
+
+// This should result in different records, due to the different template parameter type.
+void some_func(TC<THE_TYPE>);
diff --git a/test/Index/Store/relative-out-path.c b/test/Index/Store/relative-out-path.c
new file mode 100644
index 0000000..1d47ea0
--- /dev/null
+++ b/test/Index/Store/relative-out-path.c
@@ -0,0 +1,19 @@
+// Needs 'find'.
+// REQUIRES: shell
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: %clang %s -index-store-path %t/idx1 -c -o %t/outfile.o
+// RUN: cd %t
+// RUN: %clang %s -index-store-path %t/idx2 -c -o outfile.o
+// RUN: cd ..
+// RUN: %clang %s -index-store-path %t/idx3 -fsyntax-only -o outfile.o -working-directory=%t
+// RUN: diff -r -u %t/idx2 %t/idx3
+
+// RUN: find %t/idx1 -name '*outfile.o*' > %t/hashes.txt
+// RUN: find %t/idx3 -name '*outfile.o*' >> %t/hashes.txt
+// RUN: FileCheck %s --input-file=%t/hashes.txt
+// CHECK:      outfile.o[[OUT_HASH:.*$]]
+// CHECK-NEXT: outfile.o[[OUT_HASH]]
+
+void foo();
diff --git a/test/Index/Store/syntax-only.c b/test/Index/Store/syntax-only.c
new file mode 100644
index 0000000..53d22bc
--- /dev/null
+++ b/test/Index/Store/syntax-only.c
@@ -0,0 +1,11 @@
+// RUN: rm -rf %t.idx
+// RUN: %clang -fsyntax-only %s -index-store-path %t.idx -o %T/syntax-only.c.myoutfile
+// RUN: c-index-test core -print-unit %t.idx | FileCheck %s -check-prefix=CHECK-UNIT
+// RUN: c-index-test core -print-record %t.idx | FileCheck %s -check-prefix=CHECK-RECORD
+
+// XFAIL: linux
+
+// CHECK-UNIT: out-file: {{.*}}/syntax-only.c.myoutfile
+// CHECK-RECORD: function/C | foo | c:@F@foo
+
+void foo();
diff --git a/test/Index/Store/unit-with-vfs.c b/test/Index/Store/unit-with-vfs.c
new file mode 100644
index 0000000..cbed626
--- /dev/null
+++ b/test/Index/Store/unit-with-vfs.c
@@ -0,0 +1,12 @@
+// RUN: sed -e "s:INPUT_DIR:%S/Inputs:g" -e "s:OUT_DIR:%t:g" %S/Inputs/overlay.yaml > %t.yaml
+// REQUIRES: shell
+
+#include "using-overlay.h"
+
+// RUN: rm -rf %t.idx
+// RUN: %clang_cc1 %s -index-store-path %t.idx -I %t -ivfsoverlay %t.yaml
+// RUN: c-index-test core -print-unit %t.idx | FileCheck %s
+
+// XFAIL: linux
+
+// CHECK: Record | user | {{.*}}test/Index/Store/Inputs/using-overlay.h
diff --git a/test/Index/Store/unit-workdir-prefix.c b/test/Index/Store/unit-workdir-prefix.c
new file mode 100644
index 0000000..e7a3a71
--- /dev/null
+++ b/test/Index/Store/unit-workdir-prefix.c
@@ -0,0 +1,30 @@
+// XFAIL: linux
+
+#include "header.h"
+
+void foo(void) {
+  bar();
+}
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/Directory
+// RUN: mkdir -p %t/Directory.surprise
+// RUN: mkdir -p %t/sdk
+// RUN: mkdir -p %t/sdk_other
+// RUN: echo "void bar(void);" > %t/sdk_other/header.h
+// RUN: cp %s %t/Directory.surprise/main.c
+//
+// RUN: %clang_cc1 -isystem %t/sdk_other -isysroot %t/sdk -index-store-path %t/idx %t/Directory.surprise/main.c -triple x86_64-apple-macosx10.8 -working-directory %t/Directory
+// RUN: c-index-test core -print-unit %t/idx | FileCheck %s
+
+// CHECK: main.c.o
+// CHECK: provider: clang-
+// CHECK: is-system: 0
+// CHECK: has-main: 1
+// CHECK: main-path: {{.*}}Directory.surprise{{/|\\}}main.c
+// CHECK: out-file: {{.*}}Directory.surprise{{/|\\}}main.c.o
+// CHECK: target: x86_64-apple-macosx10.8
+// CHECK: is-debug: 1
+// CHECK: DEPEND START
+// CHECK: Record | user | {{.*}}Directory.surprise{{/|\\}}main.c | main.c-
+// CHECK: Record | system | {{.*}}sdk_other{{/|\\}}header.h | header.h-
diff --git a/test/Index/Store/using-libstdcpp-arc.mm b/test/Index/Store/using-libstdcpp-arc.mm
new file mode 100644
index 0000000..9738c86
--- /dev/null
+++ b/test/Index/Store/using-libstdcpp-arc.mm
@@ -0,0 +1,10 @@
+// Test to make sure we don't crash, rdar://30816887.
+
+// RUN: rm -rf %t.idx
+// RUN: %clang_cc1 %s -index-store-path %t.idx -fobjc-arc -fobjc-arc-cxxlib=libstdc++
+// RUN: c-index-test core -print-record %t.idx | FileCheck %s
+
+// XFAIL: linux
+
+// CHECK: [[@LINE+1]]:6 | function/C
+void test1(void);
diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt
index b0c97f0..96ed5f5 100644
--- a/tools/CMakeLists.txt
+++ b/tools/CMakeLists.txt
@@ -9,6 +9,7 @@
 add_clang_subdirectory(clang-offload-bundler)
 
 add_clang_subdirectory(c-index-test)
+add_clang_subdirectory(IndexStore)
 
 if(CLANG_ENABLE_ARCMT)
   add_clang_subdirectory(arcmt-test)
diff --git a/tools/IndexStore/CMakeLists.txt b/tools/IndexStore/CMakeLists.txt
new file mode 100644
index 0000000..8ad6499
--- /dev/null
+++ b/tools/IndexStore/CMakeLists.txt
@@ -0,0 +1,94 @@
+include(CheckIncludeFiles)
+
+set(SOURCES
+  IndexStore.cpp
+
+  ADDITIONAL_HEADERS
+  ../../include/indexstore/indexstore.h
+  ../../include/indexstore/IndexStoreCXX.h
+  )
+
+set(LIBS
+  clangDirectoryWatcher
+  clangIndex
+)
+
+set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/IndexStore.exports)
+
+set(ENABLE_SHARED SHARED)
+
+if(WIN32)
+  set(output_name "libIndexStore")
+else()
+  set(output_name "IndexStore")
+endif()
+
+# FIXME: needs to be ported to non-Apple platforms.
+if(APPLE)
+
+add_clang_library(IndexStore ${ENABLE_SHARED} ${ENABLE_STATIC}
+  OUTPUT_NAME ${output_name}
+  ${SOURCES}
+
+  LINK_LIBS
+  ${LIBS}
+
+  LINK_COMPONENTS
+  ${LLVM_TARGETS_TO_BUILD}
+  Core
+  Support
+  )
+
+set(INDEXSTORE_LIBRARY_VERSION "${LLVM_VERSION_MAJOR}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
+
+if(ENABLE_SHARED)
+  if(WIN32)
+    set_target_properties(IndexStore
+      PROPERTIES
+      VERSION ${INDEXSTORE_LIBRARY_VERSION}
+      DEFINE_SYMBOL _CINDEX_LIB_)
+  elseif(APPLE)
+    set(INDEXSTORE_LINK_FLAGS " -Wl,-compatibility_version -Wl,1")
+    set(INDEXSTORE_LINK_FLAGS "${INDEXSTORE_LINK_FLAGS} -Wl,-current_version -Wl,${INDEXSTORE_LIBRARY_VERSION}")
+
+    check_include_files("CoreServices/CoreServices.h" HAVE_CORESERVICES_H)
+    if(HAVE_CORESERVICES_H)
+      set(INDEXSTORE_LINK_FLAGS "${INDEXSTORE_LINK_FLAGS} -framework CoreServices")
+    endif()
+
+    set_property(TARGET IndexStore APPEND_STRING PROPERTY
+                 LINK_FLAGS ${INDEXSTORE_LINK_FLAGS})
+  else()
+    set_target_properties(IndexStore
+      PROPERTIES
+      VERSION ${INDEXSTORE_LIBRARY_VERSION}
+      DEFINE_SYMBOL _CINDEX_LIB_)
+  endif()
+endif()
+
+if (LLVM_INSTALL_TOOLCHAIN_ONLY)
+  install(TARGETS IndexStore
+    COMPONENT IndexStore
+    LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+    ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX}
+    RUNTIME DESTINATION bin)
+
+  if (NOT CMAKE_CONFIGURATION_TYPES)
+    add_custom_target(install-IndexStore
+                      DEPENDS IndexStore
+                      COMMAND "${CMAKE_COMMAND}"
+                              -DCMAKE_INSTALL_COMPONENT=IndexStore
+                              -P "${CMAKE_BINARY_DIR}/cmake_install.cmake")
+  endif()
+endif()
+
+set(INDEXSTORE_HEADERS_INSTALL_DESTINATION "local/include")
+
+install(DIRECTORY ../../include/indexstore
+  COMPONENT IndexStore
+  DESTINATION "${INDEXSTORE_HEADERS_INSTALL_DESTINATION}"
+  FILES_MATCHING
+  PATTERN "*.h"
+  PATTERN ".svn" EXCLUDE
+  )
+endif()
diff --git a/tools/IndexStore/IndexStore.cpp b/tools/IndexStore/IndexStore.cpp
new file mode 100644
index 0000000..4226524
--- /dev/null
+++ b/tools/IndexStore/IndexStore.cpp
@@ -0,0 +1,647 @@
+//===- IndexStore.cpp - Index store API -----------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the API for the index store.
+//
+//===----------------------------------------------------------------------===//
+
+#include "indexstore/indexstore.h"
+#include "clang/Index/IndexDataStore.h"
+#include "clang/Index/IndexDataStoreSymbolUtils.h"
+#include "clang/Index/IndexRecordReader.h"
+#include "clang/Index/IndexUnitReader.h"
+#include "clang/Index/IndexUnitWriter.h"
+#include "clang/DirectoryWatcher/DirectoryWatcher.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Chrono.h"
+#include <Block.h>
+
+using namespace clang;
+using namespace clang::index;
+using namespace llvm;
+
+static indexstore_string_ref_t toIndexStoreString(StringRef str) {
+  return indexstore_string_ref_t{ str.data(), str.size() };
+}
+
+static timespec toTimeSpec(sys::TimePoint<> tp) {
+  std::chrono::seconds sec = std::chrono::time_point_cast<std::chrono::seconds>(
+                 tp).time_since_epoch();
+  std::chrono::nanoseconds nsec =
+    std::chrono::time_point_cast<std::chrono::nanoseconds>(tp - sec)
+      .time_since_epoch();
+  timespec ts;
+  ts.tv_sec = sec.count();
+  ts.tv_nsec = nsec.count();
+  return ts;
+}
+
+namespace {
+
+struct IndexStoreError {
+  std::string Error;
+};
+
+} // anonymous namespace
+
+const char *
+indexstore_error_get_description(indexstore_error_t err) {
+  return static_cast<IndexStoreError*>(err)->Error.c_str();
+}
+
+void
+indexstore_error_dispose(indexstore_error_t err) {
+  delete static_cast<IndexStoreError*>(err);
+}
+
+unsigned
+indexstore_format_version(void) {
+  return IndexDataStore::getFormatVersion();
+}
+
+indexstore_t
+indexstore_store_create(const char *store_path, indexstore_error_t *c_error) {
+  std::unique_ptr<IndexDataStore> store;
+  std::string error;
+  store = IndexDataStore::create(store_path, error);
+  if (!store) {
+    if (c_error)
+      *c_error = new IndexStoreError{ error };
+    return nullptr;
+  }
+  return store.release();
+}
+
+void
+indexstore_store_dispose(indexstore_t store) {
+  delete static_cast<IndexDataStore*>(store);
+}
+
+#if INDEXSTORE_HAS_BLOCKS
+bool
+indexstore_store_units_apply(indexstore_t c_store, unsigned sorted,
+                            bool(^applier)(indexstore_string_ref_t unit_name)) {
+  IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
+  return store->foreachUnitName(sorted, [&](StringRef unitName) -> bool {
+    return applier(toIndexStoreString(unitName));
+  });
+}
+
+size_t
+indexstore_unit_event_notification_get_events_count(indexstore_unit_event_notification_t c_evtnote) {
+  auto *evtnote = static_cast<IndexDataStore::UnitEventNotification*>(c_evtnote);
+  return evtnote->Events.size();
+}
+
+indexstore_unit_event_t
+indexstore_unit_event_notification_get_event(indexstore_unit_event_notification_t c_evtnote, size_t index) {
+  auto *evtnote = static_cast<IndexDataStore::UnitEventNotification*>(c_evtnote);
+  return (indexstore_unit_event_t)&evtnote->Events[index];
+}
+
+bool
+indexstore_unit_event_notification_is_initial(indexstore_unit_event_notification_t c_evtnote) {
+  auto *evtnote = static_cast<IndexDataStore::UnitEventNotification*>(c_evtnote);
+  return evtnote->IsInitial;
+}
+
+indexstore_unit_event_kind_t
+indexstore_unit_event_get_kind(indexstore_unit_event_t c_evt) {
+  auto *evt = static_cast<IndexDataStore::UnitEvent*>(c_evt);
+  indexstore_unit_event_kind_t k;
+  switch (evt->Kind) {
+    case IndexDataStore::UnitEventKind::Added:
+      k = INDEXSTORE_UNIT_EVENT_ADDED; break;
+    case IndexDataStore::UnitEventKind::Removed:
+      k = INDEXSTORE_UNIT_EVENT_REMOVED; break;
+    case IndexDataStore::UnitEventKind::Modified:
+      k = INDEXSTORE_UNIT_EVENT_MODIFIED; break;
+    case IndexDataStore::UnitEventKind::DirectoryDeleted:
+      k = INDEXSTORE_UNIT_EVENT_DIRECTORY_DELETED; break;
+  }
+  return k;
+}
+
+indexstore_string_ref_t
+indexstore_unit_event_get_unit_name(indexstore_unit_event_t c_evt) {
+  auto *evt = static_cast<IndexDataStore::UnitEvent*>(c_evt);
+  return toIndexStoreString(evt->UnitName);
+}
+
+timespec
+indexstore_unit_event_get_modification_time(indexstore_unit_event_t c_evt) {
+  auto *evt = static_cast<IndexDataStore::UnitEvent*>(c_evt);
+  return evt->ModTime;
+}
+
+void
+indexstore_store_set_unit_event_handler(indexstore_t c_store,
+                                    indexstore_unit_event_handler_t blk_handler) {
+  IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
+  if (!blk_handler) {
+    store->setUnitEventHandler(nullptr);
+    return;
+  }
+
+  class BlockWrapper {
+    indexstore_unit_event_handler_t blk_handler;
+  public:
+    BlockWrapper(indexstore_unit_event_handler_t handler) {
+      blk_handler = Block_copy(handler);
+    }
+    BlockWrapper(const BlockWrapper &other) {
+      blk_handler = Block_copy(other.blk_handler);
+    }
+    ~BlockWrapper() {
+      Block_release(blk_handler);
+    }
+
+    void operator()(indexstore_unit_event_notification_t evt_note) const {
+      blk_handler(evt_note);
+    }
+  };
+
+  BlockWrapper handler(blk_handler);
+
+  store->setUnitEventHandler([handler](IndexDataStore::UnitEventNotification evtNote) {
+    handler(&evtNote);
+  });
+}
+#endif
+
+bool
+indexstore_store_start_unit_event_listening(indexstore_t c_store,
+                                            indexstore_unit_event_listen_options_t *client_opts,
+                                            size_t listen_options_struct_size,
+                                            indexstore_error_t *c_error) {
+  IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
+  indexstore_unit_event_listen_options_t listen_opts;
+  memset(&listen_opts, 0, sizeof(listen_opts));
+  unsigned clientOptSize = listen_options_struct_size < sizeof(listen_opts)
+                             ? listen_options_struct_size : sizeof(listen_opts);
+  memcpy(&listen_opts, client_opts, clientOptSize);
+
+  std::string error;
+  auto createFn = [](StringRef Path, AbstractDirectoryWatcher::EventReceiver Receiver, bool waitInitialSync, std::string &Error)
+      -> std::unique_ptr<AbstractDirectoryWatcher> {
+    return DirectoryWatcher::create(Path, std::move(Receiver), waitInitialSync, Error);
+  };
+  bool err = store->startEventListening(createFn, listen_opts.wait_initial_sync, error);
+  if (err && c_error)
+    *c_error = new IndexStoreError{ error };
+  return err;
+}
+
+void
+indexstore_store_stop_unit_event_listening(indexstore_t c_store) {
+  IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
+  store->stopEventListening();
+}
+
+void
+indexstore_store_discard_unit(indexstore_t c_store, const char *unit_name) {
+  IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
+  store->discardUnit(unit_name);
+}
+
+void
+indexstore_store_discard_record(indexstore_t c_store, const char *record_name) {
+  IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
+  store->discardRecord(record_name);
+}
+
+void
+indexstore_store_purge_stale_data(indexstore_t c_store) {
+  IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
+  store->purgeStaleData();
+}
+
+indexstore_symbol_kind_t
+indexstore_symbol_get_kind(indexstore_symbol_t sym) {
+  return getIndexStoreKind(static_cast<IndexRecordDecl *>(sym)->SymInfo.Kind);
+}
+
+indexstore_symbol_subkind_t
+indexstore_symbol_get_subkind(indexstore_symbol_t sym) {
+  return getIndexStoreSubKind(static_cast<IndexRecordDecl *>(sym)->SymInfo.SubKind);
+}
+
+indexstore_symbol_language_t
+indexstore_symbol_get_language(indexstore_symbol_t sym) {
+  return getIndexStoreLang(static_cast<IndexRecordDecl *>(sym)->SymInfo.Lang);
+}
+
+uint64_t
+indexstore_symbol_get_properties(indexstore_symbol_t sym) {
+  return getIndexStoreProperties(static_cast<IndexRecordDecl *>(sym)->SymInfo.Properties);
+}
+
+uint64_t
+indexstore_symbol_get_roles(indexstore_symbol_t sym) {
+  return getIndexStoreRoles(static_cast<IndexRecordDecl *>(sym)->Roles);
+}
+
+uint64_t
+indexstore_symbol_get_related_roles(indexstore_symbol_t sym) {
+  return getIndexStoreRoles(static_cast<IndexRecordDecl *>(sym)->RelatedRoles);
+}
+
+indexstore_string_ref_t
+indexstore_symbol_get_name(indexstore_symbol_t sym) {
+  auto *D = static_cast<IndexRecordDecl*>(sym);
+  return toIndexStoreString(D->Name);
+}
+
+indexstore_string_ref_t
+indexstore_symbol_get_usr(indexstore_symbol_t sym) {
+  auto *D = static_cast<IndexRecordDecl*>(sym);
+  return toIndexStoreString(D->USR);
+}
+
+indexstore_string_ref_t
+indexstore_symbol_get_codegen_name(indexstore_symbol_t sym) {
+  auto *D = static_cast<IndexRecordDecl*>(sym);
+  return toIndexStoreString(D->CodeGenName);
+}
+
+uint64_t
+indexstore_symbol_relation_get_roles(indexstore_symbol_relation_t sym_rel) {
+  return getIndexStoreRoles(static_cast<IndexRecordRelation *>(sym_rel)->Roles);
+}
+
+indexstore_symbol_t
+indexstore_symbol_relation_get_symbol(indexstore_symbol_relation_t sym_rel) {
+  return (indexstore_symbol_t)static_cast<IndexRecordRelation*>(sym_rel)->Dcl;
+}
+
+indexstore_symbol_t
+indexstore_occurrence_get_symbol(indexstore_occurrence_t occur) {
+  return (indexstore_symbol_t)static_cast<IndexRecordOccurrence*>(occur)->Dcl;
+}
+
+#if INDEXSTORE_HAS_BLOCKS
+bool
+indexstore_occurrence_relations_apply(indexstore_occurrence_t occur,
+                      bool(^applier)(indexstore_symbol_relation_t symbol_rel)) {
+  auto *recOccur = static_cast<IndexRecordOccurrence*>(occur);
+  for (auto &rel : recOccur->Relations) {
+    if (!applier(&rel))
+      return false;
+  }
+  return true;
+}
+#endif
+
+uint64_t
+indexstore_occurrence_get_roles(indexstore_occurrence_t occur) {
+  return static_cast<IndexRecordOccurrence*>(occur)->Roles;
+}
+
+void
+indexstore_occurrence_get_line_col(indexstore_occurrence_t occur,
+                              unsigned *line, unsigned *column) {
+  auto *recOccur = static_cast<IndexRecordOccurrence*>(occur);
+  if (line)
+    *line = recOccur->Line;
+  if (column)
+    *column = recOccur->Column;
+}
+
+typedef void *indexstore_record_reader_t;
+
+indexstore_record_reader_t
+indexstore_record_reader_create(indexstore_t c_store, const char *record_name,
+                                indexstore_error_t *c_error) {
+  IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
+  std::unique_ptr<IndexRecordReader> reader;
+  std::string error;
+  reader = IndexRecordReader::createWithRecordFilename(record_name,
+                                                       store->getFilePath(),
+                                                       error);
+  if (!reader) {
+    if (c_error)
+      *c_error = new IndexStoreError{ error };
+    return nullptr;
+  }
+  return reader.release();
+}
+
+void
+indexstore_record_reader_dispose(indexstore_record_reader_t rdr) {
+  auto *reader = static_cast<IndexRecordReader *>(rdr);
+  delete reader;
+}
+
+#if INDEXSTORE_HAS_BLOCKS
+/// Goes through the symbol data and passes symbols to \c receiver, for the
+/// symbol data that \c filter returns true on.
+///
+/// This allows allocating memory only for the record symbols that the caller is
+/// interested in.
+bool
+indexstore_record_reader_search_symbols(indexstore_record_reader_t rdr,
+    bool(^filter)(indexstore_symbol_t symbol, bool *stop),
+    void(^receiver)(indexstore_symbol_t symbol)) {
+  auto *reader = static_cast<IndexRecordReader *>(rdr);
+
+  auto filterFn = [&](const IndexRecordDecl &D) -> IndexRecordReader::DeclSearchReturn {
+    bool stop = false;
+    bool accept = filter((indexstore_symbol_t)&D, &stop);
+    return { accept, !stop };
+  };
+  auto receiverFn = [&](const IndexRecordDecl *D) {
+    receiver((indexstore_symbol_t)D);
+  };
+
+  return reader->searchDecls(filterFn, receiverFn);
+}
+
+bool
+indexstore_record_reader_symbols_apply(indexstore_record_reader_t rdr,
+                                        bool nocache,
+                                   bool(^applier)(indexstore_symbol_t symbol)) {
+  auto *reader = static_cast<IndexRecordReader *>(rdr);
+  auto receiverFn = [&](const IndexRecordDecl *D) -> bool {
+    return applier((indexstore_symbol_t)D);
+  };
+  return reader->foreachDecl(nocache, receiverFn);
+}
+
+bool
+indexstore_record_reader_occurrences_apply(indexstore_record_reader_t rdr,
+                                bool(^applier)(indexstore_occurrence_t occur)) {
+  auto *reader = static_cast<IndexRecordReader *>(rdr);
+  auto receiverFn = [&](const IndexRecordOccurrence &RO) -> bool {
+    return applier((indexstore_occurrence_t)&RO);
+  };
+  return reader->foreachOccurrence(receiverFn);
+}
+
+bool
+indexstore_record_reader_occurrences_in_line_range_apply(indexstore_record_reader_t rdr,
+                                                         unsigned line_start,
+                                                         unsigned line_count,
+                                bool(^applier)(indexstore_occurrence_t occur)) {
+  auto *reader = static_cast<IndexRecordReader *>(rdr);
+  auto receiverFn = [&](const IndexRecordOccurrence &RO) -> bool {
+    return applier((indexstore_occurrence_t)&RO);
+  };
+  return reader->foreachOccurrenceInLineRange(line_start, line_count, receiverFn);
+}
+
+/// \param symbols if non-zero \c symbols_count, indicates the list of symbols
+/// that we want to get occurrences for. An empty array indicates that we want
+/// occurrences for all symbols.
+/// \param related_symbols Same as \c symbols but for related symbols.
+bool
+indexstore_record_reader_occurrences_of_symbols_apply(indexstore_record_reader_t rdr,
+        indexstore_symbol_t *symbols, size_t symbols_count,
+        indexstore_symbol_t *related_symbols, size_t related_symbols_count,
+        bool(^applier)(indexstore_occurrence_t occur)) {
+  auto *reader = static_cast<IndexRecordReader *>(rdr);
+  auto receiverFn = [&](const IndexRecordOccurrence &RO) -> bool {
+    return applier((indexstore_occurrence_t)&RO);
+  };
+  return reader->foreachOccurrence({(IndexRecordDecl**)symbols, symbols_count},
+                                   {(IndexRecordDecl**)related_symbols, related_symbols_count},
+                                   receiverFn);
+}
+#endif
+
+size_t
+indexstore_store_get_unit_name_from_output_path(indexstore_t store,
+                                                const char *output_path,
+                                                char *name_buf,
+                                                size_t buf_size) {
+  SmallString<256> unitName;
+  IndexUnitWriter::getUnitNameForAbsoluteOutputFile(output_path, unitName);
+  size_t nameLen = unitName.size();
+  strlcpy(name_buf, unitName.c_str(), buf_size);
+  return nameLen;
+}
+
+bool
+indexstore_store_get_unit_modification_time(indexstore_t c_store,
+                                            const char *unit_name,
+                                            int64_t *seconds,
+                                            int64_t *nanoseconds,
+                                            indexstore_error_t *c_error) {
+  IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
+  std::string error;
+  // FIXME: This provides mod time with second-only accuracy.
+  auto optModTime = IndexUnitReader::getModificationTimeForUnit(unit_name,
+                                              store->getFilePath(), error);
+  if (!optModTime) {
+    if (c_error)
+      *c_error = new IndexStoreError{ error };
+    return true;
+  }
+
+  timespec ts = toTimeSpec(*optModTime);
+  if (seconds)
+    *seconds = ts.tv_sec;
+  if (nanoseconds)
+    *nanoseconds = ts.tv_nsec;
+
+  return false;
+}
+
+indexstore_unit_reader_t
+indexstore_unit_reader_create(indexstore_t c_store, const char *unit_name,
+                              indexstore_error_t *c_error) {
+  IndexDataStore *store = static_cast<IndexDataStore*>(c_store);
+  std::unique_ptr<IndexUnitReader> reader;
+  std::string error;
+  reader = IndexUnitReader::createWithUnitFilename(unit_name,
+                                                   store->getFilePath(), error);
+  if (!reader) {
+    if (c_error)
+      *c_error = new IndexStoreError{ error };
+    return nullptr;
+  }
+  return reader.release();
+}
+
+void
+indexstore_unit_reader_dispose(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  delete reader;
+}
+
+indexstore_string_ref_t
+indexstore_unit_reader_get_provider_identifier(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return toIndexStoreString(reader->getProviderIdentifier());
+}
+
+indexstore_string_ref_t
+indexstore_unit_reader_get_provider_version(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return toIndexStoreString(reader->getProviderVersion());
+}
+
+void
+indexstore_unit_reader_get_modification_time(indexstore_unit_reader_t rdr,
+                                             int64_t *seconds,
+                                             int64_t *nanoseconds) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  // FIXME: This provides mod time with second-only accuracy.
+  sys::TimePoint<> timeVal = reader->getModificationTime();
+  timespec ts = toTimeSpec(timeVal);
+  if (seconds)
+    *seconds = ts.tv_sec;
+  if (nanoseconds)
+    *nanoseconds = ts.tv_nsec;
+}
+
+bool
+indexstore_unit_reader_is_system_unit(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return reader->isSystemUnit();
+}
+
+bool
+indexstore_unit_reader_is_module_unit(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return reader->isModuleUnit();
+}
+
+bool
+indexstore_unit_reader_is_debug_compilation(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return reader->isDebugCompilation();
+}
+
+bool
+indexstore_unit_reader_has_main_file(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return reader->hasMainFile();
+}
+
+indexstore_string_ref_t
+indexstore_unit_reader_get_main_file(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return toIndexStoreString(reader->getMainFilePath());
+}
+
+indexstore_string_ref_t
+indexstore_unit_reader_get_module_name(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return toIndexStoreString(reader->getModuleName());
+}
+
+indexstore_string_ref_t
+indexstore_unit_reader_get_working_dir(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return toIndexStoreString(reader->getWorkingDirectory());
+}
+
+indexstore_string_ref_t
+indexstore_unit_reader_get_output_file(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return toIndexStoreString(reader->getOutputFile());
+}
+
+indexstore_string_ref_t
+indexstore_unit_reader_get_sysroot_path(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return toIndexStoreString(reader->getSysrootPath());
+}
+
+indexstore_string_ref_t
+indexstore_unit_reader_get_target(indexstore_unit_reader_t rdr) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return toIndexStoreString(reader->getTarget());
+}
+
+indexstore_unit_dependency_kind_t
+indexstore_unit_dependency_get_kind(indexstore_unit_dependency_t c_dep) {
+  auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
+  switch (dep->Kind) {
+  case IndexUnitReader::DependencyKind::Unit: return INDEXSTORE_UNIT_DEPENDENCY_UNIT;
+  case IndexUnitReader::DependencyKind::Record: return INDEXSTORE_UNIT_DEPENDENCY_RECORD;
+  case IndexUnitReader::DependencyKind::File: return INDEXSTORE_UNIT_DEPENDENCY_FILE;
+  }
+}
+
+bool
+indexstore_unit_dependency_is_system(indexstore_unit_dependency_t c_dep) {
+  auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
+  return dep->IsSystem;
+}
+
+indexstore_string_ref_t
+indexstore_unit_dependency_get_filepath(indexstore_unit_dependency_t c_dep) {
+  auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
+  return toIndexStoreString(dep->FilePath);
+}
+
+indexstore_string_ref_t
+indexstore_unit_dependency_get_modulename(indexstore_unit_dependency_t c_dep) {
+  auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
+  return toIndexStoreString(dep->ModuleName);
+}
+
+indexstore_string_ref_t
+indexstore_unit_dependency_get_name(indexstore_unit_dependency_t c_dep) {
+  auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
+  return toIndexStoreString(dep->UnitOrRecordName);
+}
+
+time_t
+indexstore_unit_dependency_get_modification_time(indexstore_unit_dependency_t c_dep) {
+  auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
+  return dep->ModTime;
+}
+
+size_t
+indexstore_unit_dependency_get_file_size(indexstore_unit_dependency_t c_dep) {
+  auto dep = static_cast<const IndexUnitReader::DependencyInfo*>(c_dep);
+  return dep->FileSize;
+}
+
+indexstore_string_ref_t
+indexstore_unit_include_get_source_path(indexstore_unit_include_t c_inc) {
+  auto inc = static_cast<const IndexUnitReader::IncludeInfo*>(c_inc);
+  return toIndexStoreString(inc->SourcePath);
+}
+
+indexstore_string_ref_t
+indexstore_unit_include_get_target_path(indexstore_unit_include_t c_inc) {
+  auto inc = static_cast<const IndexUnitReader::IncludeInfo*>(c_inc);
+  return toIndexStoreString(inc->TargetPath);
+}
+
+unsigned
+indexstore_unit_include_get_source_line(indexstore_unit_include_t c_inc) {
+  auto inc = static_cast<const IndexUnitReader::IncludeInfo*>(c_inc);
+  return inc->SourceLine;
+}
+
+#if INDEXSTORE_HAS_BLOCKS
+bool
+indexstore_unit_reader_dependencies_apply(indexstore_unit_reader_t rdr,
+                             bool(^applier)(indexstore_unit_dependency_t)) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return reader->foreachDependency([&](const IndexUnitReader::DependencyInfo &depInfo) -> bool {
+    return applier((void*)&depInfo);
+  });
+}
+
+bool
+indexstore_unit_reader_includes_apply(indexstore_unit_reader_t rdr,
+                             bool(^applier)(indexstore_unit_include_t)) {
+  auto reader = static_cast<IndexUnitReader*>(rdr);
+  return reader->foreachInclude([&](const IndexUnitReader::IncludeInfo &incInfo) -> bool {
+    return applier((void*)&incInfo);
+  });
+}
+#endif
diff --git a/tools/IndexStore/IndexStore.exports b/tools/IndexStore/IndexStore.exports
new file mode 100644
index 0000000..70c174f
--- /dev/null
+++ b/tools/IndexStore/IndexStore.exports
@@ -0,0 +1,69 @@
+indexstore_error_get_description
+indexstore_error_dispose
+indexstore_format_version
+indexstore_store_create
+indexstore_store_dispose
+indexstore_store_get_unit_modification_time
+indexstore_store_get_unit_name_from_output_path
+indexstore_store_units_apply
+indexstore_store_set_unit_event_handler
+indexstore_store_start_unit_event_listening
+indexstore_store_stop_unit_event_listening
+indexstore_store_discard_unit
+indexstore_store_discard_record
+indexstore_store_purge_stale_data
+indexstore_symbol_get_kind
+indexstore_symbol_get_language
+indexstore_symbol_get_properties
+indexstore_symbol_get_roles
+indexstore_symbol_get_related_roles
+indexstore_symbol_get_subkind
+indexstore_symbol_get_name
+indexstore_symbol_get_usr
+indexstore_symbol_get_codegen_name
+indexstore_symbol_relation_get_roles
+indexstore_symbol_relation_get_symbol
+indexstore_occurrence_get_symbol
+indexstore_occurrence_get_roles
+indexstore_occurrence_get_line_col
+indexstore_occurrence_relations_apply
+indexstore_record_reader_create
+indexstore_record_reader_dispose
+indexstore_record_reader_search_symbols
+indexstore_record_reader_symbols_apply
+indexstore_record_reader_occurrences_apply
+indexstore_record_reader_occurrences_in_line_range_apply
+indexstore_record_reader_occurrences_of_symbols_apply
+indexstore_unit_dependency_get_kind
+indexstore_unit_dependency_get_filepath
+indexstore_unit_dependency_get_file_size
+indexstore_unit_dependency_get_modification_time
+indexstore_unit_dependency_get_modulename
+indexstore_unit_dependency_get_name
+indexstore_unit_dependency_is_system
+indexstore_unit_event_get_kind
+indexstore_unit_event_get_modification_time
+indexstore_unit_event_get_unit_name
+indexstore_unit_event_notification_get_event
+indexstore_unit_event_notification_get_events_count
+indexstore_unit_event_notification_is_initial
+indexstore_unit_reader_create
+indexstore_unit_reader_dispose
+indexstore_unit_reader_get_main_file
+indexstore_unit_reader_get_modification_time
+indexstore_unit_reader_get_module_name
+indexstore_unit_reader_get_provider_identifier
+indexstore_unit_reader_get_provider_version
+indexstore_unit_reader_get_working_dir
+indexstore_unit_reader_get_output_file
+indexstore_unit_reader_get_sysroot_path
+indexstore_unit_reader_get_target
+indexstore_unit_reader_dependencies_apply
+indexstore_unit_reader_includes_apply
+indexstore_unit_reader_has_main_file
+indexstore_unit_reader_is_debug_compilation
+indexstore_unit_reader_is_module_unit
+indexstore_unit_reader_is_system_unit
+indexstore_unit_include_get_source_path
+indexstore_unit_include_get_target_path
+indexstore_unit_include_get_source_line
diff --git a/tools/c-index-test/CMakeLists.txt b/tools/c-index-test/CMakeLists.txt
index 7244e2c..c08ca7b 100644
--- a/tools/c-index-test/CMakeLists.txt
+++ b/tools/c-index-test/CMakeLists.txt
@@ -1,3 +1,5 @@
+include(CheckIncludeFiles)
+
 set(LLVM_LINK_COMPONENTS
   support
 )
@@ -5,8 +7,15 @@
 add_clang_executable(c-index-test
   c-index-test.c
   core_main.cpp
+  JSONAggregation.cpp
   )
 
+set(INDEXSTORE_LIB)
+set(CINDEXTEST_LIBS)
+if(APPLE)
+  set(INDEXSTORE_LIB IndexStore)
+endif()
+
 if(NOT MSVC)
   set_property(
     SOURCE c-index-test.c
@@ -18,16 +27,20 @@
   target_link_libraries(c-index-test
     libclang_static
     clangIndex
+    ${CINDEXTEST_LIBS}
   )
 else()
   target_link_libraries(c-index-test
     libclang
+    ${INDEXSTORE_LIB}
     clangAST
     clangBasic
     clangCodeGen
+    clangDirectoryWatcher
     clangFrontend
     clangIndex
     clangSerialization
+    ${CINDEXTEST_LIBS}
   )
 endif()
 
@@ -41,6 +54,13 @@
   target_link_libraries(c-index-test ${LIBXML2_LIBRARIES})
 endif()
 
+if(APPLE)
+  check_include_files("CoreServices/CoreServices.h" HAVE_CORESERVICES_H)
+  if(HAVE_CORESERVICES_H)
+    target_link_libraries(c-index-test "-framework CoreServices")
+  endif()
+endif()
+
 if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
   if(INTERNAL_INSTALL_PREFIX)
     set(INSTALL_DESTINATION "${INTERNAL_INSTALL_PREFIX}/bin")
diff --git a/tools/c-index-test/JSONAggregation.cpp b/tools/c-index-test/JSONAggregation.cpp
new file mode 100644
index 0000000..c7f4136
--- /dev/null
+++ b/tools/c-index-test/JSONAggregation.cpp
@@ -0,0 +1,409 @@
+//===--- JSONAggregation.cpp - Index data aggregation in JSON format ------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JSONAggregation.h"
+#include "indexstore/IndexStoreCXX.h"
+#include "clang/Index/IndexDataStoreSymbolUtils.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace clang;
+using namespace clang::index;
+using namespace indexstore;
+using namespace llvm;
+
+#if INDEXSTORE_HAS_BLOCKS
+
+namespace {
+
+typedef size_t FilePathIndex;
+typedef size_t RecordIndex;
+typedef size_t SymbolIndex;
+
+struct UnitSourceInfo {
+  FilePathIndex FilePath;
+  SmallVector<RecordIndex, 2> AssociatedRecords;
+};
+
+struct UnitInfo {
+  std::string Name;
+  SmallVector<UnitSourceInfo, 8> Sources;
+  SmallVector<std::string, 3> UnitDepends;
+  FilePathIndex OutFile;
+  StringRef Triple;
+};
+
+struct SymbolInfo {
+  SymbolKind Kind;
+  SymbolLanguage Lang;
+  StringRef USR;
+  StringRef Name;
+  StringRef CodegenName;
+  SymbolRoleSet Roles = 0;
+  SymbolRoleSet RelatedRoles = 0;
+};
+
+struct SymbolRelationInfo {
+  SymbolIndex RelatedSymbol;
+  SymbolRoleSet Roles;
+  SymbolRelationInfo(SymbolIndex relSymbol, SymbolRoleSet roles)
+    : RelatedSymbol(relSymbol), Roles(roles) {}
+};
+
+struct SymbolOccurrenceInfo {
+  SymbolIndex Symbol;
+  SymbolRoleSet Roles = 0;
+  std::vector<SymbolRelationInfo> Relations;
+  unsigned Line;
+  unsigned Column;
+};
+
+struct RecordInfo {
+  SmallVector<SymbolOccurrenceInfo, 8> Occurrences;
+};
+
+class Aggregator {
+  IndexStore Store;
+
+  BumpPtrAllocator Allocator;
+
+  StringMap<FilePathIndex, BumpPtrAllocator &> FilePathIndices;
+  std::vector<StringRef> FilePaths;
+  StringMap<char, BumpPtrAllocator &> Triples;
+
+  std::vector<std::unique_ptr<UnitInfo>> Units;
+
+  StringMap<RecordIndex, BumpPtrAllocator &> RecordIndices;
+  std::vector<std::unique_ptr<RecordInfo>> Records;
+
+  StringMap<SymbolIndex, BumpPtrAllocator &> SymbolIndices;
+  std::vector<SymbolInfo> Symbols;
+
+public:
+  explicit Aggregator(IndexStore store)
+  : Store(std::move(store)),
+    FilePathIndices(Allocator),
+    Triples(Allocator),
+    RecordIndices(Allocator),
+    SymbolIndices(Allocator) {}
+
+  bool process();
+  void processUnit(StringRef name, IndexUnitReader &UnitReader);
+  void dumpJSON(raw_ostream &OS);
+
+private:
+  StringRef copyStr(StringRef str) {
+    if (str.empty())
+      return StringRef();
+    char *buf = Allocator.Allocate<char>(str.size());
+    std::copy(str.begin(), str.end(), buf);
+    return StringRef(buf, str.size());
+  }
+
+  StringRef getTripleString(StringRef inputTriple) {
+    return Triples.insert(std::make_pair(inputTriple, 0)).first->first();
+  }
+
+  FilePathIndex getFilePathIndex(StringRef path, StringRef workingDir);
+  RecordIndex getRecordIndex(StringRef recordFile);
+  SymbolIndex getSymbolIndex(IndexRecordSymbol sym);
+  std::unique_ptr<RecordInfo> processRecord(StringRef recordFile);
+};
+
+} // anonymous namespace
+
+bool Aggregator::process() {
+  bool succ = Store.foreachUnit(/*sorted=*/true, [&](StringRef unitName) -> bool {
+    std::string error;
+    auto unitReader = IndexUnitReader(Store, unitName, error);
+    if (!unitReader) {
+      errs() << "error opening unit file '" << unitName << "': " << error << '\n';
+      return false;
+    }
+
+    processUnit(unitName, unitReader);
+    return true;
+  });
+
+  return !succ;
+}
+
+void Aggregator::processUnit(StringRef name, IndexUnitReader &UnitReader) {
+  auto workDir = UnitReader.getWorkingDirectory();
+  auto unit = llvm::make_unique<UnitInfo>();
+  unit->Name = name;
+  unit->Triple = getTripleString(UnitReader.getTarget());
+  unit->OutFile = getFilePathIndex(UnitReader.getOutputFile(), workDir);
+
+  struct DepInfo {
+    UnitSourceInfo source;
+    std::string unitName;
+  };
+  SmallVector<DepInfo, 32> Deps;
+  UnitReader.foreachDependency([&](IndexUnitDependency dep) -> bool {
+    Deps.resize(Deps.size()+1);
+    auto &depInfo = Deps.back();
+    switch (dep.getKind()) {
+      case IndexUnitDependency::DependencyKind::Unit: {
+        depInfo.unitName = dep.getName();
+        StringRef filePath = dep.getFilePath();
+        if (!filePath.empty())
+          depInfo.source.FilePath = getFilePathIndex(filePath, workDir);
+        break;
+      }
+      case IndexUnitDependency::DependencyKind::Record: {
+        depInfo.source.FilePath = getFilePathIndex(dep.getFilePath(), workDir);
+        RecordIndex recIndex = getRecordIndex(dep.getName());
+        depInfo.source.AssociatedRecords.push_back(recIndex);
+        break;
+      }
+      case IndexUnitDependency::DependencyKind::File:
+        depInfo.source.FilePath = getFilePathIndex(dep.getFilePath(), workDir);
+    }
+    return true;
+  });
+
+  unit->Sources.reserve(Deps.size());
+  for (auto &dep : Deps) {
+    if (!dep.unitName.empty()) {
+      unit->UnitDepends.emplace_back(std::move(dep.unitName));
+    } else {
+      unit->Sources.push_back(std::move(dep.source));
+    }
+  }
+
+  Units.push_back(std::move(unit));
+}
+
+FilePathIndex Aggregator::getFilePathIndex(StringRef path, StringRef workingDir) {
+  StringRef absPath;
+  SmallString<128> absPathBuf;
+  if (sys::path::is_absolute(path) || workingDir.empty()) {
+    absPath = path;
+  } else {
+    absPathBuf = workingDir;
+    sys::path::append(absPathBuf, path);
+    absPath = absPathBuf.str();
+  }
+
+  auto pair = FilePathIndices.insert(std::make_pair(absPath, FilePaths.size()));
+  bool wasInserted = pair.second;
+  if (wasInserted) {
+    FilePaths.push_back(pair.first->first());
+  }
+  return pair.first->second;
+}
+
+RecordIndex Aggregator::getRecordIndex(StringRef recordFile) {
+  auto pair = RecordIndices.insert(std::make_pair(recordFile, Records.size()));
+  bool wasInserted = pair.second;
+  if (wasInserted) {
+    Records.push_back(processRecord(recordFile));
+  }
+  return pair.first->second;
+}
+
+std::unique_ptr<RecordInfo> Aggregator::processRecord(StringRef recordFile) {
+  std::string error;
+  auto recordReader = IndexRecordReader(Store, recordFile, error);
+  if (!recordReader) {
+    errs() << "failed reading record file: " << recordFile << '\n';
+    ::exit(1);
+  }
+  auto record = llvm::make_unique<RecordInfo>();
+  recordReader.foreachOccurrence([&](IndexRecordOccurrence idxOccur) -> bool {
+    SymbolIndex symIdx = getSymbolIndex(idxOccur.getSymbol());
+    SymbolInfo &symInfo = Symbols[symIdx];
+    symInfo.Roles |= idxOccur.getRoles();
+    SymbolOccurrenceInfo occurInfo;
+    occurInfo.Symbol = symIdx;
+    idxOccur.foreachRelation([&](IndexSymbolRelation rel) -> bool {
+      SymbolIndex relsymIdx = getSymbolIndex(rel.getSymbol());
+      SymbolInfo &relsymInfo = Symbols[relsymIdx];
+      relsymInfo.RelatedRoles |= rel.getRoles();
+      occurInfo.Relations.emplace_back(relsymIdx, rel.getRoles());
+      return true;
+    });
+    occurInfo.Roles = idxOccur.getRoles();
+    std::tie(occurInfo.Line, occurInfo.Column) = idxOccur.getLineCol();
+    record->Occurrences.push_back(std::move(occurInfo));
+    return true;
+  });
+  return record;
+}
+
+SymbolIndex Aggregator::getSymbolIndex(IndexRecordSymbol sym) {
+  auto pair = SymbolIndices.insert(std::make_pair(sym.getUSR(), Symbols.size()));
+  bool wasInserted = pair.second;
+  if (wasInserted) {
+    SymbolInfo symInfo;
+    symInfo.Kind = getSymbolKind(sym.getKind());
+    symInfo.Lang = getSymbolLanguage(sym.getLanguage());
+    symInfo.USR = pair.first->first();
+    symInfo.Name = copyStr(sym.getName());
+    symInfo.CodegenName = copyStr(sym.getCodegenName());
+    Symbols.push_back(std::move(symInfo));
+  }
+  return pair.first->second;
+}
+
+
+void Aggregator::dumpJSON(raw_ostream &OS) {
+  OS << "{\n";
+  OS.indent(2) << "\"files\": [\n";
+  for (unsigned i = 0, e = FilePaths.size(); i != e; ++i) {
+    OS.indent(4) << '\"' << FilePaths[i] << '\"';
+    if (i < e-1) OS << ',';
+    OS << '\n';
+  }
+  OS.indent(2) << "],\n";
+
+  OS.indent(2) << "\"symbols\": [\n";
+  for (unsigned i = 0, e = Symbols.size(); i != e; ++i) {
+    OS.indent(4) << "{\n";
+    SymbolInfo &symInfo = Symbols[i];
+    OS.indent(6) << "\"kind\": \"" << getSymbolKindString(symInfo.Kind) << "\",\n";
+    OS.indent(6) << "\"lang\": \"" << getSymbolLanguageString(symInfo.Lang) << "\",\n";
+    OS.indent(6) << "\"usr\": \"" << symInfo.USR << "\",\n";
+    OS.indent(6) << "\"name\": \"" << symInfo.Name << "\",\n";
+    if (!symInfo.CodegenName.empty())
+      OS.indent(6) << "\"codegen\": \"" << symInfo.CodegenName << "\",\n";
+    OS.indent(6) << "\"roles\": \"";
+    printSymbolRoles(symInfo.Roles, OS);
+    OS << '\"';
+    if (symInfo.RelatedRoles != 0) {
+      OS << ",\n";
+      OS.indent(6) << "\"rel-roles\": \"";
+      printSymbolRoles(symInfo.RelatedRoles, OS);
+      OS << '\"';
+    }
+    OS << '\n';
+    OS.indent(4) << "}";
+    if (i < e-1) OS << ',';
+    OS << '\n';
+  }
+  OS.indent(2) << "],\n";
+
+  OS.indent(2) << "\"records\": [\n";
+  for (unsigned i = 0, e = Records.size(); i != e; ++i) {
+    OS.indent(4) << "{\n";
+    RecordInfo &recInfo = *Records[i];
+    OS.indent(6) << "\"occurrences\": [\n";
+    for (unsigned oi = 0, oe = recInfo.Occurrences.size(); oi != oe; ++oi) {
+      OS.indent(8) << "{\n";
+      SymbolOccurrenceInfo &occurInfo = recInfo.Occurrences[oi];
+      OS.indent(10) << "\"symbol\": " << occurInfo.Symbol << ",\n";
+      OS.indent(10) << "\"line\": " << occurInfo.Line << ",\n";
+      OS.indent(10) << "\"col\": " << occurInfo.Column << ",\n";
+      OS.indent(10) << "\"roles\": \"";
+      printSymbolRoles(occurInfo.Roles, OS);
+      OS << '\"';
+      if (!occurInfo.Relations.empty()) {
+        OS << ",\n";
+        OS.indent(10) << "\"relations\": [\n";
+        for (unsigned ri = 0, re = occurInfo.Relations.size(); ri != re; ++ri) {
+          OS.indent(12) << "{\n";
+          SymbolRelationInfo &relInfo = occurInfo.Relations[ri];
+          OS.indent(14) << "\"symbol\": " << relInfo.RelatedSymbol << ",\n";
+          OS.indent(14) << "\"rel-roles\": \"";
+          printSymbolRoles(relInfo.Roles, OS);
+          OS << "\"\n";
+          OS.indent(12) << "}";
+          if (ri < re-1) OS << ',';
+          OS << '\n';
+        }
+        OS.indent(10) << "]\n";
+      }
+      OS << '\n';
+      OS.indent(8) << "}";
+      if (oi < oe-1) OS << ',';
+      OS << '\n';
+    }
+    OS.indent(6) << "]\n";
+    OS.indent(4) << "}";
+    if (i < e-1) OS << ',';
+    OS << '\n';
+  }
+  OS.indent(2) << "],\n";
+
+  StringMap<size_t> UnitIndicesByName;
+  for (unsigned i = 0, e = Units.size(); i != e; ++i) {
+    UnitInfo &unit = *Units[i];
+    UnitIndicesByName[unit.Name] = i;
+  }
+
+  OS.indent(2) << "\"units\": [\n";
+  for (unsigned i = 0, e = Units.size(); i != e; ++i) {
+    OS.indent(4) << "{\n";
+    UnitInfo &unit = *Units[i];
+    OS.indent(6) << "\"triple\": \"" << unit.Triple << "\",\n";
+    OS.indent(6) << "\"out-file\": " << unit.OutFile << ",\n";
+    if (!unit.UnitDepends.empty()) {
+      OS.indent(6) << "\"unit-dependencies\": [";
+      for (unsigned ui = 0, ue = unit.UnitDepends.size(); ui != ue; ++ui) {
+        OS << UnitIndicesByName[unit.UnitDepends[ui]];
+        if (ui < ue-1) OS << ", ";
+      }
+      OS << "],\n";
+    }
+    OS.indent(6) << "\"sources\": [\n";
+    for (unsigned si = 0, se = unit.Sources.size(); si != se; ++si) {
+      OS.indent(8) << "{\n";
+      UnitSourceInfo &source = unit.Sources[si];
+      OS.indent(10) << "\"file\": " << source.FilePath;
+      if (!source.AssociatedRecords.empty()) {
+        OS << ",\n";
+        OS.indent(10) << "\"records\": [";
+        for (unsigned ri = 0, re = source.AssociatedRecords.size(); ri != re; ++ri) {
+          OS << source.AssociatedRecords[ri];
+          if (ri < re-1) OS << ", ";
+        }
+        OS << ']';
+      }
+      OS << '\n';
+      OS.indent(8) << "}";
+      if (si < se-1) OS << ',';
+      OS << '\n';
+    }
+    OS.indent(6) << "]\n";
+    OS.indent(4) << "}";
+    if (i < e-1) OS << ',';
+    OS << '\n';
+  }
+  OS.indent(2) << "]\n";
+  OS << "}\n";
+}
+
+
+bool index::aggregateDataAsJSON(StringRef StorePath, raw_ostream &OS) {
+  std::string error;
+  auto dataStore = IndexStore(StorePath, error);
+  if (!dataStore) {
+    errs() << "error opening store path '" << StorePath << "': " << error << '\n';
+    return true;
+  }
+
+  // Explicitely avoid doing any memory cleanup for aggregator since the process
+  // is going to exit when we are done.
+  Aggregator *aggregator = new Aggregator(std::move(dataStore));
+  bool err = aggregator->process();
+  if (err)
+    return true;
+  aggregator->dumpJSON(OS);
+  return false;
+}
+
+#else
+
+bool index::aggregateDataAsJSON(StringRef StorePath, raw_ostream &OS) {
+  return true;
+}
+#endif
diff --git a/tools/c-index-test/JSONAggregation.h b/tools/c-index-test/JSONAggregation.h
new file mode 100644
index 0000000..5224ce8
--- /dev/null
+++ b/tools/c-index-test/JSONAggregation.h
@@ -0,0 +1,24 @@
+//===--- JSONAggregation.h - Index data aggregation in JSON format --------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_CINDEXTEST_JSONAGGREGATION_H
+#define LLVM_CLANG_TOOLS_CINDEXTEST_JSONAGGREGATION_H
+
+#include "clang/Basic/LLVM.h"
+
+namespace clang {
+namespace index {
+
+/// Returns true if an error occurred, false otherwise.
+bool aggregateDataAsJSON(StringRef StorePath, raw_ostream &OS);
+
+} // end namespace index
+} // end namespace clang
+
+#endif
diff --git a/tools/c-index-test/core_main.cpp b/tools/c-index-test/core_main.cpp
index 4f2c3cb..0bafcda 100644
--- a/tools/c-index-test/core_main.cpp
+++ b/tools/c-index-test/core_main.cpp
@@ -7,6 +7,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "JSONAggregation.h"
+#include "indexstore/IndexStoreCXX.h"
+#include "clang/DirectoryWatcher/DirectoryWatcher.h"
 #include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
 #include "clang/Frontend/ASTUnit.h"
 #include "clang/Frontend/CompilerInstance.h"
@@ -14,14 +17,31 @@
 #include "clang/Frontend/FrontendAction.h"
 #include "clang/Index/IndexingAction.h"
 #include "clang/Index/IndexDataConsumer.h"
+#include "clang/Index/IndexDataStoreSymbolUtils.h"
+#include "clang/Index/IndexRecordReader.h"
+#include "clang/Index/IndexUnitReader.h"
 #include "clang/Index/USRGeneration.h"
 #include "clang/Index/CodegenNameGenerator.h"
 #include "clang/Serialization/ASTReader.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/raw_ostream.h"
 #include "llvm/Support/PrettyStackTrace.h"
 
+#define HAVE_CORESERVICES 0
+
+#if defined(__has_include)
+#if __has_include(<CoreServices/CoreServices.h>)
+
+#include <CoreServices/CoreServices.h>
+#undef HAVE_CORESERVICES
+#define HAVE_CORESERVICES 1
+
+#endif
+#endif
+
 using namespace clang;
 using namespace clang::index;
 using namespace llvm;
@@ -33,6 +53,11 @@
 enum class ActionType {
   None,
   PrintSourceSymbols,
+  PrintRecord,
+  PrintUnit,
+  PrintStoreFormatVersion,
+  AggregateAsJSON,
+  WatchDir,
 };
 
 namespace options {
@@ -43,9 +68,26 @@
 Action(cl::desc("Action:"), cl::init(ActionType::None),
        cl::values(
           clEnumValN(ActionType::PrintSourceSymbols,
-                     "print-source-symbols", "Print symbols from source")),
+                     "print-source-symbols", "Print symbols from source"),
+          clEnumValN(ActionType::PrintRecord,
+                     "print-record", "Print record info"),
+          clEnumValN(ActionType::PrintUnit,
+                     "print-unit", "Print unit info"),
+          clEnumValN(ActionType::PrintStoreFormatVersion,
+                     "print-store-format-version", "Print store format version"),
+          clEnumValN(ActionType::AggregateAsJSON,
+                     "aggregate-json", "Aggregate index data in JSON format"),
+          clEnumValN(ActionType::WatchDir,
+                     "watch-dir", "Watch directory for file events")),
        cl::cat(IndexTestCoreCategory));
 
+static cl::opt<std::string>
+OutputFile("o", cl::desc("output file"),
+           cl::cat(IndexTestCoreCategory));
+
+static cl::list<std::string>
+InputFiles(cl::Positional, cl::desc("<filename>..."));
+
 static cl::extrahelp MoreHelp(
   "\nAdd \"-- <compiler arguments>\" at the end to setup the compiler "
   "invocation\n"
@@ -65,6 +107,10 @@
   ModuleFormat("fmodule-format", cl::init("raw"),
         cl::desc("Container format for clang modules and PCH, 'raw' or 'obj'"));
 
+static cl::opt<std::string>
+FilePathAndRange("filepath",
+               cl::desc("File path that can optionally include a line range"));
+
 }
 } // anonymous namespace
 
@@ -235,6 +281,305 @@
   return false;
 }
 
+#if INDEXSTORE_HAS_BLOCKS
+
+//===----------------------------------------------------------------------===//
+// Print Record
+//===----------------------------------------------------------------------===//
+
+static void printSymbol(const IndexRecordDecl &Rec, raw_ostream &OS);
+static void printSymbol(const IndexRecordOccurrence &Rec, raw_ostream &OS);
+
+static int printRecord(StringRef Filename, raw_ostream &OS) {
+  std::string Error;
+  auto Reader = IndexRecordReader::createWithFilePath(Filename, Error);
+  if (!Reader) {
+    errs() << Error << '\n';
+    return true;
+  }
+
+  Reader->foreachDecl(/*noCache=*/true, [&](const IndexRecordDecl *Rec)->bool {
+    printSymbol(*Rec, OS);
+    return true;
+  });
+  OS << "------------\n";
+  Reader->foreachOccurrence([&](const IndexRecordOccurrence &Rec)->bool {
+    printSymbol(Rec, OS);
+    return true;
+  });
+
+  return false;
+};
+
+//===----------------------------------------------------------------------===//
+// Print Store Records
+//===----------------------------------------------------------------------===//
+
+static void printSymbol(indexstore::IndexRecordSymbol Sym, raw_ostream &OS);
+static void printSymbol(indexstore::IndexRecordOccurrence Occur, raw_ostream &OS);
+
+static bool printStoreRecord(indexstore::IndexStore &Store, StringRef RecName,
+                             StringRef FilePath, raw_ostream &OS) {
+  std::string Error;
+  indexstore::IndexRecordReader Reader(Store, RecName, Error);
+  if (!Reader) {
+    errs() << "error loading record: " << Error << "\n";
+    return true;
+  }
+
+  StringRef Filename = sys::path::filename(FilePath);
+  OS << Filename << '\n';
+  OS << "------------\n";
+  Reader.foreachSymbol(/*noCache=*/true, [&](indexstore::IndexRecordSymbol Sym) -> bool {
+    printSymbol(Sym, OS);
+    return true;
+  });
+  OS << "------------\n";
+  Reader.foreachOccurrence([&](indexstore::IndexRecordOccurrence Occur)->bool {
+    printSymbol(Occur, OS);
+    return true;
+  });
+
+  return false;
+}
+
+static int printStoreRecords(StringRef StorePath, raw_ostream &OS) {
+  std::string Error;
+  indexstore::IndexStore Store(StorePath, Error);
+  if (!Store) {
+    errs() << "error loading store: " << Error << "\n";
+    return 1;
+  }
+
+  bool Success = Store.foreachUnit(/*sorted=*/true, [&](StringRef UnitName) -> bool {
+    indexstore::IndexUnitReader Reader(Store, UnitName, Error);
+    if (!Reader) {
+      errs() << "error loading unit: " << Error << "\n";
+      return false;
+    }
+    return Reader.foreachDependency([&](indexstore::IndexUnitDependency Dep) -> bool {
+      if (Dep.getKind() == indexstore::IndexUnitDependency::DependencyKind::Record) {
+        bool Err = printStoreRecord(Store, Dep.getName(), Dep.getFilePath(), OS);
+        OS << '\n';
+        return !Err;
+      }
+      return true;
+    });
+  });
+
+  return !Success;
+}
+
+static std::string findRecordNameForFile(indexstore::IndexStore &store,
+                                         StringRef filePath) {
+  std::string recName;
+  store.foreachUnit(/*sorted=*/false, [&](StringRef unitName) -> bool {
+    std::string error;
+    indexstore::IndexUnitReader Reader(store, unitName, error);
+    if (!Reader) {
+      errs() << "error loading unit: " << error << "\n";
+      return false;
+    }
+    Reader.foreachDependency([&](indexstore::IndexUnitDependency Dep) -> bool {
+      if (Dep.getKind() == indexstore::IndexUnitDependency::DependencyKind::Record) {
+        if (Dep.getFilePath() == filePath) {
+          recName = Dep.getName();
+          return false;
+        }
+        return true;
+      }
+      return true;
+    });
+    return true;
+  });
+  return recName;
+}
+
+static int printStoreFileRecord(StringRef storePath, StringRef filePath,
+                                Optional<unsigned> lineStart, unsigned lineCount,
+                                raw_ostream &OS) {
+  std::string error;
+  indexstore::IndexStore store(storePath, error);
+  if (!store) {
+    errs() << "error loading store: " << error << "\n";
+    return 1;
+  }
+
+  std::string recName = findRecordNameForFile(store, filePath);
+  if (recName.empty()) {
+    errs() << "could not find record for '" << filePath << "'\n";
+    return 1;
+  }
+
+  if (!lineStart.hasValue())
+    return printStoreRecord(store, recName, filePath, OS);
+
+  indexstore::IndexRecordReader Reader(store, recName, error);
+  if (!Reader) {
+    errs() << "error loading record: " << error << "\n";
+    return 1;
+  }
+
+  Reader.foreachOccurrenceInLineRange(*lineStart, lineCount, [&](indexstore::IndexRecordOccurrence Occur)->bool {
+    printSymbol(Occur, OS);
+    return true;
+  });
+
+  return 0;
+}
+
+
+//===----------------------------------------------------------------------===//
+// Print Unit
+//===----------------------------------------------------------------------===//
+
+static int printUnit(StringRef Filename, raw_ostream &OS) {
+  std::string Error;
+  auto Reader = IndexUnitReader::createWithFilePath(Filename, Error);
+  if (!Reader) {
+    errs() << Error << '\n';
+    return true;
+  }
+
+  OS << "provider: " << Reader->getProviderIdentifier() << '-' << Reader->getProviderVersion() << '\n';
+  OS << "is-system: " << Reader->isSystemUnit() << '\n';
+  OS << "is-module: " << Reader->isModuleUnit() << '\n';
+  OS << "module-name: " << (Reader->getModuleName().empty() ? "<none>" : Reader->getModuleName()) << '\n';
+  OS << "has-main: " << Reader->hasMainFile() << '\n';
+  OS << "main-path: " << Reader->getMainFilePath() << '\n';
+  OS << "work-dir: " << Reader->getWorkingDirectory() << '\n';
+  OS << "out-file: " << Reader->getOutputFile() << '\n';
+  OS << "target: " << Reader->getTarget() << '\n';
+  OS << "is-debug: " << Reader->isDebugCompilation() << '\n';
+  OS << "DEPEND START\n";
+  unsigned NumDepends = 0;
+  Reader->foreachDependency([&](const IndexUnitReader::DependencyInfo &Dep) -> bool {
+    switch (Dep.Kind) {
+    case IndexUnitReader::DependencyKind::Unit:
+      OS << "Unit | "; break;
+    case IndexUnitReader::DependencyKind::Record:
+      OS << "Record | "; break;
+    case IndexUnitReader::DependencyKind::File:
+      OS << "File | "; break;
+    }
+    OS << (Dep.IsSystem ? "system" : "user");
+    OS << " | ";
+    if (!Dep.ModuleName.empty())
+      OS << Dep.ModuleName << " | ";
+    OS << Dep.FilePath << " | " << Dep.UnitOrRecordName << " | ";
+    OS << Dep.ModTime << " | " << Dep.FileSize << '\n';
+    ++NumDepends;
+    return true;
+  });
+  OS << "DEPEND END (" << NumDepends << ")\n";
+  OS << "INCLUDE START\n";
+  unsigned NumIncludes = 0;
+  Reader->foreachInclude([&](const IndexUnitReader::IncludeInfo &Inc) -> bool {
+    OS << Inc.SourcePath << ":" << Inc.SourceLine << " | ";
+    OS << Inc.TargetPath << '\n';
+    ++NumIncludes;
+    return true;
+  });
+  OS << "INCLUDE END (" << NumIncludes << ")\n";
+
+  return false;
+};
+
+//===----------------------------------------------------------------------===//
+// Print Store Units
+//===----------------------------------------------------------------------===//
+
+static bool printStoreUnit(indexstore::IndexStore &Store, StringRef UnitName,
+                           raw_ostream &OS) {
+  std::string Error;
+  indexstore::IndexUnitReader Reader(Store, UnitName, Error);
+  if (!Reader) {
+    errs() << "error loading unit: " << Error << "\n";
+    return true;
+  }
+
+  OS << "provider: " << Reader.getProviderIdentifier() << '-' << Reader.getProviderVersion() << '\n';
+  OS << "is-system: " << Reader.isSystemUnit() << '\n';
+  OS << "is-module: " << Reader.isModuleUnit() << '\n';
+  OS << "module-name: " << (Reader.getModuleName().empty() ? "<none>" : Reader.getModuleName()) << '\n';
+  OS << "has-main: " << Reader.hasMainFile() << '\n';
+  OS << "main-path: " << Reader.getMainFilePath() << '\n';
+  OS << "work-dir: " << Reader.getWorkingDirectory() << '\n';
+  OS << "out-file: " << Reader.getOutputFile() << '\n';
+  OS << "target: " << Reader.getTarget() << '\n';
+  OS << "is-debug: " << Reader.isDebugCompilation() << '\n';
+  OS << "DEPEND START\n";
+  unsigned NumDepends = 0;
+  Reader.foreachDependency([&](indexstore::IndexUnitDependency Dep) -> bool {
+    switch (Dep.getKind()) {
+    case indexstore::IndexUnitDependency::DependencyKind::Unit:
+      OS << "Unit | "; break;
+    case indexstore::IndexUnitDependency::DependencyKind::Record:
+      OS << "Record | "; break;
+    case indexstore::IndexUnitDependency::DependencyKind::File:
+      OS << "File | "; break;
+    }
+    OS << (Dep.isSystem() ? "system" : "user");
+    OS << " | ";
+    if (!Dep.getModuleName().empty())
+      OS << Dep.getModuleName() << " | ";
+    OS << Dep.getFilePath() << " | " << Dep.getName() << " | ";
+    OS << Dep.getModificationTime() << '\n';
+    ++NumDepends;
+    return true;
+  });
+  OS << "DEPEND END (" << NumDepends << ")\n";
+  OS << "INCLUDE START\n";
+  unsigned NumIncludes = 0;
+  Reader.foreachInclude([&](indexstore::IndexUnitInclude Inc) -> bool {
+    OS << Inc.getSourcePath() << ":" << Inc.getSourceLine() << " | ";
+    OS << Inc.getTargetPath() << '\n';
+    ++NumIncludes;
+    return true;
+  });
+  OS << "INCLUDE END (" << NumIncludes << ")\n";
+
+  return false;
+}
+
+static int printStoreUnits(StringRef StorePath, raw_ostream &OS) {
+  std::string Error;
+  indexstore::IndexStore Store(StorePath, Error);
+  if (!Store) {
+    errs() << "error loading store: " << Error << "\n";
+    return 1;
+  }
+
+  bool Success = Store.foreachUnit(/*sorted=*/true, [&](StringRef UnitName) -> bool {
+    OS << UnitName << '\n';
+    OS << "--------\n";
+    bool err = printStoreUnit(Store, UnitName, OS);
+    OS << '\n';
+    return !err;
+  });
+
+  return !Success;
+}
+
+
+#else
+
+static int printUnit(StringRef Filename, raw_ostream &OS) {
+  return 1;
+}
+
+static int printStoreUnits(StringRef StorePath, raw_ostream &OS) {
+  return 1;
+}
+
+static int printStoreFileRecord(StringRef storePath, StringRef filePath,
+                                Optional<unsigned> lineStart, unsigned lineCount,
+                                raw_ostream &OS) {
+  return 1;
+}
+
+#endif
+
 //===----------------------------------------------------------------------===//
 // Helper Utils
 //===----------------------------------------------------------------------===//
@@ -266,10 +611,210 @@
   }
 }
 
+#if INDEXSTORE_HAS_BLOCKS
+
+static void printSymbol(const IndexRecordDecl &Rec, raw_ostream &OS) {
+  printSymbolInfo(Rec.SymInfo, OS);
+  OS << " | ";
+
+  if (Rec.Name.empty())
+    OS << "<no-name>";
+  else
+    OS << Rec.Name;
+  OS << " | ";
+
+  if (Rec.USR.empty())
+    OS << "<no-usr>";
+  else
+    OS << Rec.USR;
+  OS << " | ";
+
+  if (Rec.CodeGenName.empty())
+    OS << "<no-cgname>";
+  else
+    OS << Rec.CodeGenName;
+  OS << " | ";
+
+  printSymbolRoles(Rec.Roles, OS);
+  OS << " - ";
+  printSymbolRoles(Rec.RelatedRoles, OS);
+  OS << '\n';
+}
+
+static void printSymbol(const IndexRecordOccurrence &Rec, raw_ostream &OS) {
+  OS << Rec.Line << ':' << Rec.Column << " | ";
+  printSymbolInfo(Rec.Dcl->SymInfo, OS);
+  OS << " | ";
+
+  if (Rec.Dcl->USR.empty())
+    OS << "<no-usr>";
+  else
+    OS << Rec.Dcl->USR;
+  OS << " | ";
+
+  printSymbolRoles(Rec.Roles, OS);
+  OS << " | ";
+  OS << "rel: " << Rec.Relations.size() << '\n';
+  for (auto &Rel : Rec.Relations) {
+    OS << '\t';
+    printSymbolRoles(Rel.Roles, OS);
+    OS << " | ";
+    if (Rel.Dcl->USR.empty())
+      OS << "<no-usr>";
+    else
+      OS << Rel.Dcl->USR;
+    OS << '\n';
+  }
+}
+
+static void printSymbol(indexstore::IndexRecordSymbol Sym, raw_ostream &OS) {
+  SymbolInfo SymInfo{getSymbolKind(Sym.getKind()),
+                     getSymbolSubKind(Sym.getSubKind()),
+                     SymbolPropertySet(Sym.getProperties()),
+                     getSymbolLanguage(Sym.getLanguage())};
+
+  printSymbolInfo(SymInfo, OS);
+  OS << " | ";
+
+  if (Sym.getName().empty())
+    OS << "<no-name>";
+  else
+    OS << Sym.getName();
+  OS << " | ";
+
+  if (Sym.getUSR().empty())
+    OS << "<no-usr>";
+  else
+    OS << Sym.getUSR();
+  OS << " | ";
+
+  if (Sym.getCodegenName().empty())
+    OS << "<no-cgname>";
+  else
+    OS << Sym.getCodegenName();
+  OS << " | ";
+
+  printSymbolRoles(Sym.getRoles(), OS);
+  OS << " - ";
+  printSymbolRoles(Sym.getRelatedRoles(), OS);
+  OS << '\n';
+}
+
+static void printSymbol(indexstore::IndexRecordOccurrence Occur, raw_ostream &OS) {
+  OS << Occur.getLineCol().first << ':' << Occur.getLineCol().second << " | ";
+  auto Sym = Occur.getSymbol();
+  SymbolInfo SymInfo{getSymbolKind(Sym.getKind()),
+                     getSymbolSubKind(Sym.getSubKind()),
+                     SymbolPropertySet(Sym.getProperties()),
+                     getSymbolLanguage(Sym.getLanguage())};
+
+  printSymbolInfo(SymInfo, OS);
+  OS << " | ";
+
+  if (Sym.getUSR().empty())
+    OS << "<no-usr>";
+  else
+    OS << Sym.getUSR();
+  OS << " | ";
+
+  unsigned NumRelations = 0;
+  Occur.foreachRelation([&](indexstore::IndexSymbolRelation) {
+    ++NumRelations;
+    return true;
+  });
+
+  printSymbolRoles(Occur.getRoles(), OS);
+  OS << " | ";
+  OS << "rel: " << NumRelations << '\n';
+  Occur.foreachRelation([&](indexstore::IndexSymbolRelation Rel) {
+    OS << '\t';
+    printSymbolRoles(Rel.getRoles(), OS);
+    OS << " | ";
+    auto Sym = Rel.getSymbol();
+    if (Sym.getUSR().empty())
+      OS << "<no-usr>";
+    else
+      OS << Sym.getUSR();
+    OS << '\n';
+    return true;
+  });
+}
+
+#else
+
+static int printRecord(StringRef Filename, raw_ostream &OS) {
+  return 1;
+}
+static int printStoreRecords(StringRef StorePath, raw_ostream &OS) {
+  return 1;
+}
+
+#endif
+
+static int watchDirectory(StringRef dirPath) {
+  raw_ostream &OS = outs();
+  auto receiver = [&](ArrayRef<DirectoryWatcher::Event> Events, bool isInitial) {
+    for (auto evt : Events) {
+      switch (evt.Kind) {
+        case DirectoryWatcher::EventKind::Added:
+          OS << "added: "; break;
+        case DirectoryWatcher::EventKind::Modified:
+          OS << "modified: "; break;
+        case DirectoryWatcher::EventKind::Removed:
+          OS << "removed: "; break;
+        case DirectoryWatcher::EventKind::DirectoryDeleted:
+          OS << "dir deleted: "; break;
+
+      }
+      OS << evt.Filename << '\n';
+    }
+  };
+  std::string Error;
+  auto watcher = DirectoryWatcher::create(dirPath, receiver,
+                                          /*waitInitialSync=*/true, Error);
+  if (!watcher) {
+    errs() << "failed creating directory watcher: " << Error << '\n';
+    return 1;
+  }
+#if HAVE_CORESERVICES
+  dispatch_main();
+#else
+  return 1;
+#endif
+}
+
 //===----------------------------------------------------------------------===//
 // Command line processing.
 //===----------------------------------------------------------------------===//
 
+bool deconstructPathAndRange(StringRef input,
+                             std::string &filepath,
+                             Optional<unsigned> &lineStart,
+                             unsigned &lineCount) {
+  StringRef path, range;
+  std::tie(path, range) = input.split(':');
+  StringRef start, end;
+  std::tie(start, end) = range.split(':');
+  filepath = path;
+  lineCount = 0;
+  if (start.empty())
+    return false;
+  unsigned num;
+  if (start.getAsInteger(10, num)) {
+    errs() << "couldn't convert to integer: " << start << '\n';
+    return true;
+  }
+  lineStart = num;
+  if (end.empty())
+    return false;
+  if (end.getAsInteger(10, num)) {
+    errs() << "couldn't convert to integer: " << end << '\n';
+    return true;
+  }
+  lineCount = num-lineStart.getValue();
+  return false;
+}
+
 int indextest_core_main(int argc, const char **argv) {
   sys::PrintStackTraceOnErrorSignal(argv[0]);
   PrettyStackTraceProgram X(argc, argv);
@@ -305,5 +850,75 @@
     return printSourceSymbols(CompArgs, options::DumpModuleImports, options::IncludeLocals);
   }
 
+  if (options::Action == ActionType::PrintRecord) {
+    if (!options::FilePathAndRange.empty()) {
+      std::string filepath;
+      Optional<unsigned> lineStart;
+      unsigned lineCount;
+      if (deconstructPathAndRange(options::FilePathAndRange,
+                                  filepath, lineStart, lineCount))
+        return 1;
+
+      if (options::InputFiles.empty()) {
+        errs() << "error: missing index store path\n";
+        return 1;
+      }
+      return printStoreFileRecord(options::InputFiles[0], filepath, lineStart, lineCount, outs());
+    }
+
+    if (options::InputFiles.empty()) {
+      errs() << "error: missing input file or directory\n";
+      return 1;
+    }
+
+    if (sys::fs::is_directory(options::InputFiles[0]))
+      return printStoreRecords(options::InputFiles[0], outs());
+    else
+      return printRecord(options::InputFiles[0], outs());
+  }
+
+  if (options::Action == ActionType::PrintUnit) {
+    if (options::InputFiles.empty()) {
+      errs() << "error: missing input file or directory\n";
+      return 1;
+    }
+
+    if (sys::fs::is_directory(options::InputFiles[0]))
+      return printStoreUnits(options::InputFiles[0], outs());
+    else
+      return printUnit(options::InputFiles[0], outs());
+  }
+
+#if INDEXSTORE_HAS_BLOCKS
+  if (options::Action == ActionType::PrintStoreFormatVersion) {
+    outs() << indexstore::IndexStore::formatVersion() << '\n';
+  }
+#endif
+
+  if (options::Action == ActionType::AggregateAsJSON) {
+    if (options::InputFiles.empty()) {
+      errs() << "error: missing input data store directory\n";
+      return 1;
+    }
+    StringRef storePath = options::InputFiles[0];
+    if (options::OutputFile.empty())
+      return aggregateDataAsJSON(storePath, outs());
+    std::error_code EC;
+    raw_fd_ostream OS(options::OutputFile, EC, llvm::sys::fs::F_None);
+    if (EC) {
+      errs() << "failed to open output file: " << EC.message() << '\n';
+      return 1;
+    }
+    return aggregateDataAsJSON(storePath, OS);
+  }
+
+  if (options::Action == ActionType::WatchDir) {
+    if (options::InputFiles.empty()) {
+      errs() << "error: missing directory path\n";
+      return 1;
+    }
+    return watchDirectory(options::InputFiles[0]);
+  }
+
   return 0;
 }