Merge commit 96f2a40217bb

* upstream svn@328819

Test: git diff 96f2a40217bb == git diff f8988e8e88b8 5383c119dd1
Change-Id: I4c9a3b9d0814fd2d7c7797e50bf211c61738b6f7
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 760340a..c434682 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,6 +7,7 @@
 endif()
 
 add_subdirectory(change-namespace)
+add_subdirectory(clang-doc)
 add_subdirectory(clang-query)
 add_subdirectory(clang-move)
 add_subdirectory(clangd)
diff --git a/change-namespace/ChangeNamespace.cpp b/change-namespace/ChangeNamespace.cpp
index 68adada..35c321a 100644
--- a/change-namespace/ChangeNamespace.cpp
+++ b/change-namespace/ChangeNamespace.cpp
@@ -478,13 +478,13 @@
                                 hasAncestor(namespaceDecl(isAnonymous())),
                                 hasAncestor(cxxRecordDecl()))),
                    hasParent(namespaceDecl()));
-  Finder->addMatcher(decl(forEachDescendant(expr(anyOf(
-                              callExpr(callee(FuncMatcher)).bind("call"),
-                              declRefExpr(to(FuncMatcher.bind("func_decl")))
-                                  .bind("func_ref")))),
-                          IsInMovedNs, unless(isImplicit()))
-                         .bind("dc"),
-                     this);
+  Finder->addMatcher(
+      expr(allOf(hasAncestor(decl().bind("dc")), IsInMovedNs,
+                 unless(hasAncestor(isImplicit())),
+                 anyOf(callExpr(callee(FuncMatcher)).bind("call"),
+                       declRefExpr(to(FuncMatcher.bind("func_decl")))
+                           .bind("func_ref")))),
+      this);
 
   auto GlobalVarMatcher = varDecl(
       hasGlobalStorage(), hasParent(namespaceDecl()),
diff --git a/clang-doc/BitcodeWriter.cpp b/clang-doc/BitcodeWriter.cpp
new file mode 100644
index 0000000..a6c9a41
--- /dev/null
+++ b/clang-doc/BitcodeWriter.cpp
@@ -0,0 +1,510 @@
+//===--  BitcodeWriter.cpp - ClangDoc Bitcode Writer ------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "BitcodeWriter.h"
+#include "llvm/ADT/IndexedMap.h"
+#include <initializer_list>
+
+namespace clang {
+namespace doc {
+
+// Since id enums are not zero-indexed, we need to transform the given id into
+// its associated index.
+struct BlockIdToIndexFunctor {
+  using argument_type = unsigned;
+  unsigned operator()(unsigned ID) const { return ID - BI_FIRST; }
+};
+
+struct RecordIdToIndexFunctor {
+  using argument_type = unsigned;
+  unsigned operator()(unsigned ID) const { return ID - RI_FIRST; }
+};
+
+using AbbrevDsc = void (*)(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev);
+
+static void AbbrevGen(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev,
+                      const std::initializer_list<llvm::BitCodeAbbrevOp> Ops) {
+  for (const auto &Op : Ops)
+    Abbrev->Add(Op);
+}
+
+static void BoolAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+  AbbrevGen(Abbrev,
+            {// 0. Boolean
+             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+                                   BitCodeConstants::BoolSize)});
+}
+
+static void IntAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+  AbbrevGen(Abbrev,
+            {// 0. Fixed-size integer
+             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+                                   BitCodeConstants::IntSize)});
+}
+
+static void SymbolIDAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+  AbbrevGen(Abbrev,
+            {// 0. Fixed-size integer (length of the sha1'd USR)
+             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+                                   BitCodeConstants::USRLengthSize),
+             // 1. Fixed-size array of Char6 (USR)
+             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Array),
+             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+                                   BitCodeConstants::USRBitLengthSize)});
+}
+
+static void StringAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+  AbbrevGen(Abbrev,
+            {// 0. Fixed-size integer (length of the following string)
+             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+                                   BitCodeConstants::StringLengthSize),
+             // 1. The string blob
+             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
+}
+
+// Assumes that the file will not have more than 65535 lines.
+static void LocationAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+  AbbrevGen(
+      Abbrev,
+      {// 0. Fixed-size integer (line number)
+       llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+                             BitCodeConstants::LineNumberSize),
+       // 1. Fixed-size integer (length of the following string (filename))
+       llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+                             BitCodeConstants::StringLengthSize),
+       // 2. The string blob
+       llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
+}
+
+static void ReferenceAbbrev(std::shared_ptr<llvm::BitCodeAbbrev> &Abbrev) {
+  AbbrevGen(Abbrev,
+            {// 0. Fixed-size integer (ref type)
+             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+                                   BitCodeConstants::ReferenceTypeSize),
+             // 1. Fixed-size integer (length of the USR or UnresolvedName)
+             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Fixed,
+                                   BitCodeConstants::StringLengthSize),
+             // 2. The string blob
+             llvm::BitCodeAbbrevOp(llvm::BitCodeAbbrevOp::Blob)});
+}
+
+struct RecordIdDsc {
+  llvm::StringRef Name;
+  AbbrevDsc Abbrev = nullptr;
+
+  RecordIdDsc() = default;
+  RecordIdDsc(llvm::StringRef Name, AbbrevDsc Abbrev)
+      : Name(Name), Abbrev(Abbrev) {}
+
+  // Is this 'description' valid?
+  operator bool() const {
+    return Abbrev != nullptr && Name.data() != nullptr && !Name.empty();
+  }
+};
+
+static const llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor>
+    BlockIdNameMap = []() {
+      llvm::IndexedMap<llvm::StringRef, BlockIdToIndexFunctor> BlockIdNameMap;
+      BlockIdNameMap.resize(BlockIdCount);
+
+      // There is no init-list constructor for the IndexedMap, so have to
+      // improvise
+      static const std::vector<std::pair<BlockId, const char *const>> Inits = {
+          {BI_VERSION_BLOCK_ID, "VersionBlock"},
+          {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"},
+          {BI_ENUM_BLOCK_ID, "EnumBlock"},
+          {BI_TYPE_BLOCK_ID, "TypeBlock"},
+          {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},
+          {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},
+          {BI_RECORD_BLOCK_ID, "RecordBlock"},
+          {BI_FUNCTION_BLOCK_ID, "FunctionBlock"},
+          {BI_COMMENT_BLOCK_ID, "CommentBlock"}};
+      assert(Inits.size() == BlockIdCount);
+      for (const auto &Init : Inits)
+        BlockIdNameMap[Init.first] = Init.second;
+      assert(BlockIdNameMap.size() == BlockIdCount);
+      return BlockIdNameMap;
+    }();
+
+static const llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor>
+    RecordIdNameMap = []() {
+      llvm::IndexedMap<RecordIdDsc, RecordIdToIndexFunctor> RecordIdNameMap;
+      RecordIdNameMap.resize(RecordIdCount);
+
+      // There is no init-list constructor for the IndexedMap, so have to
+      // improvise
+      static const std::vector<std::pair<RecordId, RecordIdDsc>> Inits = {
+          {VERSION, {"Version", &IntAbbrev}},
+          {COMMENT_KIND, {"Kind", &StringAbbrev}},
+          {COMMENT_TEXT, {"Text", &StringAbbrev}},
+          {COMMENT_NAME, {"Name", &StringAbbrev}},
+          {COMMENT_DIRECTION, {"Direction", &StringAbbrev}},
+          {COMMENT_PARAMNAME, {"ParamName", &StringAbbrev}},
+          {COMMENT_CLOSENAME, {"CloseName", &StringAbbrev}},
+          {COMMENT_SELFCLOSING, {"SelfClosing", &BoolAbbrev}},
+          {COMMENT_EXPLICIT, {"Explicit", &BoolAbbrev}},
+          {COMMENT_ATTRKEY, {"AttrKey", &StringAbbrev}},
+          {COMMENT_ATTRVAL, {"AttrVal", &StringAbbrev}},
+          {COMMENT_ARG, {"Arg", &StringAbbrev}},
+          {TYPE_REF, {"Type", &ReferenceAbbrev}},
+          {FIELD_TYPE_REF, {"Type", &ReferenceAbbrev}},
+          {FIELD_TYPE_NAME, {"Name", &StringAbbrev}},
+          {MEMBER_TYPE_REF, {"Type", &ReferenceAbbrev}},
+          {MEMBER_TYPE_NAME, {"Name", &StringAbbrev}},
+          {MEMBER_TYPE_ACCESS, {"Access", &IntAbbrev}},
+          {NAMESPACE_USR, {"USR", &SymbolIDAbbrev}},
+          {NAMESPACE_NAME, {"Name", &StringAbbrev}},
+          {NAMESPACE_NAMESPACE, {"Namespace", &ReferenceAbbrev}},
+          {ENUM_USR, {"USR", &SymbolIDAbbrev}},
+          {ENUM_NAME, {"Name", &StringAbbrev}},
+          {ENUM_NAMESPACE, {"Namespace", &ReferenceAbbrev}},
+          {ENUM_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
+          {ENUM_LOCATION, {"Location", &LocationAbbrev}},
+          {ENUM_MEMBER, {"Member", &StringAbbrev}},
+          {ENUM_SCOPED, {"Scoped", &BoolAbbrev}},
+          {RECORD_USR, {"USR", &SymbolIDAbbrev}},
+          {RECORD_NAME, {"Name", &StringAbbrev}},
+          {RECORD_NAMESPACE, {"Namespace", &ReferenceAbbrev}},
+          {RECORD_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
+          {RECORD_LOCATION, {"Location", &LocationAbbrev}},
+          {RECORD_TAG_TYPE, {"TagType", &IntAbbrev}},
+          {RECORD_PARENT, {"Parent", &ReferenceAbbrev}},
+          {RECORD_VPARENT, {"VParent", &ReferenceAbbrev}},
+          {FUNCTION_USR, {"USR", &SymbolIDAbbrev}},
+          {FUNCTION_NAME, {"Name", &StringAbbrev}},
+          {FUNCTION_NAMESPACE, {"Namespace", &ReferenceAbbrev}},
+          {FUNCTION_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
+          {FUNCTION_LOCATION, {"Location", &LocationAbbrev}},
+          {FUNCTION_PARENT, {"Parent", &ReferenceAbbrev}},
+          {FUNCTION_ACCESS, {"Access", &IntAbbrev}},
+          {FUNCTION_IS_METHOD, {"IsMethod", &BoolAbbrev}}};
+      assert(Inits.size() == RecordIdCount);
+      for (const auto &Init : Inits) {
+        RecordIdNameMap[Init.first] = Init.second;
+        assert((Init.second.Name.size() + 1) <= BitCodeConstants::RecordSize);
+      }
+      assert(RecordIdNameMap.size() == RecordIdCount);
+      return RecordIdNameMap;
+    }();
+
+static const std::vector<std::pair<BlockId, std::vector<RecordId>>>
+    RecordsByBlock{
+        // Version Block
+        {BI_VERSION_BLOCK_ID, {VERSION}},
+        // Comment Block
+        {BI_COMMENT_BLOCK_ID,
+         {COMMENT_KIND, COMMENT_TEXT, COMMENT_NAME, COMMENT_DIRECTION,
+          COMMENT_PARAMNAME, COMMENT_CLOSENAME, COMMENT_SELFCLOSING,
+          COMMENT_EXPLICIT, COMMENT_ATTRKEY, COMMENT_ATTRVAL, COMMENT_ARG}},
+        // Type Block
+        {BI_TYPE_BLOCK_ID, {TYPE_REF}},
+        // FieldType Block
+        {BI_FIELD_TYPE_BLOCK_ID, {FIELD_TYPE_REF, FIELD_TYPE_NAME}},
+        // MemberType Block
+        {BI_MEMBER_TYPE_BLOCK_ID,
+         {MEMBER_TYPE_REF, MEMBER_TYPE_NAME, MEMBER_TYPE_ACCESS}},
+        // Enum Block
+        {BI_ENUM_BLOCK_ID,
+         {ENUM_USR, ENUM_NAME, ENUM_NAMESPACE, ENUM_DEFLOCATION, ENUM_LOCATION,
+          ENUM_MEMBER, ENUM_SCOPED}},
+        // Namespace Block
+        {BI_NAMESPACE_BLOCK_ID,
+         {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_NAMESPACE}},
+        // Record Block
+        {BI_RECORD_BLOCK_ID,
+         {RECORD_USR, RECORD_NAME, RECORD_NAMESPACE, RECORD_DEFLOCATION,
+          RECORD_LOCATION, RECORD_TAG_TYPE, RECORD_PARENT, RECORD_VPARENT}},
+        // Function Block
+        {BI_FUNCTION_BLOCK_ID,
+         {FUNCTION_USR, FUNCTION_NAME, FUNCTION_NAMESPACE, FUNCTION_DEFLOCATION,
+          FUNCTION_LOCATION, FUNCTION_PARENT, FUNCTION_ACCESS,
+          FUNCTION_IS_METHOD}}};
+
+// AbbreviationMap
+
+void ClangDocBitcodeWriter::AbbreviationMap::add(RecordId RID,
+                                                 unsigned AbbrevID) {
+  assert(RecordIdNameMap[RID] && "Unknown RecordId.");
+  assert(Abbrevs.find(RID) == Abbrevs.end() && "Abbreviation already added.");
+  Abbrevs[RID] = AbbrevID;
+}
+
+unsigned ClangDocBitcodeWriter::AbbreviationMap::get(RecordId RID) const {
+  assert(RecordIdNameMap[RID] && "Unknown RecordId.");
+  assert(Abbrevs.find(RID) != Abbrevs.end() && "Unknown abbreviation.");
+  return Abbrevs.lookup(RID);
+}
+
+// Validation and Overview Blocks
+
+/// \brief Emits the magic number header to check that its the right format,
+/// in this case, 'DOCS'.
+void ClangDocBitcodeWriter::emitHeader() {
+  for (char C : llvm::StringRef("DOCS"))
+    Stream.Emit((unsigned)C, BitCodeConstants::SignatureBitSize);
+}
+
+void ClangDocBitcodeWriter::emitVersionBlock() {
+  StreamSubBlockGuard Block(Stream, BI_VERSION_BLOCK_ID);
+  emitRecord(VersionNumber, VERSION);
+}
+
+/// \brief Emits a block ID and the block name to the BLOCKINFO block.
+void ClangDocBitcodeWriter::emitBlockID(BlockId BID) {
+  const auto &BlockIdName = BlockIdNameMap[BID];
+  assert(BlockIdName.data() && BlockIdName.size() && "Unknown BlockId.");
+
+  Record.clear();
+  Record.push_back(BID);
+  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETBID, Record);
+  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_BLOCKNAME,
+                    ArrayRef<unsigned char>(BlockIdName.bytes_begin(),
+                                            BlockIdName.bytes_end()));
+}
+
+/// \brief Emits a record name to the BLOCKINFO block.
+void ClangDocBitcodeWriter::emitRecordID(RecordId ID) {
+  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+  prepRecordData(ID);
+  Record.append(RecordIdNameMap[ID].Name.begin(),
+                RecordIdNameMap[ID].Name.end());
+  Stream.EmitRecord(llvm::bitc::BLOCKINFO_CODE_SETRECORDNAME, Record);
+}
+
+// Abbreviations
+
+void ClangDocBitcodeWriter::emitAbbrev(RecordId ID, BlockId Block) {
+  assert(RecordIdNameMap[ID] && "Unknown abbreviation.");
+  auto Abbrev = std::make_shared<llvm::BitCodeAbbrev>();
+  Abbrev->Add(llvm::BitCodeAbbrevOp(ID));
+  RecordIdNameMap[ID].Abbrev(Abbrev);
+  Abbrevs.add(ID, Stream.EmitBlockInfoAbbrev(Block, std::move(Abbrev)));
+}
+
+// Records
+
+void ClangDocBitcodeWriter::emitRecord(const SymbolID &Sym, RecordId ID) {
+  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+  assert(RecordIdNameMap[ID].Abbrev == &SymbolIDAbbrev &&
+         "Abbrev type mismatch.");
+  if (!prepRecordData(ID, !Sym.empty()))
+    return;
+  assert(Sym.size() == 20);
+  Record.push_back(Sym.size());
+  Record.append(Sym.begin(), Sym.end());
+  Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
+}
+
+void ClangDocBitcodeWriter::emitRecord(llvm::StringRef Str, RecordId ID) {
+  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+  assert(RecordIdNameMap[ID].Abbrev == &StringAbbrev &&
+         "Abbrev type mismatch.");
+  if (!prepRecordData(ID, !Str.empty()))
+    return;
+  assert(Str.size() < (1U << BitCodeConstants::StringLengthSize));
+  Record.push_back(Str.size());
+  Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Str);
+}
+
+void ClangDocBitcodeWriter::emitRecord(const Location &Loc, RecordId ID) {
+  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+  assert(RecordIdNameMap[ID].Abbrev == &LocationAbbrev &&
+         "Abbrev type mismatch.");
+  if (!prepRecordData(ID, true))
+    return;
+  // FIXME: Assert that the line number is of the appropriate size.
+  Record.push_back(Loc.LineNumber);
+  assert(Loc.Filename.size() < (1U << BitCodeConstants::StringLengthSize));
+  // Record.push_back(Loc.Filename.size());
+  // Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, Loc.Filename);
+  Record.push_back(4);
+  Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, "test");
+}
+
+void ClangDocBitcodeWriter::emitRecord(const Reference &Ref, RecordId ID) {
+  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+  assert(RecordIdNameMap[ID].Abbrev == &ReferenceAbbrev &&
+         "Abbrev type mismatch.");
+  SmallString<40> StringUSR;
+  StringRef OutString;
+  if (Ref.RefType == InfoType::IT_default)
+    OutString = Ref.UnresolvedName;
+  else {
+    StringUSR = llvm::toHex(llvm::toStringRef(Ref.USR));
+    OutString = StringUSR;
+  }
+  if (!prepRecordData(ID, !OutString.empty()))
+    return;
+  assert(OutString.size() < (1U << BitCodeConstants::StringLengthSize));
+  Record.push_back((int)Ref.RefType);
+  Record.push_back(OutString.size());
+  Stream.EmitRecordWithBlob(Abbrevs.get(ID), Record, OutString);
+}
+
+void ClangDocBitcodeWriter::emitRecord(bool Val, RecordId ID) {
+  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+  assert(RecordIdNameMap[ID].Abbrev == &BoolAbbrev && "Abbrev type mismatch.");
+  if (!prepRecordData(ID, Val))
+    return;
+  Record.push_back(Val);
+  Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
+}
+
+void ClangDocBitcodeWriter::emitRecord(int Val, RecordId ID) {
+  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+  assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
+  if (!prepRecordData(ID, Val))
+    return;
+  // FIXME: Assert that the integer is of the appropriate size.
+  Record.push_back(Val);
+  Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
+}
+
+void ClangDocBitcodeWriter::emitRecord(unsigned Val, RecordId ID) {
+  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+  assert(RecordIdNameMap[ID].Abbrev == &IntAbbrev && "Abbrev type mismatch.");
+  if (!prepRecordData(ID, Val))
+    return;
+  assert(Val < (1U << BitCodeConstants::IntSize));
+  Record.push_back(Val);
+  Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
+}
+
+bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) {
+  assert(RecordIdNameMap[ID] && "Unknown RecordId.");
+  if (!ShouldEmit)
+    return false;
+  Record.clear();
+  Record.push_back(ID);
+  return true;
+}
+
+// BlockInfo Block
+
+void ClangDocBitcodeWriter::emitBlockInfoBlock() {
+  Stream.EnterBlockInfoBlock();
+  for (const auto &Block : RecordsByBlock) {
+    assert(Block.second.size() < (1U << BitCodeConstants::SubblockIDSize));
+    emitBlockInfo(Block.first, Block.second);
+  }
+  Stream.ExitBlock();
+}
+
+void ClangDocBitcodeWriter::emitBlockInfo(BlockId BID,
+                                          const std::vector<RecordId> &RIDs) {
+  assert(RIDs.size() < (1U << BitCodeConstants::SubblockIDSize));
+  emitBlockID(BID);
+  for (RecordId RID : RIDs) {
+    emitRecordID(RID);
+    emitAbbrev(RID, BID);
+  }
+}
+
+// Block emission
+
+void ClangDocBitcodeWriter::emitBlock(const TypeInfo &T) {
+  StreamSubBlockGuard Block(Stream, BI_TYPE_BLOCK_ID);
+  emitRecord(T.Type, TYPE_REF);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {
+  StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
+  emitRecord(T.Type, FIELD_TYPE_REF);
+  emitRecord(T.Name, FIELD_TYPE_NAME);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const MemberTypeInfo &T) {
+  StreamSubBlockGuard Block(Stream, BI_MEMBER_TYPE_BLOCK_ID);
+  emitRecord(T.Type, MEMBER_TYPE_REF);
+  emitRecord(T.Name, MEMBER_TYPE_NAME);
+  emitRecord(T.Access, MEMBER_TYPE_ACCESS);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const CommentInfo &I) {
+  StreamSubBlockGuard Block(Stream, BI_COMMENT_BLOCK_ID);
+  for (const auto &L :
+       std::vector<std::pair<llvm::StringRef, RecordId>>{
+           {I.Kind, COMMENT_KIND},
+           {I.Text, COMMENT_TEXT},
+           {I.Name, COMMENT_NAME},
+           {I.Direction, COMMENT_DIRECTION},
+           {I.ParamName, COMMENT_PARAMNAME},
+           {I.CloseName, COMMENT_CLOSENAME}})
+    emitRecord(L.first, L.second);
+  emitRecord(I.SelfClosing, COMMENT_SELFCLOSING);
+  emitRecord(I.Explicit, COMMENT_EXPLICIT);
+  for (const auto &A : I.AttrKeys)
+    emitRecord(A, COMMENT_ATTRKEY);
+  for (const auto &A : I.AttrValues)
+    emitRecord(A, COMMENT_ATTRVAL);
+  for (const auto &A : I.Args)
+    emitRecord(A, COMMENT_ARG);
+  for (const auto &C : I.Children)
+    emitBlock(*C);
+}
+
+#define EMITINFO(X)                                                            \
+  emitRecord(I.USR, X##_USR);                                                  \
+  emitRecord(I.Name, X##_NAME);                                                \
+  for (const auto &N : I.Namespace)                                            \
+    emitRecord(N, X##_NAMESPACE);                                              \
+  for (const auto &CI : I.Description)                                         \
+    emitBlock(CI);
+
+void ClangDocBitcodeWriter::emitBlock(const NamespaceInfo &I) {
+  StreamSubBlockGuard Block(Stream, BI_NAMESPACE_BLOCK_ID);
+  EMITINFO(NAMESPACE)
+}
+
+void ClangDocBitcodeWriter::emitBlock(const EnumInfo &I) {
+  StreamSubBlockGuard Block(Stream, BI_ENUM_BLOCK_ID);
+  EMITINFO(ENUM)
+  if (I.DefLoc)
+    emitRecord(I.DefLoc.getValue(), ENUM_DEFLOCATION);
+  for (const auto &L : I.Loc)
+    emitRecord(L, ENUM_LOCATION);
+  emitRecord(I.Scoped, ENUM_SCOPED);
+  for (const auto &N : I.Members)
+    emitRecord(N, ENUM_MEMBER);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const RecordInfo &I) {
+  StreamSubBlockGuard Block(Stream, BI_RECORD_BLOCK_ID);
+  EMITINFO(RECORD)
+  if (I.DefLoc)
+    emitRecord(I.DefLoc.getValue(), RECORD_DEFLOCATION);
+  for (const auto &L : I.Loc)
+    emitRecord(L, RECORD_LOCATION);
+  emitRecord(I.TagType, RECORD_TAG_TYPE);
+  for (const auto &N : I.Members)
+    emitBlock(N);
+  for (const auto &P : I.Parents)
+    emitRecord(P, RECORD_PARENT);
+  for (const auto &P : I.VirtualParents)
+    emitRecord(P, RECORD_VPARENT);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const FunctionInfo &I) {
+  StreamSubBlockGuard Block(Stream, BI_FUNCTION_BLOCK_ID);
+  EMITINFO(FUNCTION)
+  emitRecord(I.IsMethod, FUNCTION_IS_METHOD);
+  if (I.DefLoc)
+    emitRecord(I.DefLoc.getValue(), FUNCTION_DEFLOCATION);
+  for (const auto &L : I.Loc)
+    emitRecord(L, FUNCTION_LOCATION);
+  emitRecord(I.Parent, FUNCTION_PARENT);
+  emitBlock(I.ReturnType);
+  for (const auto &N : I.Params)
+    emitBlock(N);
+}
+
+#undef EMITINFO
+
+} // namespace doc
+} // namespace clang
diff --git a/clang-doc/BitcodeWriter.h b/clang-doc/BitcodeWriter.h
new file mode 100644
index 0000000..d0e0689
--- /dev/null
+++ b/clang-doc/BitcodeWriter.h
@@ -0,0 +1,201 @@
+//===--  BitcodeWriter.h - ClangDoc Bitcode Writer --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a writer for serializing the clang-doc internal
+// representation to LLVM bitcode. The writer takes in a stream and emits the
+// generated bitcode to that stream.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
+
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Bitcode/BitstreamWriter.h"
+#include <initializer_list>
+#include <vector>
+
+namespace clang {
+namespace doc {
+
+// Current version number of clang-doc bitcode.
+// Should be bumped when removing or changing BlockIds, RecordIds, or
+// BitCodeConstants, though they can be added without breaking it.
+static const unsigned VersionNumber = 1;
+
+struct BitCodeConstants {
+  static constexpr unsigned RecordSize = 16U;
+  static constexpr unsigned SignatureBitSize = 8U;
+  static constexpr unsigned SubblockIDSize = 4U;
+  static constexpr unsigned BoolSize = 1U;
+  static constexpr unsigned IntSize = 16U;
+  static constexpr unsigned StringLengthSize = 16U;
+  static constexpr unsigned FilenameLengthSize = 16U;
+  static constexpr unsigned LineNumberSize = 16U;
+  static constexpr unsigned ReferenceTypeSize = 8U;
+  static constexpr unsigned USRLengthSize = 6U;
+  static constexpr unsigned USRBitLengthSize = 8U;
+};
+
+// New Ids need to be added to both the enum here and the relevant IdNameMap in
+// the implementation file.
+enum BlockId {
+  BI_VERSION_BLOCK_ID = llvm::bitc::FIRST_APPLICATION_BLOCKID,
+  BI_NAMESPACE_BLOCK_ID,
+  BI_ENUM_BLOCK_ID,
+  BI_TYPE_BLOCK_ID,
+  BI_FIELD_TYPE_BLOCK_ID,
+  BI_MEMBER_TYPE_BLOCK_ID,
+  BI_RECORD_BLOCK_ID,
+  BI_FUNCTION_BLOCK_ID,
+  BI_COMMENT_BLOCK_ID,
+  BI_FIRST = BI_VERSION_BLOCK_ID,
+  BI_LAST = BI_COMMENT_BLOCK_ID
+};
+
+// New Ids need to be added to the enum here, and to the relevant IdNameMap and
+// initialization list in the implementation file.
+#define INFORECORDS(X) X##_USR, X##_NAME, X##_NAMESPACE
+
+enum RecordId {
+  VERSION = 1,
+  INFORECORDS(FUNCTION),
+  FUNCTION_DEFLOCATION,
+  FUNCTION_LOCATION,
+  FUNCTION_PARENT,
+  FUNCTION_ACCESS,
+  FUNCTION_IS_METHOD,
+  COMMENT_KIND,
+  COMMENT_TEXT,
+  COMMENT_NAME,
+  COMMENT_DIRECTION,
+  COMMENT_PARAMNAME,
+  COMMENT_CLOSENAME,
+  COMMENT_SELFCLOSING,
+  COMMENT_EXPLICIT,
+  COMMENT_ATTRKEY,
+  COMMENT_ATTRVAL,
+  COMMENT_ARG,
+  TYPE_REF,
+  FIELD_TYPE_REF,
+  FIELD_TYPE_NAME,
+  MEMBER_TYPE_REF,
+  MEMBER_TYPE_NAME,
+  MEMBER_TYPE_ACCESS,
+  INFORECORDS(NAMESPACE),
+  INFORECORDS(ENUM),
+  ENUM_DEFLOCATION,
+  ENUM_LOCATION,
+  ENUM_MEMBER,
+  ENUM_SCOPED,
+  INFORECORDS(RECORD),
+  RECORD_DEFLOCATION,
+  RECORD_LOCATION,
+  RECORD_TAG_TYPE,
+  RECORD_PARENT,
+  RECORD_VPARENT,
+  RI_FIRST = VERSION,
+  RI_LAST = RECORD_VPARENT
+};
+
+static constexpr unsigned BlockIdCount = BI_LAST - BI_FIRST + 1;
+static constexpr unsigned RecordIdCount = RI_LAST - RI_FIRST + 1;
+
+#undef INFORECORDS
+
+class ClangDocBitcodeWriter {
+public:
+  ClangDocBitcodeWriter(llvm::BitstreamWriter &Stream) : Stream(Stream) {
+    emitHeader();
+    emitBlockInfoBlock();
+    emitVersionBlock();
+  }
+
+#ifndef NDEBUG // Don't want explicit dtor unless needed.
+  ~ClangDocBitcodeWriter() {
+    // Check that the static size is large-enough.
+    assert(Record.capacity() > BitCodeConstants::RecordSize);
+  }
+#endif
+
+  // Block emission of different info types.
+  void emitBlock(const NamespaceInfo &I);
+  void emitBlock(const RecordInfo &I);
+  void emitBlock(const FunctionInfo &I);
+  void emitBlock(const EnumInfo &I);
+  void emitBlock(const TypeInfo &B);
+  void emitBlock(const FieldTypeInfo &B);
+  void emitBlock(const MemberTypeInfo &B);
+  void emitBlock(const CommentInfo &B);
+
+private:
+  class AbbreviationMap {
+    llvm::DenseMap<unsigned, unsigned> Abbrevs;
+
+  public:
+    AbbreviationMap() : Abbrevs(RecordIdCount) {}
+
+    void add(RecordId RID, unsigned AbbrevID);
+    unsigned get(RecordId RID) const;
+  };
+
+  class StreamSubBlockGuard {
+    llvm::BitstreamWriter &Stream;
+
+  public:
+    StreamSubBlockGuard(llvm::BitstreamWriter &Stream_, BlockId ID)
+        : Stream(Stream_) {
+      // NOTE: SubBlockIDSize could theoretically be calculated on the fly,
+      // based on the initialization list of records in each block.
+      Stream.EnterSubblock(ID, BitCodeConstants::SubblockIDSize);
+    }
+
+    StreamSubBlockGuard() = default;
+    StreamSubBlockGuard(const StreamSubBlockGuard &) = delete;
+    StreamSubBlockGuard &operator=(const StreamSubBlockGuard &) = delete;
+
+    ~StreamSubBlockGuard() { Stream.ExitBlock(); }
+  };
+
+  // Emission of validation and overview blocks.
+  void emitHeader();
+  void emitVersionBlock();
+  void emitRecordID(RecordId ID);
+  void emitBlockID(BlockId ID);
+  void emitBlockInfoBlock();
+  void emitBlockInfo(BlockId BID, const std::vector<RecordId> &RIDs);
+
+  // Emission of individual record types.
+  void emitRecord(StringRef Str, RecordId ID);
+  void emitRecord(const SymbolID &Str, RecordId ID);
+  void emitRecord(const Location &Loc, RecordId ID);
+  void emitRecord(const Reference &Ref, RecordId ID);
+  void emitRecord(bool Value, RecordId ID);
+  void emitRecord(int Value, RecordId ID);
+  void emitRecord(unsigned Value, RecordId ID);
+  bool prepRecordData(RecordId ID, bool ShouldEmit = true);
+
+  // Emission of appropriate abbreviation type.
+  void emitAbbrev(RecordId ID, BlockId Block);
+
+  // Static size is the maximum length of the block/record names we're pushing
+  // to this + 1. Longest is currently `MemberTypeBlock` at 15 chars.
+  SmallVector<uint32_t, BitCodeConstants::RecordSize> Record;
+  llvm::BitstreamWriter &Stream;
+  AbbreviationMap Abbrevs;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_BITCODEWRITER_H
diff --git a/clang-doc/CMakeLists.txt b/clang-doc/CMakeLists.txt
new file mode 100644
index 0000000..1852baa
--- /dev/null
+++ b/clang-doc/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(LLVM_LINK_COMPONENTS
+  support
+  )
+
+add_clang_library(clangDoc
+  BitcodeWriter.cpp
+  ClangDoc.cpp
+  Mapper.cpp
+  Serialize.cpp
+
+  LINK_LIBS
+  clangAnalysis
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangFrontend
+  clangIndex
+  clangLex
+  clangTooling
+  clangToolingCore
+  )
+
+add_subdirectory(tool)
diff --git a/clang-doc/ClangDoc.cpp b/clang-doc/ClangDoc.cpp
new file mode 100644
index 0000000..cd73723
--- /dev/null
+++ b/clang-doc/ClangDoc.cpp
@@ -0,0 +1,61 @@
+//===-- ClangDoc.cpp - ClangDoc ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the main entry point for the clang-doc tool. It runs
+// the clang-doc mapper on a given set of source code files using a
+// FrontendActionFactory.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangDoc.h"
+#include "Mapper.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Frontend/ASTConsumers.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+
+namespace clang {
+namespace doc {
+
+class MapperActionFactory : public tooling::FrontendActionFactory {
+public:
+  MapperActionFactory(tooling::ExecutionContext *ECtx) : ECtx(ECtx) {}
+  clang::FrontendAction *create() override;
+
+private:
+  tooling::ExecutionContext *ECtx;
+};
+
+clang::FrontendAction *MapperActionFactory::create() {
+  class ClangDocAction : public clang::ASTFrontendAction {
+  public:
+    ClangDocAction(ExecutionContext *ECtx) : ECtx(ECtx) {}
+
+    std::unique_ptr<clang::ASTConsumer>
+    CreateASTConsumer(clang::CompilerInstance &Compiler,
+                      llvm::StringRef InFile) override {
+      return llvm::make_unique<MapASTVisitor>(&Compiler.getASTContext(), ECtx);
+    }
+
+  private:
+    ExecutionContext *ECtx;
+  };
+  return new ClangDocAction(ECtx);
+}
+
+std::unique_ptr<tooling::FrontendActionFactory>
+newMapperActionFactory(tooling::ExecutionContext *ECtx) {
+  return llvm::make_unique<MapperActionFactory>(ECtx);
+}
+
+} // namespace doc
+} // namespace clang
diff --git a/clang-doc/ClangDoc.h b/clang-doc/ClangDoc.h
new file mode 100644
index 0000000..9a9817c
--- /dev/null
+++ b/clang-doc/ClangDoc.h
@@ -0,0 +1,33 @@
+//===-- ClangDoc.h - ClangDoc -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file exposes a method to craete the FrontendActionFactory for the
+// clang-doc tool. The factory runs the clang-doc mapper on a given set of
+// source code files, storing the results key-value pairs in its
+// ExecutionContext.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
+
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/StandaloneExecution.h"
+#include "clang/Tooling/Tooling.h"
+
+namespace clang {
+namespace doc {
+
+std::unique_ptr<tooling::FrontendActionFactory>
+newMapperActionFactory(tooling::ExecutionContext *ECtx);
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_CLANGDOC_H
diff --git a/clang-doc/Mapper.cpp b/clang-doc/Mapper.cpp
new file mode 100644
index 0000000..f3ef99e
--- /dev/null
+++ b/clang-doc/Mapper.cpp
@@ -0,0 +1,86 @@
+//===-- Mapper.cpp - ClangDoc Mapper ----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Mapper.h"
+#include "BitcodeWriter.h"
+#include "Serialize.h"
+#include "clang/AST/Comment.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/ADT/StringExtras.h"
+
+using clang::comments::FullComment;
+
+namespace clang {
+namespace doc {
+
+void MapASTVisitor::HandleTranslationUnit(ASTContext &Context) {
+  TraverseDecl(Context.getTranslationUnitDecl());
+}
+
+template <typename T> bool MapASTVisitor::mapDecl(const T *D) {
+  // If we're looking a decl not in user files, skip this decl.
+  if (D->getASTContext().getSourceManager().isInSystemHeader(D->getLocation()))
+    return true;
+
+  llvm::SmallString<128> USR;
+  // If there is an error generating a USR for the decl, skip this decl.
+  if (index::generateUSRForDecl(D, USR))
+    return true;
+
+  ECtx->reportResult(llvm::toHex(llvm::toStringRef(serialize::hashUSR(USR))),
+                     serialize::emitInfo(D, getComment(D, D->getASTContext()),
+                                         getLine(D, D->getASTContext()),
+                                         getFile(D, D->getASTContext())));
+  return true;
+}
+
+bool MapASTVisitor::VisitNamespaceDecl(const NamespaceDecl *D) {
+  return mapDecl(D);
+}
+
+bool MapASTVisitor::VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }
+
+bool MapASTVisitor::VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }
+
+bool MapASTVisitor::VisitCXXMethodDecl(const CXXMethodDecl *D) {
+  return mapDecl(D);
+}
+
+bool MapASTVisitor::VisitFunctionDecl(const FunctionDecl *D) {
+  // Don't visit CXXMethodDecls twice
+  if (dyn_cast<CXXMethodDecl>(D))
+    return true;
+  return mapDecl(D);
+}
+
+comments::FullComment *
+MapASTVisitor::getComment(const NamedDecl *D, const ASTContext &Context) const {
+  RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
+  // FIXME: Move setAttached to the initial comment parsing.
+  if (Comment) {
+    Comment->setAttached();
+    return Comment->parse(Context, nullptr, D);
+  }
+  return nullptr;
+}
+
+int MapASTVisitor::getLine(const NamedDecl *D,
+                           const ASTContext &Context) const {
+  return Context.getSourceManager().getPresumedLoc(D->getLocStart()).getLine();
+}
+
+llvm::StringRef MapASTVisitor::getFile(const NamedDecl *D,
+                                       const ASTContext &Context) const {
+  return Context.getSourceManager()
+      .getPresumedLoc(D->getLocStart())
+      .getFilename();
+}
+
+} // namespace doc
+} // namespace clang
diff --git a/clang-doc/Mapper.h b/clang-doc/Mapper.h
new file mode 100644
index 0000000..1aa3f46
--- /dev/null
+++ b/clang-doc/Mapper.h
@@ -0,0 +1,57 @@
+//===-- Mapper.h - ClangDoc Mapper ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the Mapper piece of the clang-doc tool. It implements
+// a RecursiveASTVisitor to look at each declaration and populate the info
+// into the internal representation. Each seen declaration is serialized to
+// to bitcode and written out to the ExecutionContext as a KV pair where the
+// key is the declaration's USR and the value is the serialized bitcode.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_MAPPER_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_MAPPER_H
+
+#include "clang/AST/RecursiveASTVisitor.h"
+#include "clang/Tooling/Execution.h"
+
+using namespace clang::comments;
+using namespace clang::tooling;
+
+namespace clang {
+namespace doc {
+
+class MapASTVisitor : public clang::RecursiveASTVisitor<MapASTVisitor>,
+                      public ASTConsumer {
+public:
+  explicit MapASTVisitor(ASTContext *Ctx, ExecutionContext *ECtx)
+      : ECtx(ECtx) {}
+
+  void HandleTranslationUnit(ASTContext &Context) override;
+  bool VisitNamespaceDecl(const NamespaceDecl *D);
+  bool VisitRecordDecl(const RecordDecl *D);
+  bool VisitEnumDecl(const EnumDecl *D);
+  bool VisitCXXMethodDecl(const CXXMethodDecl *D);
+  bool VisitFunctionDecl(const FunctionDecl *D);
+
+private:
+  template <typename T> bool mapDecl(const T *D);
+
+  int getLine(const NamedDecl *D, const ASTContext &Context) const;
+  StringRef getFile(const NamedDecl *D, const ASTContext &Context) const;
+  comments::FullComment *getComment(const NamedDecl *D,
+                                    const ASTContext &Context) const;
+
+  ExecutionContext *ECtx;
+};
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_MAPPER_H
diff --git a/clang-doc/Representation.h b/clang-doc/Representation.h
new file mode 100644
index 0000000..8b772a3
--- /dev/null
+++ b/clang-doc/Representation.h
@@ -0,0 +1,184 @@
+///===-- Representation.h - ClangDoc Represenation --------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the internal representations of different declaration
+// types for the clang-doc tool.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
+
+#include "clang/AST/Type.h"
+#include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
+#include <array>
+#include <string>
+
+namespace clang {
+namespace doc {
+
+using SymbolID = std::array<uint8_t, 20>;
+
+struct Info;
+enum class InfoType {
+  IT_namespace,
+  IT_record,
+  IT_function,
+  IT_enum,
+  IT_default
+};
+
+// A representation of a parsed comment.
+struct CommentInfo {
+  CommentInfo() = default;
+  CommentInfo(CommentInfo &&Other) : Children(std::move(Other.Children)) {}
+
+  SmallString<16>
+      Kind; // Kind of comment (TextComment, InlineCommandComment,
+            // HTMLStartTagComment, HTMLEndTagComment, BlockCommandComment,
+            // ParamCommandComment, TParamCommandComment, VerbatimBlockComment,
+            // VerbatimBlockLineComment, VerbatimLineComment).
+  SmallString<64> Text;      // Text of the comment.
+  SmallString<16> Name;      // Name of the comment (for Verbatim and HTML).
+  SmallString<8> Direction;  // Parameter direction (for (T)ParamCommand).
+  SmallString<16> ParamName; // Parameter name (for (T)ParamCommand).
+  SmallString<16> CloseName; // Closing tag name (for VerbatimBlock).
+  bool SelfClosing = false;  // Indicates if tag is self-closing (for HTML).
+  bool Explicit = false; // Indicates if the direction of a param is explicit
+                         // (for (T)ParamCommand).
+  llvm::SmallVector<SmallString<16>, 4>
+      AttrKeys; // List of attribute keys (for HTML).
+  llvm::SmallVector<SmallString<16>, 4>
+      AttrValues; // List of attribute values for each key (for HTML).
+  llvm::SmallVector<SmallString<16>, 4>
+      Args; // List of arguments to commands (for InlineCommand).
+  std::vector<std::unique_ptr<CommentInfo>>
+      Children; // List of child comments for this CommentInfo.
+};
+
+struct Reference {
+  Reference() = default;
+  Reference(llvm::StringRef Name) : UnresolvedName(Name) {}
+  Reference(SymbolID USR, InfoType IT) : USR(USR), RefType(IT) {}
+
+  SymbolID USR;                   // Unique identifer for referenced decl
+  SmallString<16> UnresolvedName; // Name of unresolved type.
+  InfoType RefType =
+      InfoType::IT_default; // Indicates the type of this Reference (namespace,
+                            // record, function, enum, default).
+};
+
+// A base struct for TypeInfos
+struct TypeInfo {
+  TypeInfo() = default;
+  TypeInfo(SymbolID &Type, InfoType IT) : Type(Type, IT) {}
+  TypeInfo(llvm::StringRef RefName) : Type(RefName) {}
+
+  Reference Type; // Referenced type in this info.
+};
+
+// Info for field types.
+struct FieldTypeInfo : public TypeInfo {
+  FieldTypeInfo() = default;
+  FieldTypeInfo(SymbolID &Type, InfoType IT, llvm::StringRef Name)
+      : TypeInfo(Type, IT), Name(Name) {}
+  FieldTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)
+      : TypeInfo(RefName), Name(Name) {}
+
+  SmallString<16> Name; // Name associated with this info.
+};
+
+// Info for member types.
+struct MemberTypeInfo : public FieldTypeInfo {
+  MemberTypeInfo() = default;
+  MemberTypeInfo(SymbolID &Type, InfoType IT, llvm::StringRef Name)
+      : FieldTypeInfo(Type, IT, Name) {}
+  MemberTypeInfo(llvm::StringRef RefName, llvm::StringRef Name)
+      : FieldTypeInfo(RefName, Name) {}
+
+  AccessSpecifier Access =
+      clang::AccessSpecifier::AS_none; // Access level associated with this
+                                       // info (public, protected, private,
+                                       // none).
+};
+
+struct Location {
+  Location() = default;
+  Location(int LineNumber, SmallString<16> Filename)
+      : LineNumber(LineNumber), Filename(std::move(Filename)) {}
+
+  int LineNumber;           // Line number of this Location.
+  SmallString<32> Filename; // File for this Location.
+};
+
+/// A base struct for Infos.
+struct Info {
+  Info() = default;
+  Info(Info &&Other) : Description(std::move(Other.Description)) {}
+  virtual ~Info() = default;
+
+  SymbolID USR; // Unique identifier for the decl described by this Info.
+  SmallString<16> Name; // Unqualified name of the decl.
+  llvm::SmallVector<Reference, 4>
+      Namespace; // List of parent namespaces for this decl.
+  std::vector<CommentInfo> Description; // Comment description of this decl.
+};
+
+// Info for namespaces.
+struct NamespaceInfo : public Info {};
+
+// Info for symbols.
+struct SymbolInfo : public Info {
+  llvm::Optional<Location> DefLoc;    // Location where this decl is defined.
+  llvm::SmallVector<Location, 2> Loc; // Locations where this decl is declared.
+};
+
+// TODO: Expand to allow for documenting templating and default args.
+// Info for functions.
+struct FunctionInfo : public SymbolInfo {
+  bool IsMethod = false; // Indicates whether this function is a class method.
+  Reference Parent;      // Reference to the parent class decl for this method.
+  TypeInfo ReturnType;   // Info about the return type of this function.
+  llvm::SmallVector<FieldTypeInfo, 4> Params; // List of parameters.
+  AccessSpecifier Access =
+      AccessSpecifier::AS_none; // Access level for this method (public,
+                                // private, protected, none).
+};
+
+// TODO: Expand to allow for documenting templating, inheritance access,
+// friend classes
+// Info for types.
+struct RecordInfo : public SymbolInfo {
+  TagTypeKind TagType = TagTypeKind::TTK_Struct; // Type of this record (struct,
+                                                 // class, union, interface).
+  llvm::SmallVector<MemberTypeInfo, 4>
+      Members;                             // List of info about record members.
+  llvm::SmallVector<Reference, 4> Parents; // List of base/parent records (does
+                                           // not include virtual parents).
+  llvm::SmallVector<Reference, 4>
+      VirtualParents; // List of virtual base/parent records.
+};
+
+// TODO: Expand to allow for documenting templating.
+// Info for types.
+struct EnumInfo : public SymbolInfo {
+  bool Scoped =
+      false; // Indicates whether this enum is scoped (e.g. enum class).
+  llvm::SmallVector<SmallString<16>, 4> Members; // List of enum members.
+};
+
+// TODO: Add functionality to include separate markdown pages.
+
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_REPRESENTATION_H
diff --git a/clang-doc/Serialize.cpp b/clang-doc/Serialize.cpp
new file mode 100644
index 0000000..ccde579
--- /dev/null
+++ b/clang-doc/Serialize.cpp
@@ -0,0 +1,336 @@
+//===-- Serializer.cpp - ClangDoc Serializer --------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Serialize.h"
+#include "BitcodeWriter.h"
+#include "clang/AST/Comment.h"
+#include "clang/Index/USRGeneration.h"
+#include "llvm/ADT/Hashing.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/SHA1.h"
+
+using clang::comments::FullComment;
+
+namespace clang {
+namespace doc {
+namespace serialize {
+
+SymbolID hashUSR(llvm::StringRef USR) {
+  return llvm::SHA1::hash(arrayRefFromStringRef(USR));
+}
+
+class ClangDocCommentVisitor
+    : public ConstCommentVisitor<ClangDocCommentVisitor> {
+public:
+  ClangDocCommentVisitor(CommentInfo &CI) : CurrentCI(CI) {}
+
+  void parseComment(const comments::Comment *C);
+
+  void visitTextComment(const TextComment *C);
+  void visitInlineCommandComment(const InlineCommandComment *C);
+  void visitHTMLStartTagComment(const HTMLStartTagComment *C);
+  void visitHTMLEndTagComment(const HTMLEndTagComment *C);
+  void visitBlockCommandComment(const BlockCommandComment *C);
+  void visitParamCommandComment(const ParamCommandComment *C);
+  void visitTParamCommandComment(const TParamCommandComment *C);
+  void visitVerbatimBlockComment(const VerbatimBlockComment *C);
+  void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
+  void visitVerbatimLineComment(const VerbatimLineComment *C);
+
+private:
+  std::string getCommandName(unsigned CommandID) const;
+  bool isWhitespaceOnly(StringRef S) const;
+
+  CommentInfo &CurrentCI;
+};
+
+void ClangDocCommentVisitor::parseComment(const comments::Comment *C) {
+  CurrentCI.Kind = C->getCommentKindName();
+  ConstCommentVisitor<ClangDocCommentVisitor>::visit(C);
+  for (comments::Comment *Child :
+       llvm::make_range(C->child_begin(), C->child_end())) {
+    CurrentCI.Children.emplace_back(llvm::make_unique<CommentInfo>());
+    ClangDocCommentVisitor Visitor(*CurrentCI.Children.back());
+    Visitor.parseComment(Child);
+  }
+}
+
+void ClangDocCommentVisitor::visitTextComment(const TextComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI.Text = C->getText();
+}
+
+void ClangDocCommentVisitor::visitInlineCommandComment(
+    const InlineCommandComment *C) {
+  CurrentCI.Name = getCommandName(C->getCommandID());
+  for (unsigned I = 0, E = C->getNumArgs(); I != E; ++I)
+    CurrentCI.Args.push_back(C->getArgText(I));
+}
+
+void ClangDocCommentVisitor::visitHTMLStartTagComment(
+    const HTMLStartTagComment *C) {
+  CurrentCI.Name = C->getTagName();
+  CurrentCI.SelfClosing = C->isSelfClosing();
+  for (unsigned I = 0, E = C->getNumAttrs(); I < E; ++I) {
+    const HTMLStartTagComment::Attribute &Attr = C->getAttr(I);
+    CurrentCI.AttrKeys.push_back(Attr.Name);
+    CurrentCI.AttrValues.push_back(Attr.Value);
+  }
+}
+
+void ClangDocCommentVisitor::visitHTMLEndTagComment(
+    const HTMLEndTagComment *C) {
+  CurrentCI.Name = C->getTagName();
+  CurrentCI.SelfClosing = true;
+}
+
+void ClangDocCommentVisitor::visitBlockCommandComment(
+    const BlockCommandComment *C) {
+  CurrentCI.Name = getCommandName(C->getCommandID());
+  for (unsigned I = 0, E = C->getNumArgs(); I < E; ++I)
+    CurrentCI.Args.push_back(C->getArgText(I));
+}
+
+void ClangDocCommentVisitor::visitParamCommandComment(
+    const ParamCommandComment *C) {
+  CurrentCI.Direction =
+      ParamCommandComment::getDirectionAsString(C->getDirection());
+  CurrentCI.Explicit = C->isDirectionExplicit();
+  if (C->hasParamName())
+    CurrentCI.ParamName = C->getParamNameAsWritten();
+}
+
+void ClangDocCommentVisitor::visitTParamCommandComment(
+    const TParamCommandComment *C) {
+  if (C->hasParamName())
+    CurrentCI.ParamName = C->getParamNameAsWritten();
+}
+
+void ClangDocCommentVisitor::visitVerbatimBlockComment(
+    const VerbatimBlockComment *C) {
+  CurrentCI.Name = getCommandName(C->getCommandID());
+  CurrentCI.CloseName = C->getCloseName();
+}
+
+void ClangDocCommentVisitor::visitVerbatimBlockLineComment(
+    const VerbatimBlockLineComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI.Text = C->getText();
+}
+
+void ClangDocCommentVisitor::visitVerbatimLineComment(
+    const VerbatimLineComment *C) {
+  if (!isWhitespaceOnly(C->getText()))
+    CurrentCI.Text = C->getText();
+}
+
+bool ClangDocCommentVisitor::isWhitespaceOnly(llvm::StringRef S) const {
+  return std::all_of(S.begin(), S.end(), isspace);
+}
+
+std::string ClangDocCommentVisitor::getCommandName(unsigned CommandID) const {
+  const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID);
+  if (Info)
+    return Info->Name;
+  // TODO: Add parsing for \file command.
+  return "<not a builtin command>";
+}
+
+// Serializing functions.
+
+template <typename T> static std::string serialize(T &I) {
+  SmallString<2048> Buffer;
+  llvm::BitstreamWriter Stream(Buffer);
+  ClangDocBitcodeWriter Writer(Stream);
+  Writer.emitBlock(I);
+  return Buffer.str().str();
+}
+
+static void parseFullComment(const FullComment *C, CommentInfo &CI) {
+  ClangDocCommentVisitor Visitor(CI);
+  Visitor.parseComment(C);
+}
+
+static SymbolID getUSRForDecl(const Decl *D) {
+  llvm::SmallString<128> USR;
+  if (index::generateUSRForDecl(D, USR))
+    return SymbolID();
+  return hashUSR(USR);
+}
+
+static RecordDecl *getDeclForType(const QualType &T) {
+  auto *Ty = T->getAs<RecordType>();
+  if (!Ty)
+    return nullptr;
+  return Ty->getDecl()->getDefinition();
+}
+
+static void parseFields(RecordInfo &I, const RecordDecl *D) {
+  for (const FieldDecl *F : D->fields()) {
+    // FIXME: Set Access to the appropriate value.
+    SymbolID Type;
+    std::string Name;
+    InfoType RefType;
+    if (const auto *T = getDeclForType(F->getTypeSourceInfo()->getType())) {
+      Type = getUSRForDecl(T);
+      if (dyn_cast<EnumDecl>(T))
+        RefType = InfoType::IT_enum;
+      else if (dyn_cast<RecordDecl>(T))
+        RefType = InfoType::IT_record;
+      I.Members.emplace_back(Type, RefType, F->getQualifiedNameAsString());
+    } else {
+      Name = F->getTypeSourceInfo()->getType().getAsString();
+      I.Members.emplace_back(Name, F->getQualifiedNameAsString());
+    }
+  }
+}
+
+static void parseEnumerators(EnumInfo &I, const EnumDecl *D) {
+  for (const EnumConstantDecl *E : D->enumerators())
+    I.Members.emplace_back(E->getNameAsString());
+}
+
+static void parseParameters(FunctionInfo &I, const FunctionDecl *D) {
+  for (const ParmVarDecl *P : D->parameters()) {
+    SymbolID Type;
+    std::string Name;
+    InfoType RefType;
+    if (const auto *T = getDeclForType(P->getOriginalType())) {
+      Type = getUSRForDecl(T);
+      if (dyn_cast<EnumDecl>(T))
+        RefType = InfoType::IT_enum;
+      else if (dyn_cast<RecordDecl>(T))
+        RefType = InfoType::IT_record;
+      I.Params.emplace_back(Type, RefType, P->getQualifiedNameAsString());
+    } else {
+      Name = P->getOriginalType().getAsString();
+      I.Params.emplace_back(Name, P->getQualifiedNameAsString());
+    }
+  }
+}
+
+static void parseBases(RecordInfo &I, const CXXRecordDecl *D) {
+  for (const CXXBaseSpecifier &B : D->bases()) {
+    if (B.isVirtual())
+      continue;
+    if (const auto *P = getDeclForType(B.getType()))
+      I.Parents.emplace_back(getUSRForDecl(P), InfoType::IT_record);
+    else
+      I.Parents.emplace_back(B.getType().getAsString());
+  }
+  for (const CXXBaseSpecifier &B : D->vbases()) {
+    if (const auto *P = getDeclForType(B.getType()))
+      I.VirtualParents.emplace_back(getUSRForDecl(P), InfoType::IT_record);
+    else
+      I.VirtualParents.emplace_back(B.getType().getAsString());
+  }
+}
+
+template <typename T>
+static void
+populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
+                         const T *D) {
+  const auto *DC = dyn_cast<DeclContext>(D);
+  while ((DC = DC->getParent())) {
+    if (const auto *N = dyn_cast<NamespaceDecl>(DC))
+      Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_namespace);
+    else if (const auto *N = dyn_cast<RecordDecl>(DC))
+      Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_record);
+    else if (const auto *N = dyn_cast<FunctionDecl>(DC))
+      Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_function);
+    else if (const auto *N = dyn_cast<EnumDecl>(DC))
+      Namespaces.emplace_back(getUSRForDecl(N), InfoType::IT_enum);
+  }
+}
+
+template <typename T>
+static void populateInfo(Info &I, const T *D, const FullComment *C) {
+  I.USR = getUSRForDecl(D);
+  I.Name = D->getNameAsString();
+  populateParentNamespaces(I.Namespace, D);
+  if (C) {
+    I.Description.emplace_back();
+    parseFullComment(C, I.Description.back());
+  }
+}
+
+template <typename T>
+static void populateSymbolInfo(SymbolInfo &I, const T *D, const FullComment *C,
+                               int LineNumber, StringRef Filename) {
+  populateInfo(I, D, C);
+  if (D->isThisDeclarationADefinition())
+    I.DefLoc.emplace(LineNumber, Filename);
+  else
+    I.Loc.emplace_back(LineNumber, Filename);
+}
+
+static void populateFunctionInfo(FunctionInfo &I, const FunctionDecl *D,
+                                 const FullComment *FC, int LineNumber,
+                                 StringRef Filename) {
+  populateSymbolInfo(I, D, FC, LineNumber, Filename);
+  if (const auto *T = getDeclForType(D->getReturnType())) {
+    I.ReturnType.Type.USR = getUSRForDecl(T);
+    if (dyn_cast<EnumDecl>(T))
+      I.ReturnType.Type.RefType = InfoType::IT_enum;
+    else if (dyn_cast<RecordDecl>(T))
+      I.ReturnType.Type.RefType = InfoType::IT_record;
+  } else {
+    I.ReturnType.Type.UnresolvedName = D->getReturnType().getAsString();
+  }
+  parseParameters(I, D);
+}
+
+std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
+                     int LineNumber, llvm::StringRef File) {
+  NamespaceInfo I;
+  populateInfo(I, D, FC);
+  return serialize(I);
+}
+
+std::string emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
+                     llvm::StringRef File) {
+  RecordInfo I;
+  populateSymbolInfo(I, D, FC, LineNumber, File);
+  I.TagType = D->getTagKind();
+  parseFields(I, D);
+  if (const auto *C = dyn_cast<CXXRecordDecl>(D))
+    parseBases(I, C);
+  return serialize(I);
+}
+
+std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
+                     int LineNumber, llvm::StringRef File) {
+  FunctionInfo I;
+  populateFunctionInfo(I, D, FC, LineNumber, File);
+  I.Access = clang::AccessSpecifier::AS_none;
+  return serialize(I);
+}
+
+std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
+                     int LineNumber, llvm::StringRef File) {
+  FunctionInfo I;
+  populateFunctionInfo(I, D, FC, LineNumber, File);
+  I.IsMethod = true;
+  I.Parent = Reference(getUSRForDecl(D->getParent()), InfoType::IT_record);
+  I.Access = D->getAccess();
+  return serialize(I);
+}
+
+std::string emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
+                     llvm::StringRef File) {
+  EnumInfo I;
+  populateSymbolInfo(I, D, FC, LineNumber, File);
+  I.Scoped = D->isScoped();
+  parseEnumerators(I, D);
+  return serialize(I);
+}
+
+} // namespace serialize
+} // namespace doc
+} // namespace clang
diff --git a/clang-doc/Serialize.h b/clang-doc/Serialize.h
new file mode 100644
index 0000000..5f13798
--- /dev/null
+++ b/clang-doc/Serialize.h
@@ -0,0 +1,53 @@
+//===-- Serializer.h - ClangDoc Serializer ----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the serializing functions fro the clang-doc tool. Given
+// a particular declaration, it collects the appropriate information and returns
+// a serialized bitcode string for the declaration.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_SERIALIZE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_SERIALIZE_H
+
+#include "Representation.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/CommentVisitor.h"
+#include <string>
+#include <vector>
+
+using namespace clang::comments;
+
+namespace clang {
+namespace doc {
+namespace serialize {
+
+std::string emitInfo(const NamespaceDecl *D, const FullComment *FC,
+                     int LineNumber, StringRef File);
+std::string emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
+                     StringRef File);
+std::string emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
+                     StringRef File);
+std::string emitInfo(const FunctionDecl *D, const FullComment *FC,
+                     int LineNumber, StringRef File);
+std::string emitInfo(const CXXMethodDecl *D, const FullComment *FC,
+                     int LineNumber, StringRef File);
+
+// Function to hash a given USR value for storage.
+// As USRs (Unified Symbol Resolution) could be large, especially for functions
+// with long type arguments, we use 160-bits SHA1(USR) values to
+// guarantee the uniqueness of symbols while using a relatively small amount of
+// memory (vs storing USRs directly).
+SymbolID hashUSR(llvm::StringRef USR);
+
+} // namespace serialize
+} // namespace doc
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_DOC_SERIALIZE_H
diff --git a/clang-doc/tool/CMakeLists.txt b/clang-doc/tool/CMakeLists.txt
new file mode 100644
index 0000000..d7f28cf
--- /dev/null
+++ b/clang-doc/tool/CMakeLists.txt
@@ -0,0 +1,17 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+add_clang_executable(clang-doc
+  ClangDocMain.cpp
+  )
+
+target_link_libraries(clang-doc
+  PRIVATE
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangFrontend
+  clangDoc
+  clangTooling
+  clangToolingCore
+  )
+  
\ No newline at end of file
diff --git a/clang-doc/tool/ClangDocMain.cpp b/clang-doc/tool/ClangDocMain.cpp
new file mode 100644
index 0000000..51c3aa9
--- /dev/null
+++ b/clang-doc/tool/ClangDocMain.cpp
@@ -0,0 +1,114 @@
+//===-- ClangDocMain.cpp - ClangDoc -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This tool for generating C and C++ documenation from source code
+// and comments. Generally, it runs a LibTooling FrontendAction on source files,
+// mapping each declaration in those files to its USR and serializing relevant
+// information into LLVM bitcode. It then runs a pass over the collected
+// declaration information, reducing by USR. There is an option to dump this
+// intermediate result to bitcode. Finally, it hands the reduced information
+// off to a generator, which does the final parsing from the intermediate
+// representation to the desired output format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ClangDoc.h"
+#include "clang/AST/AST.h"
+#include "clang/AST/Decl.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchersInternal.h"
+#include "clang/Driver/Options.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Execution.h"
+#include "clang/Tooling/StandaloneExecution.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/raw_ostream.h"
+#include <string>
+
+using namespace clang::ast_matchers;
+using namespace clang::tooling;
+using namespace clang;
+
+static llvm::cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);
+static llvm::cl::OptionCategory ClangDocCategory("clang-doc options");
+
+static llvm::cl::opt<std::string>
+    OutDirectory("output",
+                 llvm::cl::desc("Directory for outputting generated files."),
+                 llvm::cl::init("docs"), llvm::cl::cat(ClangDocCategory));
+
+static llvm::cl::opt<bool>
+    DumpMapperResult("dump-mapper",
+                     llvm::cl::desc("Dump mapper results to bitcode file."),
+                     llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
+
+static llvm::cl::opt<bool> DoxygenOnly(
+    "doxygen",
+    llvm::cl::desc("Use only doxygen-style comments to generate docs."),
+    llvm::cl::init(false), llvm::cl::cat(ClangDocCategory));
+
+int main(int argc, const char **argv) {
+  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+  std::error_code OK;
+
+  auto Exec = clang::tooling::createExecutorFromCommandLineArgs(
+      argc, argv, ClangDocCategory);
+
+  if (!Exec) {
+    llvm::errs() << toString(Exec.takeError()) << "\n";
+    return 1;
+  }
+
+  ArgumentsAdjuster ArgAdjuster;
+  if (!DoxygenOnly)
+    ArgAdjuster = combineAdjusters(
+        getInsertArgumentAdjuster("-fparse-all-comments",
+                                  tooling::ArgumentInsertPosition::END),
+        ArgAdjuster);
+
+  // Mapping phase
+  llvm::outs() << "Mapping decls...\n";
+  auto Err = Exec->get()->execute(doc::newMapperActionFactory(
+                                      Exec->get()->getExecutionContext()),
+                                  ArgAdjuster);
+  if (Err)
+    llvm::errs() << toString(std::move(Err)) << "\n";
+
+  if (DumpMapperResult) {
+    Exec->get()->getToolResults()->forEachResult([&](StringRef Key,
+                                                     StringRef Value) {
+      SmallString<128> IRRootPath;
+      llvm::sys::path::native(OutDirectory, IRRootPath);
+      llvm::sys::path::append(IRRootPath, "bc");
+      std::error_code DirectoryStatus =
+          llvm::sys::fs::create_directories(IRRootPath);
+      if (DirectoryStatus != OK) {
+        llvm::errs() << "Unable to create documentation directories.\n";
+        return;
+      }
+      llvm::sys::path::append(IRRootPath, Key + ".bc");
+      std::error_code OutErrorInfo;
+      llvm::raw_fd_ostream OS(IRRootPath, OutErrorInfo, llvm::sys::fs::F_None);
+      if (OutErrorInfo != OK) {
+        llvm::errs() << "Error opening documentation file.\n";
+        return;
+      }
+      OS << Value;
+      OS.close();
+    });
+  }
+
+  return 0;
+}
diff --git a/clang-tidy/CMakeLists.txt b/clang-tidy/CMakeLists.txt
index a307ec0..6738c31 100644
--- a/clang-tidy/CMakeLists.txt
+++ b/clang-tidy/CMakeLists.txt
@@ -27,6 +27,7 @@
   )
 
 add_subdirectory(android)
+add_subdirectory(abseil)
 add_subdirectory(boost)
 add_subdirectory(bugprone)
 add_subdirectory(cert)
@@ -41,6 +42,8 @@
 add_subdirectory(objc)
 add_subdirectory(performance)
 add_subdirectory(plugin)
+add_subdirectory(portability)
 add_subdirectory(readability)
 add_subdirectory(tool)
 add_subdirectory(utils)
+add_subdirectory(zircon)
diff --git a/clang-tidy/abseil/AbseilTidyModule.cpp b/clang-tidy/abseil/AbseilTidyModule.cpp
new file mode 100644
index 0000000..8e427f0
--- /dev/null
+++ b/clang-tidy/abseil/AbseilTidyModule.cpp
@@ -0,0 +1,38 @@
+//===------- AbseilTidyModule.cpp - clang-tidy ----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "StringFindStartswithCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace abseil {
+
+class AbseilModule : public ClangTidyModule {
+public:
+  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    CheckFactories.registerCheck<StringFindStartswithCheck>(
+        "abseil-string-find-startswith");
+  }
+};
+
+// Register the AbseilModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<AbseilModule> X("abseil-module",
+                                                    "Add Abseil checks.");
+
+} // namespace abseil
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the AbseilModule.
+volatile int AbseilModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tidy/abseil/CMakeLists.txt b/clang-tidy/abseil/CMakeLists.txt
new file mode 100644
index 0000000..dd59dcf
--- /dev/null
+++ b/clang-tidy/abseil/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyAbseilModule
+  AbseilTidyModule.cpp
+  StringFindStartswithCheck.cpp
+
+  LINK_LIBS
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangLex
+  clangTidy
+  clangTidyUtils
+  )
diff --git a/clang-tidy/abseil/StringFindStartswithCheck.cpp b/clang-tidy/abseil/StringFindStartswithCheck.cpp
new file mode 100644
index 0000000..44df264
--- /dev/null
+++ b/clang-tidy/abseil/StringFindStartswithCheck.cpp
@@ -0,0 +1,133 @@
+//===--- StringFindStartswithCheck.cc - clang-tidy---------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StringFindStartswithCheck.h"
+
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+#include <cassert>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace abseil {
+
+StringFindStartswithCheck::StringFindStartswithCheck(StringRef Name,
+                                                     ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      StringLikeClasses(utils::options::parseStringList(
+          Options.get("StringLikeClasses", "::std::basic_string"))),
+      IncludeStyle(utils::IncludeSorter::parseIncludeStyle(
+          Options.getLocalOrGlobal("IncludeStyle", "llvm"))),
+      AbseilStringsMatchHeader(
+          Options.get("AbseilStringsMatchHeader", "absl/strings/match.h")) {}
+
+void StringFindStartswithCheck::registerMatchers(MatchFinder *Finder) {
+  auto ZeroLiteral = integerLiteral(equals(0));
+  auto StringClassMatcher = cxxRecordDecl(hasAnyName(SmallVector<StringRef, 4>(
+      StringLikeClasses.begin(), StringLikeClasses.end())));
+
+  auto StringFind = cxxMemberCallExpr(
+      // .find()-call on a string...
+      callee(cxxMethodDecl(hasName("find"), ofClass(StringClassMatcher))),
+      // ... with some search expression ...
+      hasArgument(0, expr().bind("needle")),
+      // ... and either "0" as second argument or the default argument (also 0).
+      anyOf(hasArgument(1, ZeroLiteral), hasArgument(1, cxxDefaultArgExpr())));
+
+  Finder->addMatcher(
+      // Match [=!]= with a zero on one side and a string.find on the other.
+      binaryOperator(
+          anyOf(hasOperatorName("=="), hasOperatorName("!=")),
+          hasEitherOperand(ignoringParenImpCasts(ZeroLiteral)),
+          hasEitherOperand(ignoringParenImpCasts(StringFind.bind("findexpr"))))
+          .bind("expr"),
+      this);
+}
+
+void StringFindStartswithCheck::check(const MatchFinder::MatchResult &Result) {
+  const ASTContext &Context = *Result.Context;
+  const SourceManager &Source = Context.getSourceManager();
+
+  // Extract matching (sub)expressions
+  const auto *ComparisonExpr = Result.Nodes.getNodeAs<BinaryOperator>("expr");
+  assert(ComparisonExpr != nullptr);
+  const auto *Needle = Result.Nodes.getNodeAs<Expr>("needle");
+  assert(Needle != nullptr);
+  const Expr *Haystack = Result.Nodes.getNodeAs<CXXMemberCallExpr>("findexpr")
+                             ->getImplicitObjectArgument();
+  assert(Haystack != nullptr);
+
+  if (ComparisonExpr->getLocStart().isMacroID())
+    return;
+
+  // Get the source code blocks (as characters) for both the string object
+  // and the search expression
+  const StringRef NeedleExprCode = Lexer::getSourceText(
+      CharSourceRange::getTokenRange(Needle->getSourceRange()), Source,
+      Context.getLangOpts());
+  const StringRef HaystackExprCode = Lexer::getSourceText(
+      CharSourceRange::getTokenRange(Haystack->getSourceRange()), Source,
+      Context.getLangOpts());
+
+  // Create the StartsWith string, negating if comparison was "!=".
+  bool Neg = ComparisonExpr->getOpcodeStr() == "!=";
+  StringRef StartswithStr;
+  if (Neg) {
+    StartswithStr = "!absl::StartsWith";
+  } else {
+    StartswithStr = "absl::StartsWith";
+  }
+
+  // Create the warning message and a FixIt hint replacing the original expr.
+  auto Diagnostic =
+      diag(ComparisonExpr->getLocStart(),
+           (StringRef("use ") + StartswithStr + " instead of find() " +
+            ComparisonExpr->getOpcodeStr() + " 0")
+               .str());
+
+  Diagnostic << FixItHint::CreateReplacement(
+      ComparisonExpr->getSourceRange(),
+      (StartswithStr + "(" + HaystackExprCode + ", " + NeedleExprCode + ")")
+          .str());
+
+  // Create a preprocessor #include FixIt hint (CreateIncludeInsertion checks
+  // whether this already exists).
+  auto IncludeHint = IncludeInserter->CreateIncludeInsertion(
+      Source.getFileID(ComparisonExpr->getLocStart()), AbseilStringsMatchHeader,
+      false);
+  if (IncludeHint) {
+    Diagnostic << *IncludeHint;
+  }
+}
+
+void StringFindStartswithCheck::registerPPCallbacks(
+    CompilerInstance &Compiler) {
+  IncludeInserter = llvm::make_unique<clang::tidy::utils::IncludeInserter>(
+      Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle);
+  Compiler.getPreprocessor().addPPCallbacks(
+      IncludeInserter->CreatePPCallbacks());
+}
+
+void StringFindStartswithCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "StringLikeClasses",
+                utils::options::serializeStringList(StringLikeClasses));
+  Options.store(Opts, "IncludeStyle",
+                utils::IncludeSorter::toString(IncludeStyle));
+  Options.store(Opts, "AbseilStringsMatchHeader", AbseilStringsMatchHeader);
+}
+
+} // namespace abseil
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tidy/abseil/StringFindStartswithCheck.h b/clang-tidy/abseil/StringFindStartswithCheck.h
new file mode 100644
index 0000000..1c04e80
--- /dev/null
+++ b/clang-tidy/abseil/StringFindStartswithCheck.h
@@ -0,0 +1,48 @@
+//===--- StringFindStartswithCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+//                     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_EXTRA_CLANG_TIDY_ABSEIL_STRINGFINDSTARTSWITHCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_STRINGFINDSTARTSWITHCHECK_H
+
+#include "../ClangTidy.h"
+#include "../utils/IncludeInserter.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace tidy {
+namespace abseil {
+
+// Find string.find(...) == 0 comparisons and suggest replacing with StartsWith.
+// FIXME(niko): Add similar check for EndsWith
+// FIXME(niko): Add equivalent modernize checks for C++20's std::starts_With
+class StringFindStartswithCheck : public ClangTidyCheck {
+public:
+  using ClangTidyCheck::ClangTidyCheck;
+  StringFindStartswithCheck(StringRef Name, ClangTidyContext *Context);
+  void registerPPCallbacks(CompilerInstance &Compiler) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+
+private:
+  std::unique_ptr<clang::tidy::utils::IncludeInserter> IncludeInserter;
+  const std::vector<std::string> StringLikeClasses;
+  const utils::IncludeSorter::IncludeStyle IncludeStyle;
+  const std::string AbseilStringsMatchHeader;
+};
+
+} // namespace abseil
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ABSEIL_STRINGFINDSTARTSWITHCHECK_H
diff --git a/clang-tidy/add_new_check.py b/clang-tidy/add_new_check.py
index ab0c883..2f1a301 100755
--- a/clang-tidy/add_new_check.py
+++ b/clang-tidy/add_new_check.py
@@ -9,12 +9,13 @@
 #
 #===------------------------------------------------------------------------===#
 
+from __future__ import print_function
+
 import argparse
 import os
 import re
 import sys
 
-
 # Adapts the module's CMakelist file. Returns 'True' if it could add a new entry
 # and 'False' if the entry already existed.
 def adapt_cmake(module_path, check_name_camel):
@@ -30,7 +31,7 @@
       return False
 
   print('Updating %s...' % filename)
-  with open(filename, 'wb') as f:
+  with open(filename, 'w') as f:
     cpp_found = False
     file_added = False
     for line in lines:
@@ -50,7 +51,7 @@
   check_name_dashes = module + '-' + check_name
   filename = os.path.join(module_path, check_name_camel) + '.h'
   print('Creating %s...' % filename)
-  with open(filename, 'wb') as f:
+  with open(filename, 'w') as f:
     header_guard = ('LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_' + module.upper() + '_'
                     + check_name_camel.upper() + '_H')
     f.write('//===--- ')
@@ -103,7 +104,7 @@
 def write_implementation(module_path, module, check_name_camel):
   filename = os.path.join(module_path, check_name_camel) + '.cpp'
   print('Creating %s...' % filename)
-  with open(filename, 'wb') as f:
+  with open(filename, 'w') as f:
     f.write('//===--- ')
     f.write(os.path.basename(filename))
     f.write(' - clang-tidy')
@@ -152,14 +153,15 @@
 
 # Modifies the module to include the new check.
 def adapt_module(module_path, module, check_name, check_name_camel):
-  modulecpp = filter(lambda p: p.lower() == module.lower() + 'tidymodule.cpp',
-                     os.listdir(module_path))[0]
+  modulecpp = list(filter(
+      lambda p: p.lower() == module.lower() + 'tidymodule.cpp',
+      os.listdir(module_path)))[0]
   filename = os.path.join(module_path, modulecpp)
   with open(filename, 'r') as f:
     lines = f.readlines()
 
   print('Updating %s...' % filename)
-  with open(filename, 'wb') as f:
+  with open(filename, 'w') as f:
     header_added = False
     header_found = False
     check_added = False
@@ -199,7 +201,7 @@
     lines = f.readlines()
 
   print('Updating %s...' % filename)
-  with open(filename, 'wb') as f:
+  with open(filename, 'w') as f:
     note_added = False
     header_found = False
 
@@ -211,8 +213,8 @@
         elif header_found:
           if not line.startswith('----'):
             f.write("""
-- New `%s
-  <http://clang.llvm.org/extra/clang-tidy/checks/%s.html>`_ check
+- New :doc:`%s
+  <clang-tidy/checks/%s>` check
 
   FIXME: add release notes.
 """ % (check_name_dashes, check_name_dashes))
@@ -227,7 +229,7 @@
   filename = os.path.normpath(os.path.join(module_path, '../../test/clang-tidy',
                                            check_name_dashes + '.' + test_extension))
   print('Creating %s...' % filename)
-  with open(filename, 'wb') as f:
+  with open(filename, 'w') as f:
     f.write("""// RUN: %%check_clang_tidy %%s %(check_name_dashes)s %%t
 
 // FIXME: Add something that triggers the check here.
@@ -251,8 +253,8 @@
   filename = os.path.normpath(os.path.join(docs_dir, 'list.rst'))
   with open(filename, 'r') as f:
     lines = f.readlines()
-  doc_files = filter(lambda s: s.endswith('.rst') and s != 'list.rst',
-                     os.listdir(docs_dir))
+  doc_files = list(filter(lambda s: s.endswith('.rst') and s != 'list.rst',
+                     os.listdir(docs_dir)))
   doc_files.sort()
 
   def format_link(doc_file):
@@ -275,7 +277,7 @@
   checks = map(format_link, doc_files)
 
   print('Updating %s...' % filename)
-  with open(filename, 'wb') as f:
+  with open(filename, 'w') as f:
     for line in lines:
       f.write(line)
       if line.startswith('.. toctree::'):
@@ -289,7 +291,7 @@
   filename = os.path.normpath(os.path.join(
       module_path, '../../docs/clang-tidy/checks/', check_name_dashes + '.rst'))
   print('Creating %s...' % filename)
-  with open(filename, 'wb') as f:
+  with open(filename, 'w') as f:
     f.write(""".. title:: clang-tidy - %(check_name_dashes)s
 
 %(check_name_dashes)s
@@ -333,7 +335,7 @@
     return
 
   if not args.module or not args.check:
-    print 'Module and check must be specified.'
+    print('Module and check must be specified.')
     parser.print_usage()
     return
 
@@ -341,8 +343,8 @@
   check_name = args.check
 
   if check_name.startswith(module):
-    print 'Check name "%s" must not start with the module "%s". Exiting.' % (
-        check_name, module)
+    print('Check name "%s" must not start with the module "%s". Exiting.' % (
+        check_name, module))
     return
   check_name_camel = ''.join(map(lambda elem: elem.capitalize(),
                                  check_name.split('-'))) + 'Check'
diff --git a/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tidy/bugprone/BugproneTidyModule.cpp
index ff35641..14f07dc 100644
--- a/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -22,11 +22,14 @@
 #include "IncorrectRoundingsCheck.h"
 #include "IntegerDivisionCheck.h"
 #include "LambdaFunctionNameCheck.h"
+#include "MacroParenthesesCheck.h"
 #include "MacroRepeatedSideEffectsCheck.h"
 #include "MisplacedOperatorInStrlenInAllocCheck.h"
 #include "MisplacedWideningCastCheck.h"
 #include "MoveForwardingReferenceCheck.h"
 #include "MultipleStatementMacroCheck.h"
+#include "SizeofContainerCheck.h"
+#include "SizeofExpressionCheck.h"
 #include "StringConstructorCheck.h"
 #include "StringIntegerAssignmentCheck.h"
 #include "StringLiteralWithEmbeddedNulCheck.h"
@@ -39,6 +42,8 @@
 #include "ThrowKeywordMissingCheck.h"
 #include "UndefinedMemoryManipulationCheck.h"
 #include "UndelegatedConstructorCheck.h"
+#include "UnusedRaiiCheck.h"
+#include "UnusedReturnValueCheck.h"
 #include "UseAfterMoveCheck.h"
 #include "VirtualNearMissCheck.h"
 
@@ -73,6 +78,8 @@
         "bugprone-integer-division");
     CheckFactories.registerCheck<LambdaFunctionNameCheck>(
         "bugprone-lambda-function-name");
+    CheckFactories.registerCheck<MacroParenthesesCheck>(
+        "bugprone-macro-parentheses");
     CheckFactories.registerCheck<MacroRepeatedSideEffectsCheck>(
         "bugprone-macro-repeated-side-effects");
     CheckFactories.registerCheck<MisplacedOperatorInStrlenInAllocCheck>(
@@ -83,6 +90,10 @@
         "bugprone-move-forwarding-reference");
     CheckFactories.registerCheck<MultipleStatementMacroCheck>(
         "bugprone-multiple-statement-macro");
+    CheckFactories.registerCheck<SizeofContainerCheck>(
+        "bugprone-sizeof-container");
+    CheckFactories.registerCheck<SizeofExpressionCheck>(
+        "bugprone-sizeof-expression");
     CheckFactories.registerCheck<StringConstructorCheck>(
         "bugprone-string-constructor");
     CheckFactories.registerCheck<StringIntegerAssignmentCheck>(
@@ -107,6 +118,10 @@
         "bugprone-undefined-memory-manipulation");
     CheckFactories.registerCheck<UndelegatedConstructorCheck>(
         "bugprone-undelegated-constructor");
+    CheckFactories.registerCheck<UnusedRaiiCheck>(
+        "bugprone-unused-raii");
+    CheckFactories.registerCheck<UnusedReturnValueCheck>(
+        "bugprone-unused-return-value");
     CheckFactories.registerCheck<UseAfterMoveCheck>(
         "bugprone-use-after-move");
     CheckFactories.registerCheck<VirtualNearMissCheck>(
diff --git a/clang-tidy/bugprone/CMakeLists.txt b/clang-tidy/bugprone/CMakeLists.txt
index a34d3fd..4624f60 100644
--- a/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tidy/bugprone/CMakeLists.txt
@@ -14,11 +14,14 @@
   IncorrectRoundingsCheck.cpp
   IntegerDivisionCheck.cpp
   LambdaFunctionNameCheck.cpp
+  MacroParenthesesCheck.cpp
   MacroRepeatedSideEffectsCheck.cpp
   MisplacedOperatorInStrlenInAllocCheck.cpp
   MisplacedWideningCastCheck.cpp
   MoveForwardingReferenceCheck.cpp
   MultipleStatementMacroCheck.cpp
+  SizeofContainerCheck.cpp
+  SizeofExpressionCheck.cpp
   StringConstructorCheck.cpp
   StringIntegerAssignmentCheck.cpp
   StringLiteralWithEmbeddedNulCheck.cpp
@@ -31,6 +34,8 @@
   ThrowKeywordMissingCheck.cpp
   UndefinedMemoryManipulationCheck.cpp
   UndelegatedConstructorCheck.cpp
+  UnusedRaiiCheck.cpp
+  UnusedReturnValueCheck.cpp
   UseAfterMoveCheck.cpp
   VirtualNearMissCheck.cpp
 
diff --git a/clang-tidy/bugprone/IncorrectRoundingsCheck.h b/clang-tidy/bugprone/IncorrectRoundingsCheck.h
index 9a88e21..b1886fd 100644
--- a/clang-tidy/bugprone/IncorrectRoundingsCheck.h
+++ b/clang-tidy/bugprone/IncorrectRoundingsCheck.h
@@ -1,4 +1,4 @@
-//===--- IncorrectRoundingsCheckCheck.h - clang-tidy -----------------*- C++ -*-===//
+//===--- IncorrectRoundingsCheck.h - clang-tidy -----------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
diff --git a/clang-tidy/misc/MacroParenthesesCheck.cpp b/clang-tidy/bugprone/MacroParenthesesCheck.cpp
similarity index 99%
rename from clang-tidy/misc/MacroParenthesesCheck.cpp
rename to clang-tidy/bugprone/MacroParenthesesCheck.cpp
index 59fe772..6846bc2 100644
--- a/clang-tidy/misc/MacroParenthesesCheck.cpp
+++ b/clang-tidy/bugprone/MacroParenthesesCheck.cpp
@@ -14,7 +14,7 @@
 
 namespace clang {
 namespace tidy {
-namespace misc {
+namespace bugprone {
 
 namespace {
 class MacroParenthesesPPCallbacks : public PPCallbacks {
@@ -255,6 +255,6 @@
           &Compiler.getPreprocessor(), this));
 }
 
-} // namespace misc
+} // namespace bugprone
 } // namespace tidy
 } // namespace clang
diff --git a/clang-tidy/misc/MacroParenthesesCheck.h b/clang-tidy/bugprone/MacroParenthesesCheck.h
similarity index 82%
rename from clang-tidy/misc/MacroParenthesesCheck.h
rename to clang-tidy/bugprone/MacroParenthesesCheck.h
index e398fc6..383a6cc 100644
--- a/clang-tidy/misc/MacroParenthesesCheck.h
+++ b/clang-tidy/bugprone/MacroParenthesesCheck.h
@@ -7,14 +7,14 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MACRO_PARENTHESES_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MACRO_PARENTHESES_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MACROPARENTHESESCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MACROPARENTHESESCHECK_H
 
 #include "../ClangTidy.h"
 
 namespace clang {
 namespace tidy {
-namespace misc {
+namespace bugprone {
 
 /// Finds macros that can have unexpected behaviour due to missing parentheses.
 ///
@@ -36,8 +36,8 @@
   void registerPPCallbacks(CompilerInstance &Compiler) override;
 };
 
-} // namespace misc
+} // namespace bugprone
 } // namespace tidy
 } // namespace clang
 
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MACRO_PARENTHESES_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_MACROPARENTHESESCHECK_H
diff --git a/clang-tidy/misc/SizeofContainerCheck.cpp b/clang-tidy/bugprone/SizeofContainerCheck.cpp
similarity index 97%
rename from clang-tidy/misc/SizeofContainerCheck.cpp
rename to clang-tidy/bugprone/SizeofContainerCheck.cpp
index de4e8ad..b4a019e 100644
--- a/clang-tidy/misc/SizeofContainerCheck.cpp
+++ b/clang-tidy/bugprone/SizeofContainerCheck.cpp
@@ -15,7 +15,7 @@
 
 namespace clang {
 namespace tidy {
-namespace misc {
+namespace bugprone {
 
 void SizeofContainerCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
@@ -44,6 +44,6 @@
                                   "container; did you mean .size()?");
 }
 
-} // namespace misc
+} // namespace bugprone
 } // namespace tidy
 } // namespace clang
diff --git a/clang-tidy/misc/SizeofContainerCheck.h b/clang-tidy/bugprone/SizeofContainerCheck.h
similarity index 72%
rename from clang-tidy/misc/SizeofContainerCheck.h
rename to clang-tidy/bugprone/SizeofContainerCheck.h
index ed13ca5..76b82b0 100644
--- a/clang-tidy/misc/SizeofContainerCheck.h
+++ b/clang-tidy/bugprone/SizeofContainerCheck.h
@@ -7,20 +7,20 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SIZEOF_CONTAINER_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SIZEOF_CONTAINER_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFCONTAINERCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFCONTAINERCHECK_H
 
 #include "../ClangTidy.h"
 
 namespace clang {
 namespace tidy {
-namespace misc {
+namespace bugprone {
 
 /// Find usages of sizeof on expressions of STL container types. Most likely the
 /// user wanted to use `.size()` instead.
 ///
 /// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/misc-sizeof-container.html
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-sizeof-container.html
 class SizeofContainerCheck : public ClangTidyCheck {
 public:
   SizeofContainerCheck(StringRef Name, ClangTidyContext *Context)
@@ -29,8 +29,8 @@
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 };
 
-} // namespace misc
+} // namespace bugprone
 } // namespace tidy
 } // namespace clang
 
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SIZEOF_CONTAINER_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFCONTAINERCHECK_H
diff --git a/clang-tidy/misc/SizeofExpressionCheck.cpp b/clang-tidy/bugprone/SizeofExpressionCheck.cpp
similarity index 99%
rename from clang-tidy/misc/SizeofExpressionCheck.cpp
rename to clang-tidy/bugprone/SizeofExpressionCheck.cpp
index 5b8e7e7..d389ff1 100644
--- a/clang-tidy/misc/SizeofExpressionCheck.cpp
+++ b/clang-tidy/bugprone/SizeofExpressionCheck.cpp
@@ -16,7 +16,7 @@
 
 namespace clang {
 namespace tidy {
-namespace misc {
+namespace bugprone {
 
 namespace {
 
@@ -260,6 +260,6 @@
   }
 }
 
-} // namespace misc
+} // namespace bugprone
 } // namespace tidy
 } // namespace clang
diff --git a/clang-tidy/misc/SizeofExpressionCheck.h b/clang-tidy/bugprone/SizeofExpressionCheck.h
similarity index 73%
rename from clang-tidy/misc/SizeofExpressionCheck.h
rename to clang-tidy/bugprone/SizeofExpressionCheck.h
index d2ba9da..2811b5a 100644
--- a/clang-tidy/misc/SizeofExpressionCheck.h
+++ b/clang-tidy/bugprone/SizeofExpressionCheck.h
@@ -7,19 +7,19 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SIZEOF_EXPRESSION_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SIZEOF_EXPRESSION_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFEXPRESSIONCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFEXPRESSIONCHECK_H
 
 #include "../ClangTidy.h"
 
 namespace clang {
 namespace tidy {
-namespace misc {
+namespace bugprone {
 
 /// Find suspicious usages of sizeof expression.
 ///
 /// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/misc-sizeof-expression.html
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-sizeof-expression.html
 class SizeofExpressionCheck : public ClangTidyCheck {
 public:
   SizeofExpressionCheck(StringRef Name, ClangTidyContext *Context);
@@ -33,8 +33,8 @@
   const bool WarnOnSizeOfCompareToConstant;
 };
 
-} // namespace misc
+} // namespace bugprone
 } // namespace tidy
 } // namespace clang
 
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_SIZEOF_EXPRESSION_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SIZEOFEXPRESSIONCHECK_H
diff --git a/clang-tidy/misc/UnusedRAIICheck.cpp b/clang-tidy/bugprone/UnusedRaiiCheck.cpp
similarity index 91%
rename from clang-tidy/misc/UnusedRAIICheck.cpp
rename to clang-tidy/bugprone/UnusedRaiiCheck.cpp
index e1acfe9..e2882f3 100644
--- a/clang-tidy/misc/UnusedRAIICheck.cpp
+++ b/clang-tidy/bugprone/UnusedRaiiCheck.cpp
@@ -1,4 +1,4 @@
-//===--- UnusedRAIICheck.cpp - clang-tidy ---------------------------------===//
+//===--- UnusedRaiiCheck.cpp - clang-tidy ---------------------------------===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -7,7 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "UnusedRAIICheck.h"
+#include "UnusedRaiiCheck.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/Lex/Lexer.h"
 
@@ -15,7 +15,7 @@
 
 namespace clang {
 namespace tidy {
-namespace misc {
+namespace bugprone {
 
 namespace {
 AST_MATCHER(CXXRecordDecl, hasNonTrivialDestructor) {
@@ -24,7 +24,7 @@
 }
 } // namespace
 
-void UnusedRAIICheck::registerMatchers(MatchFinder *Finder) {
+void UnusedRaiiCheck::registerMatchers(MatchFinder *Finder) {
   // Only register the matchers for C++; the functionality currently does not
   // provide any benefit to other languages, despite being benign.
   if (!getLangOpts().CPlusPlus)
@@ -47,7 +47,7 @@
       this);
 }
 
-void UnusedRAIICheck::check(const MatchFinder::MatchResult &Result) {
+void UnusedRaiiCheck::check(const MatchFinder::MatchResult &Result) {
   const auto *E = Result.Nodes.getNodeAs<Expr>("expr");
 
   // We ignore code expanded from macros to reduce the number of false
@@ -89,6 +89,6 @@
       Replacement);
 }
 
-} // namespace misc
+} // namespace bugprone
 } // namespace tidy
 } // namespace clang
diff --git a/clang-tidy/bugprone/UnusedRaiiCheck.h b/clang-tidy/bugprone/UnusedRaiiCheck.h
new file mode 100644
index 0000000..34190ec
--- /dev/null
+++ b/clang-tidy/bugprone/UnusedRaiiCheck.h
@@ -0,0 +1,35 @@
+//===--- UnusedRaiiCheck.h - clang-tidy -------------------------*- C++ -*-===//
+//
+//                     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_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRAIICHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRAIICHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Finds temporaries that look like RAII objects.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-unused-raii.html
+class UnusedRaiiCheck : public ClangTidyCheck {
+public:
+  UnusedRaiiCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRAIICHECK_H
diff --git a/clang-tidy/bugprone/UnusedReturnValueCheck.cpp b/clang-tidy/bugprone/UnusedReturnValueCheck.cpp
new file mode 100644
index 0000000..198d0db
--- /dev/null
+++ b/clang-tidy/bugprone/UnusedReturnValueCheck.cpp
@@ -0,0 +1,82 @@
+//===--- UnusedReturnValueCheck.cpp - clang-tidy---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnusedReturnValueCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+using namespace clang::ast_matchers::internal;
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+UnusedReturnValueCheck::UnusedReturnValueCheck(llvm::StringRef Name,
+                                               ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      CheckedFunctions(Options.get("CheckedFunctions", "::std::async;"
+                                                       "::std::launder;"
+                                                       "::std::remove;"
+                                                       "::std::remove_if;"
+                                                       "::std::unique")) {}
+
+void UnusedReturnValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "CheckedFunctions", CheckedFunctions);
+}
+
+void UnusedReturnValueCheck::registerMatchers(MatchFinder *Finder) {
+  auto FunVec = utils::options::parseStringList(CheckedFunctions);
+  auto MatchedCallExpr = expr(ignoringImplicit(ignoringParenImpCasts(
+      callExpr(
+          callee(functionDecl(
+              // Don't match void overloads of checked functions.
+              unless(returns(voidType())), hasAnyName(std::vector<StringRef>(
+                                               FunVec.begin(), FunVec.end())))))
+          .bind("match"))));
+
+  auto UnusedInCompoundStmt =
+      compoundStmt(forEach(MatchedCallExpr),
+                   // The checker can't currently differentiate between the
+                   // return statement and other statements inside GNU statement
+                   // expressions, so disable the checker inside them to avoid
+                   // false positives.
+                   unless(hasParent(stmtExpr())));
+  auto UnusedInIfStmt =
+      ifStmt(eachOf(hasThen(MatchedCallExpr), hasElse(MatchedCallExpr)));
+  auto UnusedInWhileStmt = whileStmt(hasBody(MatchedCallExpr));
+  auto UnusedInDoStmt = doStmt(hasBody(MatchedCallExpr));
+  auto UnusedInForStmt =
+      forStmt(eachOf(hasLoopInit(MatchedCallExpr),
+                     hasIncrement(MatchedCallExpr), hasBody(MatchedCallExpr)));
+  auto UnusedInRangeForStmt = cxxForRangeStmt(hasBody(MatchedCallExpr));
+  auto UnusedInCaseStmt = switchCase(forEach(MatchedCallExpr));
+
+  Finder->addMatcher(
+      stmt(anyOf(UnusedInCompoundStmt, UnusedInIfStmt, UnusedInWhileStmt,
+                 UnusedInDoStmt, UnusedInForStmt, UnusedInRangeForStmt,
+                 UnusedInCaseStmt)),
+      this);
+}
+
+void UnusedReturnValueCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *Matched = Result.Nodes.getNodeAs<CallExpr>("match")) {
+    diag(Matched->getLocStart(),
+         "the value returned by this function should be used")
+        << Matched->getSourceRange();
+    diag(Matched->getLocStart(),
+         "cast the expression to void to silence this warning",
+         DiagnosticIDs::Note);
+  }
+}
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tidy/bugprone/UnusedReturnValueCheck.h b/clang-tidy/bugprone/UnusedReturnValueCheck.h
new file mode 100644
index 0000000..9475f56
--- /dev/null
+++ b/clang-tidy/bugprone/UnusedReturnValueCheck.h
@@ -0,0 +1,39 @@
+//===--- UnusedReturnValueCheck.h - clang-tidy-------------------*- C++ -*-===//
+//
+//                     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_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRETURNVALUECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRETURNVALUECHECK_H
+
+#include "../ClangTidy.h"
+#include <string>
+
+namespace clang {
+namespace tidy {
+namespace bugprone {
+
+/// Detects function calls where the return value is unused.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone-unused-return-value.html
+class UnusedReturnValueCheck : public ClangTidyCheck {
+public:
+  UnusedReturnValueCheck(StringRef Name, ClangTidyContext *Context);
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  std::string CheckedFunctions;
+};
+
+} // namespace bugprone
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNUSEDRETURNVALUECHECK_H
diff --git a/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp b/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp
index 791651f..aa91ff0 100644
--- a/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp
+++ b/clang-tidy/google/AvoidThrowingObjCExceptionCheck.cpp
@@ -19,6 +19,11 @@
 namespace objc {
 
 void AvoidThrowingObjCExceptionCheck::registerMatchers(MatchFinder *Finder) {
+  // this check should only be applied to ObjC sources.
+  if (!getLangOpts().ObjC1 && !getLangOpts().ObjC2) {
+    return;
+  }
+
   Finder->addMatcher(objcThrowStmt().bind("throwStmt"), this);
   Finder->addMatcher(
       objcMessageExpr(anyOf(hasSelector("raise:format:"),
diff --git a/clang-tidy/hicpp/CMakeLists.txt b/clang-tidy/hicpp/CMakeLists.txt
index 0e37b3e..eeccf62 100644
--- a/clang-tidy/hicpp/CMakeLists.txt
+++ b/clang-tidy/hicpp/CMakeLists.txt
@@ -2,6 +2,7 @@
 
 add_clang_library(clangTidyHICPPModule
   ExceptionBaseclassCheck.cpp
+  MultiwayPathsCoveredCheck.cpp
   NoAssemblerCheck.cpp
   HICPPTidyModule.cpp
   SignedBitwiseCheck.cpp
diff --git a/clang-tidy/hicpp/HICPPTidyModule.cpp b/clang-tidy/hicpp/HICPPTidyModule.cpp
index d8e9a20..d2b9fc6 100644
--- a/clang-tidy/hicpp/HICPPTidyModule.cpp
+++ b/clang-tidy/hicpp/HICPPTidyModule.cpp
@@ -36,6 +36,7 @@
 #include "../readability/FunctionSizeCheck.h"
 #include "../readability/IdentifierNamingCheck.h"
 #include "ExceptionBaseclassCheck.h"
+#include "MultiwayPathsCoveredCheck.h"
 #include "NoAssemblerCheck.h"
 #include "SignedBitwiseCheck.h"
 
@@ -54,6 +55,8 @@
         "hicpp-deprecated-headers");
     CheckFactories.registerCheck<ExceptionBaseclassCheck>(
         "hicpp-exception-baseclass");
+    CheckFactories.registerCheck<MultiwayPathsCoveredCheck>(
+        "hicpp-multiway-paths-covered");
     CheckFactories.registerCheck<SignedBitwiseCheck>("hicpp-signed-bitwise");
     CheckFactories.registerCheck<google::ExplicitConstructorCheck>(
         "hicpp-explicit-conversions");
diff --git a/clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp b/clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp
new file mode 100644
index 0000000..68ae54e
--- /dev/null
+++ b/clang-tidy/hicpp/MultiwayPathsCoveredCheck.cpp
@@ -0,0 +1,181 @@
+//===--- MultiwayPathsCoveredCheck.cpp - clang-tidy------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MultiwayPathsCoveredCheck.h"
+#include "clang/AST/ASTContext.h"
+
+#include <limits>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+void MultiwayPathsCoveredCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "WarnOnMissingElse", WarnOnMissingElse);
+}
+
+void MultiwayPathsCoveredCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      switchStmt(
+          hasCondition(allOf(
+              // Match on switch statements that have either a bit-field or
+              // an integer condition. The ordering in 'anyOf()' is
+              // important because the last condition is the most general.
+              anyOf(ignoringImpCasts(memberExpr(hasDeclaration(
+                        fieldDecl(isBitField()).bind("bitfield")))),
+                    ignoringImpCasts(declRefExpr().bind("non-enum-condition"))),
+              // 'unless()' must be the last match here and must be bound,
+              // otherwise the matcher does not work correctly, because it
+              // will not explicitly ignore enum conditions.
+              unless(ignoringImpCasts(
+                  declRefExpr(hasType(enumType())).bind("enum-condition"))))))
+          .bind("switch"),
+      this);
+
+  // This option is noisy, therefore matching is configurable.
+  if (WarnOnMissingElse) {
+    Finder->addMatcher(
+        ifStmt(allOf(hasParent(ifStmt()), unless(hasElse(anything()))))
+            .bind("else-if"),
+        this);
+  }
+}
+
+static std::pair<std::size_t, bool> countCaseLabels(const SwitchStmt *Switch) {
+  std::size_t CaseCount = 0;
+  bool HasDefault = false;
+
+  const SwitchCase *CurrentCase = Switch->getSwitchCaseList();
+  while (CurrentCase) {
+    ++CaseCount;
+    if (isa<DefaultStmt>(CurrentCase))
+      HasDefault = true;
+
+    CurrentCase = CurrentCase->getNextSwitchCase();
+  }
+
+  return std::make_pair(CaseCount, HasDefault);
+}
+
+/// This function calculate 2 ** Bits and returns
+/// numeric_limits<std::size_t>::max() if an overflow occured.
+static std::size_t twoPow(std::size_t Bits) {
+  return Bits >= std::numeric_limits<std::size_t>::digits
+             ? std::numeric_limits<std::size_t>::max()
+             : static_cast<size_t>(1) << Bits;
+}
+
+/// Get the number of possible values that can be switched on for the type T.
+///
+/// \return - 0 if bitcount could not be determined
+///         - numeric_limits<std::size_t>::max() when overflow appeared due to
+///           more than 64 bits type size.
+static std::size_t getNumberOfPossibleValues(QualType T,
+                                             const ASTContext &Context) {
+  // `isBooleanType` must come first because `bool` is an integral type as well
+  // and would not return 2 as result.
+  if (T->isBooleanType())
+    return 2;
+  else if (T->isIntegralType(Context))
+    return twoPow(Context.getTypeSize(T));
+  else
+    return 1;
+}
+
+void MultiwayPathsCoveredCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *ElseIfWithoutElse =
+          Result.Nodes.getNodeAs<IfStmt>("else-if")) {
+    diag(ElseIfWithoutElse->getLocStart(),
+         "potentially uncovered codepath; add an ending else statement");
+    return;
+  }
+  const auto *Switch = Result.Nodes.getNodeAs<SwitchStmt>("switch");
+  std::size_t SwitchCaseCount;
+  bool SwitchHasDefault;
+  std::tie(SwitchCaseCount, SwitchHasDefault) = countCaseLabels(Switch);
+
+  // Checks the sanity of 'switch' statements that actually do define
+  // a default branch but might be degenerated by having no or only one case.
+  if (SwitchHasDefault) {
+    handleSwitchWithDefault(Switch, SwitchCaseCount);
+    return;
+  }
+  // Checks all 'switch' statements that do not define a default label.
+  // Here the heavy lifting happens.
+  if (!SwitchHasDefault && SwitchCaseCount > 0) {
+    handleSwitchWithoutDefault(Switch, SwitchCaseCount, Result);
+    return;
+  }
+  // Warns for degenerated 'switch' statements that neither define a case nor
+  // a default label.
+  // FIXME: Evaluate, if emitting a fix-it to simplify that statement is 
+  // reasonable.
+  if (!SwitchHasDefault && SwitchCaseCount == 0) {
+    diag(Switch->getLocStart(),
+         "switch statement without labels has no effect");
+    return;
+  }
+  llvm_unreachable("matched a case, that was not explicitly handled");
+}
+
+void MultiwayPathsCoveredCheck::handleSwitchWithDefault(
+    const SwitchStmt *Switch, std::size_t CaseCount) {
+  assert(CaseCount > 0 && "Switch statement with supposedly one default "
+                          "branch did not contain any case labels");
+  if (CaseCount == 1 || CaseCount == 2)
+    diag(Switch->getLocStart(),
+         CaseCount == 1
+             ? "degenerated switch with default label only"
+             : "switch could be better written as an if/else statement");
+}
+
+void MultiwayPathsCoveredCheck::handleSwitchWithoutDefault(
+    const SwitchStmt *Switch, std::size_t CaseCount,
+    const MatchFinder::MatchResult &Result) {
+  // The matcher only works because some nodes are explicitly matched and
+  // bound but ignored. This is necessary to build the excluding logic for
+  // enums and 'switch' statements without a 'default' branch.
+  assert(!Result.Nodes.getNodeAs<DeclRefExpr>("enum-condition") &&
+         "switch over enum is handled by warnings already, explicitly ignoring "
+         "them");
+  // Determine the number of case labels. Because 'default' is not present
+  // and duplicating case labels is not allowed this number represents
+  // the number of codepaths. It can be directly compared to 'MaxPathsPossible'
+  // to see if some cases are missing.
+  // CaseCount == 0 is caught in DegenerateSwitch. Necessary because the
+  // matcher used for here does not match on degenerate 'switch'.
+  assert(CaseCount > 0 && "Switch statement without any case found. This case "
+                          "should be excluded by the matcher and is handled "
+                          "separatly.");
+  std::size_t MaxPathsPossible = [&]() {
+    if (const auto *GeneralCondition =
+            Result.Nodes.getNodeAs<DeclRefExpr>("non-enum-condition")) {
+      return getNumberOfPossibleValues(GeneralCondition->getType(),
+                                       *Result.Context);
+    }
+    if (const auto *BitfieldDecl =
+            Result.Nodes.getNodeAs<FieldDecl>("bitfield")) {
+      return twoPow(BitfieldDecl->getBitWidthValue(*Result.Context));
+    }
+
+    return static_cast<std::size_t>(0);
+  }();
+
+  // FIXME: Transform the 'switch' into an 'if' for CaseCount == 1.
+  if (CaseCount < MaxPathsPossible)
+    diag(Switch->getLocStart(),
+         CaseCount == 1 ? "switch with only one case; use an if statement"
+                        : "potential uncovered code path; add a default label");
+}
+} // namespace hicpp
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tidy/hicpp/MultiwayPathsCoveredCheck.h b/clang-tidy/hicpp/MultiwayPathsCoveredCheck.h
new file mode 100644
index 0000000..498dad6
--- /dev/null
+++ b/clang-tidy/hicpp/MultiwayPathsCoveredCheck.h
@@ -0,0 +1,51 @@
+//===--- MultiwayPathsCoveredCheck.h - clang-tidy----------------*- C++ -*-===//
+//
+//                     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_EXTRA_CLANG_TIDY_HICPP_MULTIWAY_PATHS_COVERED_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_MULTIWAY_PATHS_COVERED_H
+
+#include "../ClangTidy.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include <iostream>
+
+namespace clang {
+namespace tidy {
+namespace hicpp {
+
+/// Find occasions where not all codepaths are explicitly covered in code.
+/// This includes 'switch' without a 'default'-branch and 'if'-'else if'-chains
+/// without a final 'else'-branch.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/hicpp-multiway-paths-covered.html
+class MultiwayPathsCoveredCheck : public ClangTidyCheck {
+public:
+  MultiwayPathsCoveredCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context),
+        WarnOnMissingElse(Options.get("WarnOnMissingElse", 0)) {}
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  void handleSwitchWithDefault(const SwitchStmt *Switch, std::size_t CaseCount);
+  void handleSwitchWithoutDefault(
+      const SwitchStmt *Switch, std::size_t CaseCount,
+      const ast_matchers::MatchFinder::MatchResult &Result);
+  /// This option can be configured to warn on missing 'else' branches in an
+  /// 'if-else if' chain. The default is false because this option might be
+  /// noisy on some code bases.
+  const bool WarnOnMissingElse;
+};
+
+} // namespace hicpp
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_HICPP_MULTIWAY_PATHS_COVERED_H
diff --git a/clang-tidy/misc/CMakeLists.txt b/clang-tidy/misc/CMakeLists.txt
index 30b8efe..3806398 100644
--- a/clang-tidy/misc/CMakeLists.txt
+++ b/clang-tidy/misc/CMakeLists.txt
@@ -4,19 +4,15 @@
   MisplacedConstCheck.cpp
   UnconventionalAssignOperatorCheck.cpp
   DefinitionsInHeadersCheck.cpp
-  MacroParenthesesCheck.cpp
   MiscTidyModule.cpp
   NewDeleteOverloadsCheck.cpp
   NonCopyableObjects.cpp
   RedundantExpressionCheck.cpp
-  SizeofContainerCheck.cpp
-  SizeofExpressionCheck.cpp
   StaticAssertCheck.cpp
   ThrowByValueCatchByReferenceCheck.cpp
   UniqueptrResetReleaseCheck.cpp
   UnusedAliasDeclsCheck.cpp
   UnusedParametersCheck.cpp
-  UnusedRAIICheck.cpp
   UnusedUsingDeclsCheck.cpp
 
   LINK_LIBS
diff --git a/clang-tidy/misc/MiscTidyModule.cpp b/clang-tidy/misc/MiscTidyModule.cpp
index 56e6492..241689a 100644
--- a/clang-tidy/misc/MiscTidyModule.cpp
+++ b/clang-tidy/misc/MiscTidyModule.cpp
@@ -11,20 +11,16 @@
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
 #include "DefinitionsInHeadersCheck.h"
-#include "MacroParenthesesCheck.h"
 #include "MisplacedConstCheck.h"
 #include "NewDeleteOverloadsCheck.h"
 #include "NonCopyableObjects.h"
 #include "RedundantExpressionCheck.h"
-#include "SizeofContainerCheck.h"
-#include "SizeofExpressionCheck.h"
 #include "StaticAssertCheck.h"
 #include "ThrowByValueCatchByReferenceCheck.h"
 #include "UnconventionalAssignOperatorCheck.h"
 #include "UniqueptrResetReleaseCheck.h"
 #include "UnusedAliasDeclsCheck.h"
 #include "UnusedParametersCheck.h"
-#include "UnusedRAIICheck.h"
 #include "UnusedUsingDeclsCheck.h"
 
 namespace clang {
@@ -39,17 +35,12 @@
         "misc-unconventional-assign-operator");
     CheckFactories.registerCheck<DefinitionsInHeadersCheck>(
         "misc-definitions-in-headers");
-    CheckFactories.registerCheck<MacroParenthesesCheck>(
-        "misc-macro-parentheses");
     CheckFactories.registerCheck<NewDeleteOverloadsCheck>(
         "misc-new-delete-overloads");
     CheckFactories.registerCheck<NonCopyableObjectsCheck>(
         "misc-non-copyable-objects");
     CheckFactories.registerCheck<RedundantExpressionCheck>(
         "misc-redundant-expression");
-    CheckFactories.registerCheck<SizeofContainerCheck>("misc-sizeof-container");
-    CheckFactories.registerCheck<SizeofExpressionCheck>(
-        "misc-sizeof-expression");
     CheckFactories.registerCheck<StaticAssertCheck>("misc-static-assert");
     CheckFactories.registerCheck<ThrowByValueCatchByReferenceCheck>(
         "misc-throw-by-value-catch-by-reference");
@@ -59,7 +50,6 @@
         "misc-unused-alias-decls");
     CheckFactories.registerCheck<UnusedParametersCheck>(
         "misc-unused-parameters");
-    CheckFactories.registerCheck<UnusedRAIICheck>("misc-unused-raii");
     CheckFactories.registerCheck<UnusedUsingDeclsCheck>(
         "misc-unused-using-decls");
   }
diff --git a/clang-tidy/misc/UnusedRAIICheck.h b/clang-tidy/misc/UnusedRAIICheck.h
deleted file mode 100644
index 40f44e3..0000000
--- a/clang-tidy/misc/UnusedRAIICheck.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//===--- UnusedRAIICheck.h - clang-tidy -------------------------*- C++ -*-===//
-//
-//                     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_EXTRA_CLANG_TIDY_MISC_UNUSEDRAIICHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSEDRAIICHECK_H
-
-#include "../ClangTidy.h"
-
-namespace clang {
-namespace tidy {
-namespace misc {
-
-/// Finds temporaries that look like RAII objects.
-///
-/// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/misc-unused-raii.html
-class UnusedRAIICheck : public ClangTidyCheck {
-public:
-  UnusedRAIICheck(StringRef Name, ClangTidyContext *Context)
-      : ClangTidyCheck(Name, Context) {}
-  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
-  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
-};
-
-} // namespace misc
-} // namespace tidy
-} // namespace clang
-
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_UNUSEDRAIICHECK_H
diff --git a/clang-tidy/modernize/MakeSmartPtrCheck.cpp b/clang-tidy/modernize/MakeSmartPtrCheck.cpp
index fa071b8..8deaa83 100644
--- a/clang-tidy/modernize/MakeSmartPtrCheck.cpp
+++ b/clang-tidy/modernize/MakeSmartPtrCheck.cpp
@@ -61,8 +61,13 @@
   Options.store(Opts, "IgnoreMacros", IgnoreMacros);
 }
 
+bool MakeSmartPtrCheck::isLanguageVersionSupported(
+    const LangOptions &LangOpts) const {
+  return LangOpts.CPlusPlus11;
+}
+
 void MakeSmartPtrCheck::registerPPCallbacks(CompilerInstance &Compiler) {
-  if (getLangOpts().CPlusPlus11) {
+  if (isLanguageVersionSupported(getLangOpts())) {
     Inserter.reset(new utils::IncludeInserter(
         Compiler.getSourceManager(), Compiler.getLangOpts(), IncludeStyle));
     Compiler.getPreprocessor().addPPCallbacks(Inserter->CreatePPCallbacks());
@@ -70,7 +75,7 @@
 }
 
 void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
-  if (!getLangOpts().CPlusPlus11)
+  if (!isLanguageVersionSupported(getLangOpts()))
     return;
 
   // Calling make_smart_ptr from within a member function of a type with a
diff --git a/clang-tidy/modernize/MakeSmartPtrCheck.h b/clang-tidy/modernize/MakeSmartPtrCheck.h
index 8282154..6622482 100644
--- a/clang-tidy/modernize/MakeSmartPtrCheck.h
+++ b/clang-tidy/modernize/MakeSmartPtrCheck.h
@@ -40,6 +40,9 @@
   /// in this class.
   virtual SmartPtrTypeMatcher getSmartPointerTypeMatcher() const = 0;
 
+  /// Returns whether the C++ version is compatible with current check.
+  virtual bool isLanguageVersionSupported(const LangOptions &LangOpts) const;
+
   static const char PointerType[];
   static const char ConstructorCall[];
   static const char ResetCall[];
diff --git a/clang-tidy/modernize/MakeUniqueCheck.cpp b/clang-tidy/modernize/MakeUniqueCheck.cpp
index 4a9b306..3ebbb07 100644
--- a/clang-tidy/modernize/MakeUniqueCheck.cpp
+++ b/clang-tidy/modernize/MakeUniqueCheck.cpp
@@ -17,7 +17,8 @@
 
 MakeUniqueCheck::MakeUniqueCheck(StringRef Name,
                                  clang::tidy::ClangTidyContext *Context)
-    : MakeSmartPtrCheck(Name, Context, "std::make_unique") {}
+    : MakeSmartPtrCheck(Name, Context, "std::make_unique"),
+      RequireCPlusPlus14(Options.get("MakeSmartPtrFunction", "").empty()) {}
 
 MakeUniqueCheck::SmartPtrTypeMatcher
 MakeUniqueCheck::getSmartPointerTypeMatcher() const {
@@ -36,6 +37,11 @@
                                     equalsBoundNode(PointerType))))))))))))))));
 }
 
+bool MakeUniqueCheck::isLanguageVersionSupported(
+    const LangOptions &LangOpts) const {
+  return RequireCPlusPlus14 ? LangOpts.CPlusPlus14 : LangOpts.CPlusPlus11;
+}
+
 } // namespace modernize
 } // namespace tidy
 } // namespace clang
diff --git a/clang-tidy/modernize/MakeUniqueCheck.h b/clang-tidy/modernize/MakeUniqueCheck.h
index 15fbd55..587b41e 100644
--- a/clang-tidy/modernize/MakeUniqueCheck.h
+++ b/clang-tidy/modernize/MakeUniqueCheck.h
@@ -31,6 +31,11 @@
 
 protected:
   SmartPtrTypeMatcher getSmartPointerTypeMatcher() const override;
+
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override;
+
+private:
+  const bool RequireCPlusPlus14;
 };
 
 } // namespace modernize
diff --git a/clang-tidy/objc/AvoidNSErrorInitCheck.cpp b/clang-tidy/objc/AvoidNSErrorInitCheck.cpp
index d92414c..86c4656 100644
--- a/clang-tidy/objc/AvoidNSErrorInitCheck.cpp
+++ b/clang-tidy/objc/AvoidNSErrorInitCheck.cpp
@@ -18,6 +18,10 @@
 namespace objc {
 
 void AvoidNSErrorInitCheck::registerMatchers(MatchFinder *Finder) {
+  // this check should only be applied to ObjC sources.
+  if (!getLangOpts().ObjC1 && !getLangOpts().ObjC2) {
+    return;
+  }
   Finder->addMatcher(objcMessageExpr(hasSelector("init"),
                                      hasReceiverType(asString("NSError *")))
                          .bind("nserrorInit"),
diff --git a/clang-tidy/objc/ForbiddenSubclassingCheck.cpp b/clang-tidy/objc/ForbiddenSubclassingCheck.cpp
index a8d79f5..e78cb99 100644
--- a/clang-tidy/objc/ForbiddenSubclassingCheck.cpp
+++ b/clang-tidy/objc/ForbiddenSubclassingCheck.cpp
@@ -77,6 +77,10 @@
 }
 
 void ForbiddenSubclassingCheck::registerMatchers(MatchFinder *Finder) {
+  // this check should only be applied to ObjC sources.
+  if (!getLangOpts().ObjC1 && !getLangOpts().ObjC2) {
+    return;
+  }
   Finder->addMatcher(
       objcInterfaceDecl(
           isSubclassOf(
diff --git a/clang-tidy/objc/PropertyDeclarationCheck.cpp b/clang-tidy/objc/PropertyDeclarationCheck.cpp
index 700c5e6..7a3bbaf 100644
--- a/clang-tidy/objc/PropertyDeclarationCheck.cpp
+++ b/clang-tidy/objc/PropertyDeclarationCheck.cpp
@@ -170,6 +170,10 @@
       EscapedAcronyms() {}
 
 void PropertyDeclarationCheck::registerMatchers(MatchFinder *Finder) {
+  // this check should only be applied to ObjC sources.
+  if (!getLangOpts().ObjC1 && !getLangOpts().ObjC2) {
+    return;
+  }
   if (IncludeDefaultAcronyms) {
     EscapedAcronyms.reserve(llvm::array_lengthof(DefaultSpecialAcronyms) +
                             SpecialAcronyms.size());
diff --git a/clang-tidy/plugin/CMakeLists.txt b/clang-tidy/plugin/CMakeLists.txt
index 995c086..1979383 100644
--- a/clang-tidy/plugin/CMakeLists.txt
+++ b/clang-tidy/plugin/CMakeLists.txt
@@ -9,6 +9,7 @@
   clangSema
   clangTidy
   clangTidyAndroidModule
+  clangTidyAbseilModule
   clangTidyBoostModule
   clangTidyCERTModule
   clangTidyCppCoreGuidelinesModule
@@ -19,6 +20,7 @@
   clangTidyMPIModule
   clangTidyObjCModule
   clangTidyPerformanceModule
+  clangTidyPortabilityModule
   clangTidyReadabilityModule
   clangTooling
   )
diff --git a/clang-tidy/plugin/ClangTidyPlugin.cpp b/clang-tidy/plugin/ClangTidyPlugin.cpp
index 25c13c7..dc56772 100644
--- a/clang-tidy/plugin/ClangTidyPlugin.cpp
+++ b/clang-tidy/plugin/ClangTidyPlugin.cpp
@@ -118,6 +118,11 @@
 static int LLVM_ATTRIBUTE_UNUSED PerformanceModuleAnchorDestination =
     PerformanceModuleAnchorSource;
 
+// This anchor is used to force the linker to link the PortabilityModule.
+extern volatile int PortabilityModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED PortabilityModuleAnchorDestination =
+    PortabilityModuleAnchorSource;
+
 // This anchor is used to force the linker to link the ReadabilityModule.
 extern volatile int ReadabilityModuleAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination =
diff --git a/clang-tidy/portability/CMakeLists.txt b/clang-tidy/portability/CMakeLists.txt
new file mode 100644
index 0000000..0420a18
--- /dev/null
+++ b/clang-tidy/portability/CMakeLists.txt
@@ -0,0 +1,15 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyPortabilityModule
+  PortabilityTidyModule.cpp
+  SIMDIntrinsicsCheck.cpp
+
+  LINK_LIBS
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangLex
+  clangTidy
+  clangTidyUtils
+  clangTooling
+  )
diff --git a/clang-tidy/portability/PortabilityTidyModule.cpp b/clang-tidy/portability/PortabilityTidyModule.cpp
new file mode 100644
index 0000000..013cbcf
--- /dev/null
+++ b/clang-tidy/portability/PortabilityTidyModule.cpp
@@ -0,0 +1,38 @@
+//===--- PortabilityTidyModule.cpp - clang-tidy ---------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "SIMDIntrinsicsCheck.h"
+
+namespace clang {
+namespace tidy {
+namespace portability {
+
+class PortabilityModule : public ClangTidyModule {
+public:
+  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    CheckFactories.registerCheck<SIMDIntrinsicsCheck>(
+        "portability-simd-intrinsics");
+  }
+};
+
+// Register the PortabilityModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<PortabilityModule>
+    X("portability-module", "Adds portability-related checks.");
+
+} // namespace portability
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the PortabilityModule.
+volatile int PortabilityModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tidy/readability/SIMDIntrinsicsCheck.cpp b/clang-tidy/portability/SIMDIntrinsicsCheck.cpp
similarity index 82%
rename from clang-tidy/readability/SIMDIntrinsicsCheck.cpp
rename to clang-tidy/portability/SIMDIntrinsicsCheck.cpp
index 123e76d..d5434cc 100644
--- a/clang-tidy/readability/SIMDIntrinsicsCheck.cpp
+++ b/clang-tidy/portability/SIMDIntrinsicsCheck.cpp
@@ -18,7 +18,7 @@
 
 namespace clang {
 namespace tidy {
-namespace readability {
+namespace portability {
 
 namespace {
 
@@ -84,17 +84,21 @@
 
 SIMDIntrinsicsCheck::SIMDIntrinsicsCheck(StringRef Name,
                                          ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context), Suggest(Options.get("Suggest", 0) != 0) {}
+    : ClangTidyCheck(Name, Context), Std(Options.get("Std", "")),
+      Suggest(Options.get("Suggest", 0) != 0) {}
 
 void SIMDIntrinsicsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "Std", "");
   Options.store(Opts, "Suggest", 0);
 }
 
 void SIMDIntrinsicsCheck::registerMatchers(MatchFinder *Finder) {
   if (!getLangOpts().CPlusPlus11)
     return;
+  // If Std is not specified, infer it from the language options.
   // libcxx implementation backports it to C++11 std::experimental::simd.
-  Std = getLangOpts().CPlusPlus2a ? "std" : "std::experimental";
+  if (Std.empty())
+    Std = getLangOpts().CPlusPlus2a ? "std" : "std::experimental";
 
   Finder->addMatcher(callExpr(callee(functionDecl(allOf(
                                   matchesName("^::(_mm_|_mm256_|_mm512_|vec_)"),
@@ -116,20 +120,23 @@
   llvm::Triple::ArchType Arch =
       Result.Context->getTargetInfo().getTriple().getArch();
 
+  // We warn or suggest if this SIMD intrinsic function has a std::simd
+  // replacement.
   switch (Arch) {
-    default:
-      break;
-    case llvm::Triple::ppc:
-    case llvm::Triple::ppc64:
-    case llvm::Triple::ppc64le:
-      New = TrySuggestPPC(Old);
-      break;
-    case llvm::Triple::x86:
-    case llvm::Triple::x86_64:
-      New = TrySuggestX86(Old);
-      break;
+  default:
+    break;
+  case llvm::Triple::ppc:
+  case llvm::Triple::ppc64:
+  case llvm::Triple::ppc64le:
+    New = TrySuggestPPC(Old);
+    break;
+  case llvm::Triple::x86:
+  case llvm::Triple::x86_64:
+    New = TrySuggestX86(Old);
+    break;
   }
 
+  // We have found a std::simd replacement.
   if (!New.empty()) {
     std::string Message;
     // If Suggest is true, give a P0214 alternative, otherwise point it out it
@@ -137,7 +144,8 @@
     if (Suggest) {
       Message = (Twine("'") + Old + "' can be replaced by " + New).str();
       Message = llvm::Regex("\\$std").sub(Std, Message);
-      Message = llvm::Regex("\\$simd").sub(Std.str() + "::simd", Message);
+      Message =
+          llvm::Regex("\\$simd").sub((Std.str() + "::simd").str(), Message);
     } else {
       Message = (Twine("'") + Old + "' is a non-portable " +
                  llvm::Triple::getArchTypeName(Arch) + " intrinsic function")
@@ -147,6 +155,6 @@
   }
 }
 
-} // namespace readability
+} // namespace portability
 } // namespace tidy
 } // namespace clang
diff --git a/clang-tidy/readability/SIMDIntrinsicsCheck.h b/clang-tidy/portability/SIMDIntrinsicsCheck.h
similarity index 86%
rename from clang-tidy/readability/SIMDIntrinsicsCheck.h
rename to clang-tidy/portability/SIMDIntrinsicsCheck.h
index 8c36cd7..ebcc855 100644
--- a/clang-tidy/readability/SIMDIntrinsicsCheck.h
+++ b/clang-tidy/portability/SIMDIntrinsicsCheck.h
@@ -12,14 +12,16 @@
 
 #include "../ClangTidy.h"
 
+#include "llvm/ADT/SmallString.h"
+
 namespace clang {
 namespace tidy {
-namespace readability {
+namespace portability {
 
 /// Find SIMD intrinsics calls and suggest std::experimental::simd alternatives.
 ///
 /// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/readability-simd-intrinsics.html
+/// http://clang.llvm.org/extra/clang-tidy/checks/portability-simd-intrinsics.html
 class SIMDIntrinsicsCheck : public ClangTidyCheck {
 public:
   SIMDIntrinsicsCheck(StringRef Name, ClangTidyContext *Context);
@@ -29,11 +31,11 @@
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 
  private:
+  llvm::SmallString<32> Std;
   const bool Suggest;
-  StringRef Std;
 };
 
-} // namespace readability
+} // namespace portability
 } // namespace tidy
 } // namespace clang
 
diff --git a/clang-tidy/readability/CMakeLists.txt b/clang-tidy/readability/CMakeLists.txt
index d750626..95769ee 100644
--- a/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tidy/readability/CMakeLists.txt
@@ -24,7 +24,6 @@
   RedundantStringCStrCheck.cpp
   RedundantSmartptrGetCheck.cpp
   RedundantStringInitCheck.cpp
-  SIMDIntrinsicsCheck.cpp
   SimplifyBooleanExprCheck.cpp
   StaticAccessedThroughInstanceCheck.cpp
   StaticDefinitionInAnonymousNamespaceCheck.cpp
diff --git a/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tidy/readability/ReadabilityTidyModule.cpp
index 619a448..f39e4a1 100644
--- a/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -31,7 +31,6 @@
 #include "RedundantSmartptrGetCheck.h"
 #include "RedundantStringCStrCheck.h"
 #include "RedundantStringInitCheck.h"
-#include "SIMDIntrinsicsCheck.h"
 #include "SimplifyBooleanExprCheck.h"
 #include "StaticAccessedThroughInstanceCheck.h"
 #include "StaticDefinitionInAnonymousNamespaceCheck.h"
@@ -93,8 +92,6 @@
         "readability-redundant-string-cstr");
     CheckFactories.registerCheck<RedundantStringInitCheck>(
         "readability-redundant-string-init");
-    CheckFactories.registerCheck<SIMDIntrinsicsCheck>(
-        "readability-simd-intrinsics");
     CheckFactories.registerCheck<SimplifyBooleanExprCheck>(
         "readability-simplify-boolean-expr");
     CheckFactories.registerCheck<UniqueptrDeleteReleaseCheck>(
diff --git a/clang-tidy/rename_check.py b/clang-tidy/rename_check.py
index 49798f7..53a5ff9 100755
--- a/clang-tidy/rename_check.py
+++ b/clang-tidy/rename_check.py
@@ -171,8 +171,8 @@
         elif header_found:
           if not line.startswith('----'):
             f.write("""
-- The '%s' check was renamed to `%s
-  <http://clang.llvm.org/extra/clang-tidy/checks/%s.html>`_
+- The '%s' check was renamed to :doc:`%s
+  <clang-tidy/checks/%s>`
 """ % (old_check_name, new_check_name, new_check_name))
             note_added = True
 
diff --git a/clang-tidy/tool/CMakeLists.txt b/clang-tidy/tool/CMakeLists.txt
index 07f2671..a3ec4ae 100644
--- a/clang-tidy/tool/CMakeLists.txt
+++ b/clang-tidy/tool/CMakeLists.txt
@@ -18,6 +18,7 @@
   clangBasic
   clangTidy
   clangTidyAndroidModule
+  clangTidyAbseilModule
   clangTidyBoostModule
   clangTidyBugproneModule
   clangTidyCERTModule
@@ -31,7 +32,9 @@
   clangTidyMPIModule
   clangTidyObjCModule
   clangTidyPerformanceModule
+  clangTidyPortabilityModule
   clangTidyReadabilityModule
+  clangTidyZirconModule
   clangTooling
   clangToolingCore
   )
diff --git a/clang-tidy/tool/ClangTidyMain.cpp b/clang-tidy/tool/ClangTidyMain.cpp
index e362b32..8f0c420 100644
--- a/clang-tidy/tool/ClangTidyMain.cpp
+++ b/clang-tidy/tool/ClangTidyMain.cpp
@@ -424,13 +424,13 @@
   if (EnabledChecks.empty()) {
     llvm::errs() << "Error: no checks enabled.\n";
     llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
-    return 0;
+    return 1;
   }
 
   if (PathList.empty()) {
     llvm::errs() << "Error: no input files specified.\n";
     llvm::cl::PrintHelpMessage(/*Hidden=*/false, /*Categorized=*/true);
-    return 0;
+    return 1;
   }
   llvm::IntrusiveRefCntPtr<vfs::FileSystem> BaseFS(
       VfsOverlay.empty() ? vfs::getRealFileSystem()
@@ -499,6 +499,11 @@
 static int LLVM_ATTRIBUTE_UNUSED CERTModuleAnchorDestination =
     CERTModuleAnchorSource;
 
+// This anchor is used to force the linker to link the AbseilModule.
+extern volatile int AbseilModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED AbseilModuleAnchorDestination =
+    AbseilModuleAnchorSource;
+
 // This anchor is used to force the linker to link the BoostModule.
 extern volatile int BoostModuleAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED BoostModuleAnchorDestination =
@@ -519,7 +524,7 @@
 static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination =
     CppCoreGuidelinesModuleAnchorSource;
 
-// This anchor is used to force the linker to link the GoogleModule.
+// This anchor is used to force the linker to link the FuchsiaModule.
 extern volatile int FuchsiaModuleAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED FuchsiaModuleAnchorDestination =
     FuchsiaModuleAnchorSource;
@@ -554,6 +559,11 @@
 static int LLVM_ATTRIBUTE_UNUSED PerformanceModuleAnchorDestination =
     PerformanceModuleAnchorSource;
 
+// This anchor is used to force the linker to link the PortabilityModule.
+extern volatile int PortabilityModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED PortabilityModuleAnchorDestination =
+    PortabilityModuleAnchorSource;
+
 // This anchor is used to force the linker to link the ReadabilityModule.
 extern volatile int ReadabilityModuleAnchorSource;
 static int LLVM_ATTRIBUTE_UNUSED ReadabilityModuleAnchorDestination =
@@ -569,6 +579,11 @@
 static int LLVM_ATTRIBUTE_UNUSED HICPPModuleAnchorDestination =
     HICPPModuleAnchorSource;
 
+// This anchor is used to force the linker to link the ZirconModule.
+extern volatile int ZirconModuleAnchorSource;
+static int LLVM_ATTRIBUTE_UNUSED ZirconModuleAnchorDestination =
+    ZirconModuleAnchorSource;
+
 } // namespace tidy
 } // namespace clang
 
diff --git a/clang-tidy/tool/run-clang-tidy.py b/clang-tidy/tool/run-clang-tidy.py
index 379ad71..ce46c0e 100755
--- a/clang-tidy/tool/run-clang-tidy.py
+++ b/clang-tidy/tool/run-clang-tidy.py
@@ -75,7 +75,8 @@
 
 
 def get_tidy_invocation(f, clang_tidy_binary, checks, tmpdir, build_path,
-                        header_filter, extra_arg, extra_arg_before, quiet):
+                        header_filter, extra_arg, extra_arg_before, quiet,
+                        config):
   """Gets a command line for clang-tidy."""
   start = [clang_tidy_binary]
   if header_filter is not None:
@@ -99,6 +100,8 @@
   start.append('-p=' + build_path)
   if quiet:
       start.append('-quiet')
+  if config:
+      start.append('-config=' + config)
   start.append(f)
   return start
 
@@ -150,16 +153,18 @@
   subprocess.call(invocation)
 
 
-def run_tidy(args, tmpdir, build_path, queue):
+def run_tidy(args, tmpdir, build_path, queue, failed_files):
   """Takes filenames out of queue and runs clang-tidy on them."""
   while True:
     name = queue.get()
     invocation = get_tidy_invocation(name, args.clang_tidy_binary, args.checks,
                                      tmpdir, build_path, args.header_filter,
                                      args.extra_arg, args.extra_arg_before,
-                                     args.quiet)
+                                     args.quiet, args.config)
     sys.stdout.write(' '.join(invocation) + '\n')
-    subprocess.call(invocation)
+    return_code = subprocess.call(invocation)
+    if return_code != 0:
+      failed_files.append(name)
     queue.task_done()
 
 
@@ -177,6 +182,14 @@
   parser.add_argument('-checks', default=None,
                       help='checks filter, when not specified, use clang-tidy '
                       'default')
+  parser.add_argument('-config', default=None,
+                      help='Specifies a configuration in YAML/JSON format: '
+                      '  -config="{Checks: \'*\', '
+                      '                       CheckOptions: [{key: x, '
+                      '                                       value: y}]}" '
+                      'When the value is empty, clang-tidy will '
+                      'attempt to find a file named .clang-tidy for '
+                      'each source file in its parent directories.')
   parser.add_argument('-header-filter', default=None,
                       help='regular expression matching the names of the '
                       'headers to output diagnostics from. Diagnostics from '
@@ -244,12 +257,15 @@
   # Build up a big regexy filter from all command line arguments.
   file_name_re = re.compile('|'.join(args.files))
 
+  return_code = 0
   try:
     # Spin up a bunch of tidy-launching threads.
     task_queue = queue.Queue(max_task)
+    # List of files with a non-zero return code.
+    failed_files = []
     for _ in range(max_task):
       t = threading.Thread(target=run_tidy,
-                           args=(args, tmpdir, build_path, task_queue))
+                           args=(args, tmpdir, build_path, task_queue, failed_files))
       t.daemon = True
       t.start()
 
@@ -260,6 +276,8 @@
 
     # Wait for all threads to be done.
     task_queue.join()
+    if len(failed_files):
+      return_code = 1
 
   except KeyboardInterrupt:
     # This is a sad hack. Unfortunately subprocess goes
@@ -269,7 +287,6 @@
       shutil.rmtree(tmpdir)
     os.kill(0, 9)
 
-  return_code = 0
   if args.export_fixes:
     print('Writing fixes to ' + args.export_fixes + ' ...')
     try:
diff --git a/clang-tidy/zircon/CMakeLists.txt b/clang-tidy/zircon/CMakeLists.txt
new file mode 100644
index 0000000..7aa7cd3
--- /dev/null
+++ b/clang-tidy/zircon/CMakeLists.txt
@@ -0,0 +1,14 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangTidyZirconModule
+  TemporaryObjectsCheck.cpp
+  ZirconTidyModule.cpp
+
+  LINK_LIBS
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangLex
+  clangTidy
+  clangTidyUtils
+  )
diff --git a/clang-tidy/zircon/TemporaryObjectsCheck.cpp b/clang-tidy/zircon/TemporaryObjectsCheck.cpp
new file mode 100644
index 0000000..5fff67b
--- /dev/null
+++ b/clang-tidy/zircon/TemporaryObjectsCheck.cpp
@@ -0,0 +1,60 @@
+//===--- TemporaryObjectsCheck.cpp - clang-tidy----------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "TemporaryObjectsCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include <string>
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace zircon {
+
+AST_MATCHER_P(CXXRecordDecl, matchesAnyName, ArrayRef<std::string>, Names) {
+  std::string QualifiedName = Node.getQualifiedNameAsString();
+  return llvm::any_of(Names,
+                      [&](StringRef Name) { return QualifiedName == Name; });
+}
+
+void TemporaryObjectsCheck::registerMatchers(MatchFinder *Finder) {
+  // Matcher for default constructors.
+  Finder->addMatcher(
+      cxxTemporaryObjectExpr(hasDeclaration(cxxConstructorDecl(hasParent(
+                                 cxxRecordDecl(matchesAnyName(Names))))))
+          .bind("temps"),
+      this);
+
+  // Matcher for user-defined constructors.
+  Finder->addMatcher(
+      cxxConstructExpr(allOf(hasParent(cxxFunctionalCastExpr()),
+                             hasDeclaration(cxxConstructorDecl(hasParent(
+                                 cxxRecordDecl(matchesAnyName(Names)))))))
+          .bind("temps"),
+      this);
+}
+
+void TemporaryObjectsCheck::check(const MatchFinder::MatchResult &Result) {
+  if (const auto *D = Result.Nodes.getNodeAs<CXXConstructExpr>("temps"))
+    diag(D->getLocation(),
+         "creating a temporary object of type %q0 is prohibited")
+        << D->getConstructor()->getParent();
+}
+
+void TemporaryObjectsCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "Names", utils::options::serializeStringList(Names));
+}
+
+} // namespace zircon
+} // namespace tidy
+} // namespace clang
diff --git a/clang-tidy/zircon/TemporaryObjectsCheck.h b/clang-tidy/zircon/TemporaryObjectsCheck.h
new file mode 100644
index 0000000..302ef72
--- /dev/null
+++ b/clang-tidy/zircon/TemporaryObjectsCheck.h
@@ -0,0 +1,42 @@
+//===--- TemporaryObjectsCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+//                     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_EXTRA_CLANG_TIDY_ZIRCON_TEMPORARYOBJECTSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_TEMPORARYOBJECTSCHECK_H
+
+#include "../ClangTidy.h"
+#include "../utils/OptionsUtils.h"
+
+namespace clang {
+namespace tidy {
+namespace zircon {
+
+/// Construction of specific temporary objects in the Zircon kernel is
+/// discouraged.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/zircon-temporary-objects.html
+class TemporaryObjectsCheck : public ClangTidyCheck {
+public:
+  TemporaryObjectsCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context),
+        Names(utils::options::parseStringList(Options.get("Names", ""))) {}
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  std::vector<std::string> Names;
+};
+
+} // namespace zircon
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_ZIRCON_TEMPORARYOBJECTSCHECK_H
diff --git a/clang-tidy/zircon/ZirconTidyModule.cpp b/clang-tidy/zircon/ZirconTidyModule.cpp
new file mode 100644
index 0000000..3e53c23
--- /dev/null
+++ b/clang-tidy/zircon/ZirconTidyModule.cpp
@@ -0,0 +1,40 @@
+//===--- ZirconTidyModule.cpp - clang-tidy---------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "../ClangTidy.h"
+#include "../ClangTidyModule.h"
+#include "../ClangTidyModuleRegistry.h"
+#include "TemporaryObjectsCheck.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace zircon {
+
+/// This module is for Zircon-specific checks.
+class ZirconModule : public ClangTidyModule {
+public:
+  void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    CheckFactories.registerCheck<TemporaryObjectsCheck>(
+        "zircon-temporary-objects");
+  }
+};
+
+// Register the ZirconTidyModule using this statically initialized variable.
+static ClangTidyModuleRegistry::Add<ZirconModule>
+    X("zircon-module", "Adds Zircon kernel checks.");
+} // namespace zircon
+
+// This anchor is used to force the linker to link in the generated object file
+// and thus register the ZirconModule.
+volatile int ZirconModuleAnchorSource = 0;
+
+} // namespace tidy
+} // namespace clang
diff --git a/clangd/AST.cpp b/clangd/AST.cpp
new file mode 100644
index 0000000..5d549c3
--- /dev/null
+++ b/clangd/AST.cpp
@@ -0,0 +1,42 @@
+//===--- AST.cpp - Utility AST functions  -----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "AST.h"
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/Basic/SourceManager.h"
+
+namespace clang {
+namespace clangd {
+using namespace llvm;
+
+SourceLocation findNameLoc(const clang::Decl* D) {
+  const auto& SM = D->getASTContext().getSourceManager();
+  // FIXME: Revisit the strategy, the heuristic is limitted when handling
+  // macros, we should use the location where the whole definition occurs.
+  SourceLocation SpellingLoc = SM.getSpellingLoc(D->getLocation());
+  if (D->getLocation().isMacroID()) {
+    std::string PrintLoc = SpellingLoc.printToString(SM);
+    if (llvm::StringRef(PrintLoc).startswith("<scratch") ||
+        llvm::StringRef(PrintLoc).startswith("<command line>")) {
+      // We use the expansion location for the following symbols, as spelling
+      // locations of these symbols are not interesting to us:
+      //   * symbols formed via macro concatenation, the spelling location will
+      //     be "<scratch space>"
+      //   * symbols controlled and defined by a compile command-line option
+      //     `-DName=foo`, the spelling location will be "<command line>".
+      SpellingLoc = SM.getExpansionRange(D->getLocation()).first;
+    }
+  }
+  return SpellingLoc;
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/clangd/AST.h b/clangd/AST.h
new file mode 100644
index 0000000..b8cf074
--- /dev/null
+++ b/clangd/AST.h
@@ -0,0 +1,34 @@
+//===--- AST.h - Utility AST functions  -------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Various code that examines C++ source code using AST.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
+
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+class SourceManager;
+class Decl;
+
+namespace clangd {
+
+/// Find the identifier source location of the given D.
+///
+/// The returned location is usually the spelling location where the name of the
+/// decl occurs in the code.
+SourceLocation findNameLoc(const clang::Decl* D);
+
+} // namespace clangd
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANGD_AST_H_
diff --git a/clangd/CMakeLists.txt b/clangd/CMakeLists.txt
index d12a6b3..6da1766 100644
--- a/clangd/CMakeLists.txt
+++ b/clangd/CMakeLists.txt
@@ -3,6 +3,7 @@
   )
 
 add_clang_library(clangDaemon
+  AST.cpp
   ClangdLSPServer.cpp
   ClangdServer.cpp
   ClangdUnit.cpp
@@ -11,6 +12,7 @@
   CompileArgsCache.cpp
   Compiler.cpp
   Context.cpp
+  Diagnostics.cpp
   DraftStore.cpp
   FuzzyMatch.cpp
   GlobalCompilationDatabase.cpp
diff --git a/clangd/ClangdLSPServer.cpp b/clangd/ClangdLSPServer.cpp
index 539ee17..61dbd66 100644
--- a/clangd/ClangdLSPServer.cpp
+++ b/clangd/ClangdLSPServer.cpp
@@ -8,9 +8,11 @@
 //===---------------------------------------------------------------------===//
 
 #include "ClangdLSPServer.h"
+#include "Diagnostics.h"
 #include "JSONRPCDispatcher.h"
 #include "SourceCode.h"
 #include "URI.h"
+#include "llvm/Support/Errc.h"
 #include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"
 
@@ -98,7 +100,7 @@
   reply(json::obj{
       {{"capabilities",
         json::obj{
-            {"textDocumentSync", 1},
+            {"textDocumentSync", (int)TextDocumentSyncKind::Incremental},
             {"documentFormattingProvider", true},
             {"documentRangeFormattingProvider", true},
             {"documentOnTypeFormattingProvider",
@@ -141,21 +143,34 @@
   if (Params.metadata && !Params.metadata->extraFlags.empty())
     CDB.setExtraFlagsForFile(Params.textDocument.uri.file(),
                              std::move(Params.metadata->extraFlags));
-  Server.addDocument(Params.textDocument.uri.file(), Params.textDocument.text,
-                     WantDiagnostics::Yes);
+
+  PathRef File = Params.textDocument.uri.file();
+  std::string &Contents = Params.textDocument.text;
+
+  DraftMgr.addDraft(File, Contents);
+  Server.addDocument(File, Contents, WantDiagnostics::Yes);
 }
 
 void ClangdLSPServer::onDocumentDidChange(DidChangeTextDocumentParams &Params) {
-  if (Params.contentChanges.size() != 1)
-    return replyError(ErrorCode::InvalidParams,
-                      "can only apply one change at a time");
   auto WantDiags = WantDiagnostics::Auto;
   if (Params.wantDiagnostics.hasValue())
     WantDiags = Params.wantDiagnostics.getValue() ? WantDiagnostics::Yes
                                                   : WantDiagnostics::No;
-  // We only support full syncing right now.
-  Server.addDocument(Params.textDocument.uri.file(),
-                     Params.contentChanges[0].text, WantDiags);
+
+  PathRef File = Params.textDocument.uri.file();
+  llvm::Expected<std::string> Contents =
+      DraftMgr.updateDraft(File, Params.contentChanges);
+  if (!Contents) {
+    // If this fails, we are most likely going to be not in sync anymore with
+    // the client.  It is better to remove the draft and let further operations
+    // fail rather than giving wrong results.
+    DraftMgr.removeDraft(File);
+    Server.removeDocument(File);
+    log(llvm::toString(Contents.takeError()));
+    return;
+  }
+
+  Server.addDocument(File, *Contents, WantDiags);
 }
 
 void ClangdLSPServer::onFileEvent(DidChangeWatchedFilesParams &Params) {
@@ -187,7 +202,7 @@
   } else if (Params.command ==
              ExecuteCommandParams::CLANGD_INSERT_HEADER_INCLUDE) {
     auto &FileURI = Params.includeInsertion->textDocument.uri;
-    auto Code = Server.getDocument(FileURI.file());
+    auto Code = DraftMgr.getDraft(FileURI.file());
     if (!Code)
       return replyError(ErrorCode::InvalidParams,
                         ("command " +
@@ -232,7 +247,7 @@
 
 void ClangdLSPServer::onRename(RenameParams &Params) {
   Path File = Params.textDocument.uri.file();
-  llvm::Optional<std::string> Code = Server.getDocument(File);
+  llvm::Optional<std::string> Code = DraftMgr.getDraft(File);
   if (!Code)
     return replyError(ErrorCode::InvalidParams,
                       "onRename called for non-added file");
@@ -253,13 +268,15 @@
 }
 
 void ClangdLSPServer::onDocumentDidClose(DidCloseTextDocumentParams &Params) {
-  Server.removeDocument(Params.textDocument.uri.file());
+  PathRef File = Params.textDocument.uri.file();
+  DraftMgr.removeDraft(File);
+  Server.removeDocument(File);
 }
 
 void ClangdLSPServer::onDocumentOnTypeFormatting(
     DocumentOnTypeFormattingParams &Params) {
   auto File = Params.textDocument.uri.file();
-  auto Code = Server.getDocument(File);
+  auto Code = DraftMgr.getDraft(File);
   if (!Code)
     return replyError(ErrorCode::InvalidParams,
                       "onDocumentOnTypeFormatting called for non-added file");
@@ -275,7 +292,7 @@
 void ClangdLSPServer::onDocumentRangeFormatting(
     DocumentRangeFormattingParams &Params) {
   auto File = Params.textDocument.uri.file();
-  auto Code = Server.getDocument(File);
+  auto Code = DraftMgr.getDraft(File);
   if (!Code)
     return replyError(ErrorCode::InvalidParams,
                       "onDocumentRangeFormatting called for non-added file");
@@ -290,7 +307,7 @@
 
 void ClangdLSPServer::onDocumentFormatting(DocumentFormattingParams &Params) {
   auto File = Params.textDocument.uri.file();
-  auto Code = Server.getDocument(File);
+  auto Code = DraftMgr.getDraft(File);
   if (!Code)
     return replyError(ErrorCode::InvalidParams,
                       "onDocumentFormatting called for non-added file");
@@ -306,19 +323,19 @@
 void ClangdLSPServer::onCodeAction(CodeActionParams &Params) {
   // We provide a code action for each diagnostic at the requested location
   // which has FixIts available.
-  auto Code = Server.getDocument(Params.textDocument.uri.file());
+  auto Code = DraftMgr.getDraft(Params.textDocument.uri.file());
   if (!Code)
     return replyError(ErrorCode::InvalidParams,
                       "onCodeAction called for non-added file");
 
   json::ary Commands;
   for (Diagnostic &D : Params.context.diagnostics) {
-    auto Edits = getFixIts(Params.textDocument.uri.file(), D);
-    if (!Edits.empty()) {
+    for (auto &F : getFixes(Params.textDocument.uri.file(), D)) {
       WorkspaceEdit WE;
+      std::vector<TextEdit> Edits(F.Edits.begin(), F.Edits.end());
       WE.changes = {{Params.textDocument.uri.uri(), std::move(Edits)}};
       Commands.push_back(json::obj{
-          {"title", llvm::formatv("Apply FixIt {0}", D.message)},
+          {"title", llvm::formatv("Apply fix: {0}", F.Message)},
           {"command", ExecuteCommandParams::CLANGD_APPLY_FIX_COMMAND},
           {"arguments", {WE}},
       });
@@ -329,28 +346,33 @@
 
 void ClangdLSPServer::onCompletion(TextDocumentPositionParams &Params) {
   Server.codeComplete(Params.textDocument.uri.file(), Params.position, CCOpts,
-                      [](Tagged<CompletionList> List) { reply(List.Value); });
+                      [](llvm::Expected<CompletionList> List) {
+                        if (!List)
+                          return replyError(ErrorCode::InvalidParams,
+                                            llvm::toString(List.takeError()));
+                        reply(*List);
+                      });
 }
 
 void ClangdLSPServer::onSignatureHelp(TextDocumentPositionParams &Params) {
   Server.signatureHelp(Params.textDocument.uri.file(), Params.position,
-                       [](llvm::Expected<Tagged<SignatureHelp>> SignatureHelp) {
+                       [](llvm::Expected<SignatureHelp> SignatureHelp) {
                          if (!SignatureHelp)
                            return replyError(
                                ErrorCode::InvalidParams,
                                llvm::toString(SignatureHelp.takeError()));
-                         reply(SignatureHelp->Value);
+                         reply(*SignatureHelp);
                        });
 }
 
 void ClangdLSPServer::onGoToDefinition(TextDocumentPositionParams &Params) {
   Server.findDefinitions(
       Params.textDocument.uri.file(), Params.position,
-      [](llvm::Expected<Tagged<std::vector<Location>>> Items) {
+      [](llvm::Expected<std::vector<Location>> Items) {
         if (!Items)
           return replyError(ErrorCode::InvalidParams,
                             llvm::toString(Items.takeError()));
-        reply(json::ary(Items->Value));
+        reply(json::ary(*Items));
       });
 }
 
@@ -362,24 +384,24 @@
 void ClangdLSPServer::onDocumentHighlight(TextDocumentPositionParams &Params) {
   Server.findDocumentHighlights(
       Params.textDocument.uri.file(), Params.position,
-      [](llvm::Expected<Tagged<std::vector<DocumentHighlight>>> Highlights) {
+      [](llvm::Expected<std::vector<DocumentHighlight>> Highlights) {
         if (!Highlights)
           return replyError(ErrorCode::InternalError,
                             llvm::toString(Highlights.takeError()));
-        reply(json::ary(Highlights->Value));
+        reply(json::ary(*Highlights));
       });
 }
 
 void ClangdLSPServer::onHover(TextDocumentPositionParams &Params) {
   Server.findHover(Params.textDocument.uri.file(), Params.position,
-                   [](llvm::Expected<Tagged<Hover>> H) {
+                   [](llvm::Expected<Hover> H) {
                      if (!H) {
                        replyError(ErrorCode::InternalError,
                                   llvm::toString(H.takeError()));
                        return;
                      }
 
-                     reply(H->Value);
+                     reply(*H);
                    });
 }
 
@@ -391,7 +413,7 @@
   // Compilation database change.
   if (Settings.compilationDatabasePath.hasValue()) {
     CDB.setCompileCommandsDir(Settings.compilationDatabasePath.getValue());
-    Server.reparseOpenedFiles();
+    reparseOpenedFiles();
   }
 }
 
@@ -409,7 +431,7 @@
   JSONRPCDispatcher Dispatcher([](const json::Expr &Params) {
     replyError(ErrorCode::MethodNotFound, "method not found");
   });
-  registerCallbackHandlers(Dispatcher, Out, /*Callbacks=*/*this);
+  registerCallbackHandlers(Dispatcher, /*Callbacks=*/*this);
 
   // Run the Language Server loop.
   runLanguageServerLoop(In, Out, InputStyle, Dispatcher, IsDone);
@@ -421,8 +443,8 @@
   return ShutdownRequestReceived;
 }
 
-std::vector<TextEdit> ClangdLSPServer::getFixIts(StringRef File,
-                                                 const clangd::Diagnostic &D) {
+std::vector<Fix> ClangdLSPServer::getFixes(StringRef File,
+                                           const clangd::Diagnostic &D) {
   std::lock_guard<std::mutex> Lock(FixItsMutex);
   auto DiagToFixItsIter = FixItsMap.find(File);
   if (DiagToFixItsIter == FixItsMap.end())
@@ -436,22 +458,23 @@
   return FixItsIter->second;
 }
 
-void ClangdLSPServer::onDiagnosticsReady(
-    PathRef File, Tagged<std::vector<DiagWithFixIts>> Diagnostics) {
+void ClangdLSPServer::onDiagnosticsReady(PathRef File,
+                                         std::vector<Diag> Diagnostics) {
   json::ary DiagnosticsJSON;
 
   DiagnosticToReplacementMap LocalFixIts; // Temporary storage
-  for (auto &DiagWithFixes : Diagnostics.Value) {
-    auto Diag = DiagWithFixes.Diag;
-    DiagnosticsJSON.push_back(json::obj{
-        {"range", Diag.range},
-        {"severity", Diag.severity},
-        {"message", Diag.message},
+  for (auto &Diag : Diagnostics) {
+    toLSPDiags(Diag, [&](clangd::Diagnostic Diag, llvm::ArrayRef<Fix> Fixes) {
+      DiagnosticsJSON.push_back(json::obj{
+          {"range", Diag.range},
+          {"severity", Diag.severity},
+          {"message", Diag.message},
+      });
+
+      auto &FixItsForDiagnostic = LocalFixIts[Diag];
+      std::copy(Fixes.begin(), Fixes.end(),
+                std::back_inserter(FixItsForDiagnostic));
     });
-    // We convert to Replacements to become independent of the SourceManager.
-    auto &FixItsForDiagnostic = LocalFixIts[Diag];
-    std::copy(DiagWithFixes.FixIts.begin(), DiagWithFixes.FixIts.end(),
-              std::back_inserter(FixItsForDiagnostic));
   }
 
   // Cache FixIts
@@ -472,3 +495,10 @@
        }},
   });
 }
+
+void ClangdLSPServer::reparseOpenedFiles() {
+  for (const Path &FilePath : DraftMgr.getActiveFiles())
+    Server.addDocument(FilePath, *DraftMgr.getDraft(FilePath),
+                       WantDiagnostics::Auto,
+                       /*SkipCache=*/true);
+}
diff --git a/clangd/ClangdLSPServer.h b/clangd/ClangdLSPServer.h
index 30e1746..82cf16f 100644
--- a/clangd/ClangdLSPServer.h
+++ b/clangd/ClangdLSPServer.h
@@ -11,6 +11,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDLSPSERVER_H
 
 #include "ClangdServer.h"
+#include "DraftStore.h"
 #include "GlobalCompilationDatabase.h"
 #include "Path.h"
 #include "Protocol.h"
@@ -46,9 +47,7 @@
 
 private:
   // Implement DiagnosticsConsumer.
-  virtual void
-  onDiagnosticsReady(PathRef File,
-                     Tagged<std::vector<DiagWithFixIts>> Diagnostics) override;
+  void onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) override;
 
   // Implement ProtocolCallbacks.
   void onInitialize(InitializeParams &Params) override;
@@ -74,7 +73,12 @@
   void onHover(TextDocumentPositionParams &Params) override;
   void onChangeConfiguration(DidChangeConfigurationParams &Params) override;
 
-  std::vector<TextEdit> getFixIts(StringRef File, const clangd::Diagnostic &D);
+  std::vector<Fix> getFixes(StringRef File, const clangd::Diagnostic &D);
+
+  /// Forces a reparse of all currently opened files.  As a result, this method
+  /// may be very expensive.  This method is normally called when the
+  /// compilation database is changed.
+  void reparseOpenedFiles();
 
   JSONOutput &Out;
   /// Used to indicate that the 'shutdown' request was received from the
@@ -87,8 +91,7 @@
   bool IsDone = false;
 
   std::mutex FixItsMutex;
-  typedef std::map<clangd::Diagnostic, std::vector<TextEdit>,
-                   LSPDiagnosticCompare>
+  typedef std::map<clangd::Diagnostic, std::vector<Fix>, LSPDiagnosticCompare>
       DiagnosticToReplacementMap;
   /// Caches FixIts per file and diagnostics
   llvm::StringMap<DiagnosticToReplacementMap> FixItsMap;
@@ -99,6 +102,10 @@
   RealFileSystemProvider FSProvider;
   /// Options used for code completion
   clangd::CodeCompleteOptions CCOpts;
+
+  // Store of the current versions of the open documents.
+  DraftStore DraftMgr;
+
   // Server must be the last member of the class to allow its destructor to exit
   // the worker thread that may otherwise run an async callback on partially
   // destructed instance of ClangdLSPServer.
diff --git a/clangd/ClangdServer.cpp b/clangd/ClangdServer.cpp
index 53e3539..dbb3ce4 100644
--- a/clangd/ClangdServer.cpp
+++ b/clangd/ClangdServer.cpp
@@ -65,9 +65,8 @@
 
 } // namespace
 
-Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
-RealFileSystemProvider::getTaggedFileSystem(PathRef File) {
-  return make_tagged(vfs::getRealFileSystem(), VFSTag());
+IntrusiveRefCntPtr<vfs::FileSystem> RealFileSystemProvider::getFileSystem() {
+  return vfs::getRealFileSystem();
 }
 
 ClangdServer::Options ClangdServer::optsForTest() {
@@ -117,115 +116,87 @@
 }
 
 void ClangdServer::addDocument(PathRef File, StringRef Contents,
-                               WantDiagnostics WantDiags) {
-  DocVersion Version = DraftMgr.updateDraft(File, Contents);
-  auto TaggedFS = FSProvider.getTaggedFileSystem(File);
-  scheduleReparseAndDiags(File, VersionedDraft{Version, Contents.str()},
-                          WantDiags, std::move(TaggedFS));
+                               WantDiagnostics WantDiags, bool SkipCache) {
+  if (SkipCache)
+    CompileArgs.invalidate(File);
+
+  DocVersion Version = ++InternalVersion[File];
+  ParseInputs Inputs = {CompileArgs.getCompileCommand(File),
+                        FSProvider.getFileSystem(), Contents.str()};
+
+  Path FileStr = File.str();
+  WorkScheduler.update(File, std::move(Inputs), WantDiags,
+                       [this, FileStr, Version](std::vector<Diag> Diags) {
+                         consumeDiagnostics(FileStr, Version, std::move(Diags));
+                       });
 }
 
 void ClangdServer::removeDocument(PathRef File) {
-  DraftMgr.removeDraft(File);
+  ++InternalVersion[File];
   CompileArgs.invalidate(File);
   WorkScheduler.remove(File);
 }
 
-void ClangdServer::forceReparse(PathRef File) {
-  auto FileContents = DraftMgr.getDraft(File);
-  assert(FileContents.Draft &&
-         "forceReparse() was called for non-added document");
-
-  // forceReparse promises to request new compilation flags from CDB, so we
-  // remove any cahced flags.
-  CompileArgs.invalidate(File);
-
-  auto TaggedFS = FSProvider.getTaggedFileSystem(File);
-  scheduleReparseAndDiags(File, std::move(FileContents), WantDiagnostics::Yes,
-                          std::move(TaggedFS));
-}
-
-void ClangdServer::codeComplete(
-    PathRef File, Position Pos, const clangd::CodeCompleteOptions &Opts,
-    UniqueFunction<void(Tagged<CompletionList>)> Callback,
-    IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS) {
-  using CallbackType = UniqueFunction<void(Tagged<CompletionList>)>;
-
-  auto TaggedFS = FSProvider.getTaggedFileSystem(File);
-  if (UsedFS)
-    *UsedFS = TaggedFS.Value;
-
+void ClangdServer::codeComplete(PathRef File, Position Pos,
+                                const clangd::CodeCompleteOptions &Opts,
+                                Callback<CompletionList> CB) {
   // Copy completion options for passing them to async task handler.
   auto CodeCompleteOpts = Opts;
   if (!CodeCompleteOpts.Index) // Respect overridden index.
     CodeCompleteOpts.Index = Index;
 
-  VersionedDraft Latest = DraftMgr.getDraft(File);
-  // FIXME(sammccall): return error for consistency?
-  assert(Latest.Draft && "codeComplete called for non-added document");
-
   // Copy PCHs to avoid accessing this->PCHs concurrently
   std::shared_ptr<PCHContainerOperations> PCHs = this->PCHs;
-  auto Task = [PCHs, Pos, TaggedFS, CodeCompleteOpts](
-                  std::string Contents, Path File, CallbackType Callback,
-                  llvm::Expected<InputsAndPreamble> IP) {
-    assert(IP && "error when trying to read preamble for codeComplete");
+  auto FS = FSProvider.getFileSystem();
+  auto Task = [PCHs, Pos, FS,
+               CodeCompleteOpts](Path File, Callback<CompletionList> CB,
+                                 llvm::Expected<InputsAndPreamble> IP) {
+    if (!IP)
+      return CB(IP.takeError());
+
     auto PreambleData = IP->Preamble;
-    auto &Command = IP->Inputs.CompileCommand;
 
     // FIXME(ibiryukov): even if Preamble is non-null, we may want to check
     // both the old and the new version in case only one of them matches.
     CompletionList Result = clangd::codeComplete(
-        File, Command, PreambleData ? &PreambleData->Preamble : nullptr,
-        Contents, Pos, TaggedFS.Value, PCHs, CodeCompleteOpts);
-
-    Callback(make_tagged(std::move(Result), std::move(TaggedFS.Tag)));
+        File, IP->Command, PreambleData ? &PreambleData->Preamble : nullptr,
+        IP->Contents, Pos, FS, PCHs, CodeCompleteOpts);
+    CB(std::move(Result));
   };
 
-  WorkScheduler.runWithPreamble(
-      "CodeComplete", File,
-      Bind(Task, std::move(*Latest.Draft), File.str(), std::move(Callback)));
+  WorkScheduler.runWithPreamble("CodeComplete", File,
+                                Bind(Task, File.str(), std::move(CB)));
 }
 
-void ClangdServer::signatureHelp(
-    PathRef File, Position Pos,
-    UniqueFunction<void(llvm::Expected<Tagged<SignatureHelp>>)> Callback,
-    IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS) {
-  auto TaggedFS = FSProvider.getTaggedFileSystem(File);
-  if (UsedFS)
-    *UsedFS = TaggedFS.Value;
-
-  VersionedDraft Latest = DraftMgr.getDraft(File);
-  if (!Latest.Draft)
-    return Callback(llvm::make_error<llvm::StringError>(
-        "signatureHelp is called for non-added document",
-        llvm::errc::invalid_argument));
+void ClangdServer::signatureHelp(PathRef File, Position Pos,
+                                 Callback<SignatureHelp> CB) {
 
   auto PCHs = this->PCHs;
-  auto Action = [Pos, TaggedFS, PCHs](std::string Contents, Path File,
-                                      decltype(Callback) Callback,
-                                      llvm::Expected<InputsAndPreamble> IP) {
+  auto FS = FSProvider.getFileSystem();
+  auto Action = [Pos, FS, PCHs](Path File, Callback<SignatureHelp> CB,
+                                llvm::Expected<InputsAndPreamble> IP) {
     if (!IP)
-      return Callback(IP.takeError());
+      return CB(IP.takeError());
 
     auto PreambleData = IP->Preamble;
-    auto &Command = IP->Inputs.CompileCommand;
-    Callback(make_tagged(
-        clangd::signatureHelp(File, Command,
-                              PreambleData ? &PreambleData->Preamble : nullptr,
-                              Contents, Pos, TaggedFS.Value, PCHs),
-        TaggedFS.Tag));
+    CB(clangd::signatureHelp(File, IP->Command,
+                             PreambleData ? &PreambleData->Preamble : nullptr,
+                             IP->Contents, Pos, FS, PCHs));
   };
 
-  WorkScheduler.runWithPreamble(
-      "SignatureHelp", File,
-      Bind(Action, std::move(*Latest.Draft), File.str(), std::move(Callback)));
+  WorkScheduler.runWithPreamble("SignatureHelp", File,
+                                Bind(Action, File.str(), std::move(CB)));
 }
 
 llvm::Expected<tooling::Replacements>
 ClangdServer::formatRange(StringRef Code, PathRef File, Range Rng) {
-  size_t Begin = positionToOffset(Code, Rng.start);
-  size_t Len = positionToOffset(Code, Rng.end) - Begin;
-  return formatCode(Code, File, {tooling::Range(Begin, Len)});
+  llvm::Expected<size_t> Begin = positionToOffset(Code, Rng.start);
+  if (!Begin)
+    return Begin.takeError();
+  llvm::Expected<size_t> End = positionToOffset(Code, Rng.end);
+  if (!End)
+    return End.takeError();
+  return formatCode(Code, File, {tooling::Range(*Begin, *End - *Begin)});
 }
 
 llvm::Expected<tooling::Replacements> ClangdServer::formatFile(StringRef Code,
@@ -238,24 +209,24 @@
 ClangdServer::formatOnType(StringRef Code, PathRef File, Position Pos) {
   // Look for the previous opening brace from the character position and
   // format starting from there.
-  size_t CursorPos = positionToOffset(Code, Pos);
-  size_t PreviousLBracePos = StringRef(Code).find_last_of('{', CursorPos);
+  llvm::Expected<size_t> CursorPos = positionToOffset(Code, Pos);
+  if (!CursorPos)
+    return CursorPos.takeError();
+  size_t PreviousLBracePos = StringRef(Code).find_last_of('{', *CursorPos);
   if (PreviousLBracePos == StringRef::npos)
-    PreviousLBracePos = CursorPos;
-  size_t Len = CursorPos - PreviousLBracePos;
+    PreviousLBracePos = *CursorPos;
+  size_t Len = *CursorPos - PreviousLBracePos;
 
   return formatCode(Code, File, {tooling::Range(PreviousLBracePos, Len)});
 }
 
-void ClangdServer::rename(
-    PathRef File, Position Pos, llvm::StringRef NewName,
-    UniqueFunction<void(Expected<std::vector<tooling::Replacement>>)>
-        Callback) {
+void ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName,
+                          Callback<std::vector<tooling::Replacement>> CB) {
   auto Action = [Pos](Path File, std::string NewName,
-                      decltype(Callback) Callback,
+                      Callback<std::vector<tooling::Replacement>> CB,
                       Expected<InputsAndAST> InpAST) {
     if (!InpAST)
-      return Callback(InpAST.takeError());
+      return CB(InpAST.takeError());
     auto &AST = InpAST->AST;
 
     RefactoringResultCollector ResultCollector;
@@ -263,7 +234,7 @@
     const FileEntry *FE =
         SourceMgr.getFileEntryForID(SourceMgr.getMainFileID());
     if (!FE)
-      return Callback(llvm::make_error<llvm::StringError>(
+      return CB(llvm::make_error<llvm::StringError>(
           "rename called for non-added document",
           llvm::errc::invalid_argument));
     SourceLocation SourceLocationBeg =
@@ -274,13 +245,13 @@
     auto Rename = clang::tooling::RenameOccurrences::initiate(
         Context, SourceRange(SourceLocationBeg), NewName);
     if (!Rename)
-      return Callback(Rename.takeError());
+      return CB(Rename.takeError());
 
     Rename->invoke(ResultCollector, Context);
 
     assert(ResultCollector.Result.hasValue());
     if (!ResultCollector.Result.getValue())
-      return Callback(ResultCollector.Result->takeError());
+      return CB(ResultCollector.Result->takeError());
 
     std::vector<tooling::Replacement> Replacements;
     for (const tooling::AtomicChange &Change : ResultCollector.Result->get()) {
@@ -299,12 +270,11 @@
           Replacements.push_back(Rep);
       }
     }
-    return Callback(Replacements);
+    return CB(std::move(Replacements));
   };
 
   WorkScheduler.runWithAST(
-      "Rename", File,
-      Bind(Action, File.str(), NewName.str(), std::move(Callback)));
+      "Rename", File, Bind(Action, File.str(), NewName.str(), std::move(CB)));
 }
 
 /// Creates a `HeaderFile` from \p Header which can be either a URI or a literal
@@ -335,9 +305,9 @@
   if (!ResolvedPreferred)
     return ResolvedPreferred.takeError();
   tooling::CompileCommand CompileCommand = CompileArgs.getCompileCommand(File);
-  auto Include = calculateIncludePath(
-      File, Code, *ResolvedOrginal, *ResolvedPreferred, CompileCommand,
-      FSProvider.getTaggedFileSystem(File).Value);
+  auto Include =
+      calculateIncludePath(File, Code, *ResolvedOrginal, *ResolvedPreferred,
+                           CompileCommand, FSProvider.getFileSystem());
   if (!Include)
     return Include.takeError();
   if (Include->empty())
@@ -353,20 +323,13 @@
   // Replacement with offset UINT_MAX and length 0 will be treated as include
   // insertion.
   tooling::Replacement R(File, /*Offset=*/UINT_MAX, 0, "#include " + ToInclude);
-  auto Replaces = format::cleanupAroundReplacements(
-      Code, tooling::Replacements(R), *Style);
+  auto Replaces =
+      format::cleanupAroundReplacements(Code, tooling::Replacements(R), *Style);
   if (!Replaces)
     return Replaces;
   return formatReplacements(Code, *Replaces, *Style);
 }
 
-llvm::Optional<std::string> ClangdServer::getDocument(PathRef File) {
-  auto Latest = DraftMgr.getDraft(File);
-  if (!Latest.Draft)
-    return llvm::None;
-  return std::move(*Latest.Draft);
-}
-
 void ClangdServer::dumpAST(PathRef File,
                            UniqueFunction<void(std::string)> Callback) {
   auto Action = [](decltype(Callback) Callback,
@@ -387,21 +350,17 @@
   WorkScheduler.runWithAST("DumpAST", File, Bind(Action, std::move(Callback)));
 }
 
-void ClangdServer::findDefinitions(
-    PathRef File, Position Pos,
-    UniqueFunction<void(llvm::Expected<Tagged<std::vector<Location>>>)>
-        Callback) {
-  auto TaggedFS = FSProvider.getTaggedFileSystem(File);
-  auto Action = [Pos, TaggedFS](decltype(Callback) Callback,
-                                llvm::Expected<InputsAndAST> InpAST) {
+void ClangdServer::findDefinitions(PathRef File, Position Pos,
+                                   Callback<std::vector<Location>> CB) {
+  auto FS = FSProvider.getFileSystem();
+  auto Action = [Pos, FS](Callback<std::vector<Location>> CB,
+                          llvm::Expected<InputsAndAST> InpAST) {
     if (!InpAST)
-      return Callback(InpAST.takeError());
-    auto Result = clangd::findDefinitions(InpAST->AST, Pos);
-    Callback(make_tagged(std::move(Result), TaggedFS.Tag));
+      return CB(InpAST.takeError());
+    CB(clangd::findDefinitions(InpAST->AST, Pos));
   };
 
-  WorkScheduler.runWithAST("Definitions", File,
-                           Bind(Action, std::move(Callback)));
+  WorkScheduler.runWithAST("Definitions", File, Bind(Action, std::move(CB)));
 }
 
 llvm::Optional<Path> ClangdServer::switchSourceHeader(PathRef Path) {
@@ -444,7 +403,7 @@
   SmallString<128> NewPath = StringRef(Path);
 
   // Instance of vfs::FileSystem, used for file existence checks.
-  auto FS = FSProvider.getTaggedFileSystem(Path).Value;
+  auto FS = FSProvider.getFileSystem();
 
   // Loop through switched extension candidates.
   for (StringRef NewExt : NewExts) {
@@ -467,9 +426,8 @@
 ClangdServer::formatCode(llvm::StringRef Code, PathRef File,
                          ArrayRef<tooling::Range> Ranges) {
   // Call clang-format.
-  auto TaggedFS = FSProvider.getTaggedFileSystem(File);
-  auto Style =
-      format::getStyle("file", File, "LLVM", Code, TaggedFS.Value.get());
+  auto FS = FSProvider.getFileSystem();
+  auto Style = format::getStyle("file", File, "LLVM", Code, FS.get());
   if (!Style)
     return Style.takeError();
 
@@ -486,89 +444,47 @@
 }
 
 void ClangdServer::findDocumentHighlights(
-    PathRef File, Position Pos,
-    UniqueFunction<void(llvm::Expected<Tagged<std::vector<DocumentHighlight>>>)>
-        Callback) {
-  auto FileContents = DraftMgr.getDraft(File);
-  if (!FileContents.Draft)
-    return Callback(llvm::make_error<llvm::StringError>(
-        "findDocumentHighlights called on non-added file",
-        llvm::errc::invalid_argument));
+    PathRef File, Position Pos, Callback<std::vector<DocumentHighlight>> CB) {
 
-  auto TaggedFS = FSProvider.getTaggedFileSystem(File);
-
-  auto Action = [TaggedFS, Pos](decltype(Callback) Callback,
-                                llvm::Expected<InputsAndAST> InpAST) {
+  auto FS = FSProvider.getFileSystem();
+  auto Action = [FS, Pos](Callback<std::vector<DocumentHighlight>> CB,
+                          llvm::Expected<InputsAndAST> InpAST) {
     if (!InpAST)
-      return Callback(InpAST.takeError());
-    auto Result = clangd::findDocumentHighlights(InpAST->AST, Pos);
-    Callback(make_tagged(std::move(Result), TaggedFS.Tag));
+      return CB(InpAST.takeError());
+    CB(clangd::findDocumentHighlights(InpAST->AST, Pos));
   };
 
-  WorkScheduler.runWithAST("Highlights", File,
-                           Bind(Action, std::move(Callback)));
+  WorkScheduler.runWithAST("Highlights", File, Bind(Action, std::move(CB)));
 }
 
-void ClangdServer::findHover(
-    PathRef File, Position Pos,
-    UniqueFunction<void(llvm::Expected<Tagged<Hover>>)> Callback) {
-  Hover FinalHover;
-  auto FileContents = DraftMgr.getDraft(File);
-  if (!FileContents.Draft)
-    return Callback(llvm::make_error<llvm::StringError>(
-        "findHover called on non-added file", llvm::errc::invalid_argument));
-
-  auto TaggedFS = FSProvider.getTaggedFileSystem(File);
-
-  auto Action = [Pos, TaggedFS](decltype(Callback) Callback,
-                                llvm::Expected<InputsAndAST> InpAST) {
+void ClangdServer::findHover(PathRef File, Position Pos, Callback<Hover> CB) {
+  auto FS = FSProvider.getFileSystem();
+  auto Action = [Pos, FS](Callback<Hover> CB,
+                          llvm::Expected<InputsAndAST> InpAST) {
     if (!InpAST)
-      return Callback(InpAST.takeError());
-
-    Hover Result = clangd::getHover(InpAST->AST, Pos);
-    Callback(make_tagged(std::move(Result), TaggedFS.Tag));
+      return CB(InpAST.takeError());
+    CB(clangd::getHover(InpAST->AST, Pos));
   };
 
-  WorkScheduler.runWithAST("Hover", File, Bind(Action, std::move(Callback)));
+  WorkScheduler.runWithAST("Hover", File, Bind(Action, std::move(CB)));
 }
 
-void ClangdServer::scheduleReparseAndDiags(
-    PathRef File, VersionedDraft Contents, WantDiagnostics WantDiags,
-    Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS) {
-  tooling::CompileCommand Command = CompileArgs.getCompileCommand(File);
+void ClangdServer::consumeDiagnostics(PathRef File, DocVersion Version,
+                                      std::vector<Diag> Diags) {
+  // We need to serialize access to resulting diagnostics to avoid calling
+  // `onDiagnosticsReady` in the wrong order.
+  std::lock_guard<std::mutex> DiagsLock(DiagnosticsMutex);
+  DocVersion &LastReportedDiagsVersion = ReportedDiagnosticVersions[File];
 
-  DocVersion Version = Contents.Version;
-  Path FileStr = File.str();
-  VFSTag Tag = std::move(TaggedFS.Tag);
+  // FIXME(ibiryukov): get rid of '<' comparison here. In the current
+  // implementation diagnostics will not be reported after version counters'
+  // overflow. This should not happen in practice, since DocVersion is a
+  // 64-bit unsigned integer.
+  if (Version < LastReportedDiagsVersion)
+    return;
+  LastReportedDiagsVersion = Version;
 
-  auto Callback = [this, Version, FileStr,
-                   Tag](std::vector<DiagWithFixIts> Diags) {
-    // We need to serialize access to resulting diagnostics to avoid calling
-    // `onDiagnosticsReady` in the wrong order.
-    std::lock_guard<std::mutex> DiagsLock(DiagnosticsMutex);
-    DocVersion &LastReportedDiagsVersion = ReportedDiagnosticVersions[FileStr];
-    // FIXME(ibiryukov): get rid of '<' comparison here. In the current
-    // implementation diagnostics will not be reported after version counters'
-    // overflow. This should not happen in practice, since DocVersion is a
-    // 64-bit unsigned integer.
-    if (Version < LastReportedDiagsVersion)
-      return;
-    LastReportedDiagsVersion = Version;
-
-    DiagConsumer.onDiagnosticsReady(
-        FileStr, make_tagged(std::move(Diags), std::move(Tag)));
-  };
-
-  WorkScheduler.update(File,
-                       ParseInputs{std::move(Command),
-                                   std::move(TaggedFS.Value),
-                                   std::move(*Contents.Draft)},
-                       WantDiags, std::move(Callback));
-}
-
-void ClangdServer::reparseOpenedFiles() {
-  for (const Path &FilePath : DraftMgr.getActiveFiles())
-    forceReparse(FilePath);
+  DiagConsumer.onDiagnosticsReady(File, std::move(Diags));
 }
 
 void ClangdServer::onFileEvent(const DidChangeWatchedFilesParams &Params) {
diff --git a/clangd/ClangdServer.h b/clangd/ClangdServer.h
index 5e10c24..34af4b9 100644
--- a/clangd/ClangdServer.h
+++ b/clangd/ClangdServer.h
@@ -13,7 +13,6 @@
 #include "ClangdUnit.h"
 #include "CodeComplete.h"
 #include "CompileArgsCache.h"
-#include "DraftStore.h"
 #include "Function.h"
 #include "GlobalCompilationDatabase.h"
 #include "Protocol.h"
@@ -35,64 +34,29 @@
 
 namespace clangd {
 
-/// A tag supplied by the FileSytemProvider.
-typedef std::string VFSTag;
-
-/// A value of an arbitrary type and VFSTag that was supplied by the
-/// FileSystemProvider when this value was computed.
-template <class T> class Tagged {
-public:
-  // MSVC requires future<> arguments to be default-constructible.
-  Tagged() = default;
-
-  template <class U>
-  Tagged(U &&Value, VFSTag Tag)
-      : Value(std::forward<U>(Value)), Tag(std::move(Tag)) {}
-
-  template <class U>
-  Tagged(const Tagged<U> &Other) : Value(Other.Value), Tag(Other.Tag) {}
-
-  template <class U>
-  Tagged(Tagged<U> &&Other)
-      : Value(std::move(Other.Value)), Tag(std::move(Other.Tag)) {}
-
-  T Value = T();
-  VFSTag Tag = VFSTag();
-};
-
-template <class T>
-Tagged<typename std::decay<T>::type> make_tagged(T &&Value, VFSTag Tag) {
-  return Tagged<typename std::decay<T>::type>(std::forward<T>(Value), Tag);
-}
-
 class DiagnosticsConsumer {
 public:
   virtual ~DiagnosticsConsumer() = default;
 
   /// Called by ClangdServer when \p Diagnostics for \p File are ready.
-  virtual void
-  onDiagnosticsReady(PathRef File,
-                     Tagged<std::vector<DiagWithFixIts>> Diagnostics) = 0;
+  virtual void onDiagnosticsReady(PathRef File,
+                                  std::vector<Diag> Diagnostics) = 0;
 };
 
 class FileSystemProvider {
 public:
   virtual ~FileSystemProvider() = default;
   /// Called by ClangdServer to obtain a vfs::FileSystem to be used for parsing.
-  /// Name of the file that will be parsed is passed in \p File.
-  ///
-  /// \return A filesystem that will be used for all file accesses in clangd.
-  /// A Tag returned by this method will be propagated to all results of clangd
-  /// that will use this filesystem.
-  virtual Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
-  getTaggedFileSystem(PathRef File) = 0;
+  /// Context::current() will be the context passed to the clang entrypoint,
+  /// such as addDocument(), and will also be propagated to result callbacks.
+  /// Embedders may use this to isolate filesystem accesses.
+  virtual IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() = 0;
 };
 
 class RealFileSystemProvider : public FileSystemProvider {
 public:
-  /// \return getRealFileSystem() tagged with default tag, i.e. VFSTag()
-  Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
-  getTaggedFileSystem(PathRef File) override;
+  /// Returns getRealFileSystem().
+  IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() override;
 };
 
 /// Provides API to manage ASTs for a collection of C++ files and request
@@ -138,10 +102,6 @@
   /// those arguments for subsequent reparses. However, ClangdServer will check
   /// if compilation arguments changed on calls to forceReparse().
   ///
-  /// FSProvider provides a vfs::FileSystem for each parsing request. Results of
-  /// code completion and diagnostics also include a tag, that \p FSProvider
-  /// returns along with the vfs::FileSystem.
-  ///
   /// After each parsing request finishes, ClangdServer reports diagnostics to
   /// \p DiagConsumer. Note that a callback to \p DiagConsumer happens on a
   /// worker thread. Therefore, instances of \p DiagConsumer must properly
@@ -156,30 +116,19 @@
   /// \p File is already tracked. Also schedules parsing of the AST for it on a
   /// separate thread. When the parsing is complete, DiagConsumer passed in
   /// constructor will receive onDiagnosticsReady callback.
+  /// When \p SkipCache is true, compile commands will always be requested from
+  /// compilation database even if they were cached in previous invocations.
   void addDocument(PathRef File, StringRef Contents,
-                   WantDiagnostics WD = WantDiagnostics::Auto);
+                   WantDiagnostics WD = WantDiagnostics::Auto,
+                   bool SkipCache = false);
 
   /// Remove \p File from list of tracked files, schedule a request to free
   /// resources associated with it.
   void removeDocument(PathRef File);
 
-  /// Force \p File to be reparsed using the latest contents.
-  /// Will also check if CompileCommand, provided by GlobalCompilationDatabase
-  /// for \p File has changed. If it has, will remove currently stored Preamble
-  /// and AST and rebuild them from scratch.
-  void forceReparse(PathRef File);
-
-  /// Calls forceReparse() on all currently opened files.
-  /// As a result, this method may be very expensive.
-  /// This method is normally called when the compilation database is changed.
-  void reparseOpenedFiles();
-
   /// Run code completion for \p File at \p Pos.
   /// Request is processed asynchronously.
   ///
-  /// The current draft for \p File will be used. If \p UsedFS is non-null, it
-  /// will be overwritten by vfs::FileSystem used for completion.
-  ///
   /// This method should only be called for currently tracked files. However, it
   /// is safe to call removeDocument for \p File after this method returns, even
   /// while returned future is not yet ready.
@@ -187,39 +136,26 @@
   /// when codeComplete results become available.
   void codeComplete(PathRef File, Position Pos,
                     const clangd::CodeCompleteOptions &Opts,
-                    UniqueFunction<void(Tagged<CompletionList>)> Callback,
-                    IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
+                    Callback<CompletionList> CB);
 
-  /// Provide signature help for \p File at \p Pos. If \p OverridenContents is
-  /// not None, they will used only for signature help, i.e. no diagnostics
-  /// update will be scheduled and a draft for \p File will not be updated. If
-  /// If \p UsedFS is non-null, it will be overwritten by vfs::FileSystem used
-  /// for signature help. This method should only be called for tracked files.
-  void signatureHelp(
-      PathRef File, Position Pos,
-      UniqueFunction<void(llvm::Expected<Tagged<SignatureHelp>>)> Callback,
-      IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
+  /// Provide signature help for \p File at \p Pos.  This method should only be
+  /// called for tracked files.
+  void signatureHelp(PathRef File, Position Pos, Callback<SignatureHelp> CB);
 
   /// Get definition of symbol at a specified \p Line and \p Column in \p File.
-  void findDefinitions(
-      PathRef File, Position Pos,
-      UniqueFunction<void(llvm::Expected<Tagged<std::vector<Location>>>)>
-          Callback);
+  void findDefinitions(PathRef File, Position Pos,
+                       Callback<std::vector<Location>> CB);
 
   /// Helper function that returns a path to the corresponding source file when
   /// given a header file and vice versa.
   llvm::Optional<Path> switchSourceHeader(PathRef Path);
 
   /// Get document highlights for a given position.
-  void findDocumentHighlights(
-      PathRef File, Position Pos,
-      UniqueFunction<
-          void(llvm::Expected<Tagged<std::vector<DocumentHighlight>>>)>
-          Callback);
+  void findDocumentHighlights(PathRef File, Position Pos,
+                              Callback<std::vector<DocumentHighlight>> CB);
 
   /// Get code hover for a given position.
-  void findHover(PathRef File, Position Pos,
-                 UniqueFunction<void(llvm::Expected<Tagged<Hover>>)> Callback);
+  void findHover(PathRef File, Position Pos, Callback<Hover> CB);
 
   /// Run formatting for \p Rng inside \p File with content \p Code.
   llvm::Expected<tooling::Replacements> formatRange(StringRef Code,
@@ -237,8 +173,7 @@
   /// Rename all occurrences of the symbol at the \p Pos in \p File to
   /// \p NewName.
   void rename(PathRef File, Position Pos, llvm::StringRef NewName,
-              UniqueFunction<void(Expected<std::vector<tooling::Replacement>>)>
-                  Callback);
+              Callback<std::vector<tooling::Replacement>> CB);
 
   /// Inserts a new #include into \p File, if it's not present in \p Code.
   ///
@@ -256,12 +191,6 @@
                                                 StringRef DeclaringHeader,
                                                 StringRef InsertedHeader);
 
-  /// Gets current document contents for \p File. Returns None if \p File is not
-  /// currently tracked.
-  /// FIXME(ibiryukov): This function is here to allow offset-to-Position
-  /// conversions in outside code, maybe there's a way to get rid of it.
-  llvm::Optional<std::string> getDocument(PathRef File);
-
   /// Only for testing purposes.
   /// Waits until all requests to worker thread are finished and dumps AST for
   /// \p File. \p File must be in the list of added documents.
@@ -290,15 +219,18 @@
   formatCode(llvm::StringRef Code, PathRef File,
              ArrayRef<tooling::Range> Ranges);
 
-  void
-  scheduleReparseAndDiags(PathRef File, VersionedDraft Contents,
-                          WantDiagnostics WD,
-                          Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS);
+  typedef uint64_t DocVersion;
+
+  void consumeDiagnostics(PathRef File, DocVersion Version,
+                          std::vector<Diag> Diags);
 
   CompileArgsCache CompileArgs;
   DiagnosticsConsumer &DiagConsumer;
   FileSystemProvider &FSProvider;
-  DraftStore DraftMgr;
+
+  /// Used to synchronize diagnostic responses for added and removed files.
+  llvm::StringMap<DocVersion> InternalVersion;
+
   // The index used to look up symbols. This could be:
   //   - null (all index functionality is optional)
   //   - the dynamic index owned by ClangdServer (FileIdx)
diff --git a/clangd/ClangdUnit.cpp b/clangd/ClangdUnit.cpp
index 4ad95c4..b20ca8e 100644
--- a/clangd/ClangdUnit.cpp
+++ b/clangd/ClangdUnit.cpp
@@ -9,7 +9,9 @@
 
 #include "ClangdUnit.h"
 #include "Compiler.h"
+#include "Diagnostics.h"
 #include "Logger.h"
+#include "SourceCode.h"
 #include "Trace.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/CompilerInvocation.h"
@@ -81,22 +83,6 @@
   std::vector<const Decl *> TopLevelDecls;
 };
 
-// Converts a half-open clang source range to an LSP range.
-// Note that clang also uses closed source ranges, which this can't handle!
-Range toRange(CharSourceRange R, const SourceManager &M) {
-  // Clang is 1-based, LSP uses 0-based indexes.
-  Position Begin;
-  Begin.line = static_cast<int>(M.getSpellingLineNumber(R.getBegin())) - 1;
-  Begin.character =
-      static_cast<int>(M.getSpellingColumnNumber(R.getBegin())) - 1;
-
-  Position End;
-  End.line = static_cast<int>(M.getSpellingLineNumber(R.getEnd())) - 1;
-  End.character = static_cast<int>(M.getSpellingColumnNumber(R.getEnd())) - 1;
-
-  return {Begin, End};
-}
-
 class InclusionLocationsCollector : public PPCallbacks {
 public:
   InclusionLocationsCollector(SourceManager &SourceMgr,
@@ -115,7 +101,7 @@
     if (SourceMgr.isInMainFile(SR.getBegin())) {
       // Only inclusion directives in the main file make sense. The user cannot
       // select directives not in the main file.
-      IncLocations.emplace_back(toRange(FilenameRange, SourceMgr),
+      IncLocations.emplace_back(halfOpenToRange(SourceMgr, FilenameRange),
                                 File->tryGetRealPathName());
     }
   }
@@ -170,113 +156,6 @@
   SourceManager *SourceMgr = nullptr;
 };
 
-/// Convert from clang diagnostic level to LSP severity.
-static int getSeverity(DiagnosticsEngine::Level L) {
-  switch (L) {
-  case DiagnosticsEngine::Remark:
-    return 4;
-  case DiagnosticsEngine::Note:
-    return 3;
-  case DiagnosticsEngine::Warning:
-    return 2;
-  case DiagnosticsEngine::Fatal:
-  case DiagnosticsEngine::Error:
-    return 1;
-  case DiagnosticsEngine::Ignored:
-    return 0;
-  }
-  llvm_unreachable("Unknown diagnostic level!");
-}
-
-// Checks whether a location is within a half-open range.
-// Note that clang also uses closed source ranges, which this can't handle!
-bool locationInRange(SourceLocation L, CharSourceRange R,
-                     const SourceManager &M) {
-  assert(R.isCharRange());
-  if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
-      M.getFileID(R.getBegin()) != M.getFileID(L))
-    return false;
-  return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
-}
-
-// Clang diags have a location (shown as ^) and 0 or more ranges (~~~~).
-// LSP needs a single range.
-Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) {
-  auto &M = D.getSourceManager();
-  auto Loc = M.getFileLoc(D.getLocation());
-  // Accept the first range that contains the location.
-  for (const auto &CR : D.getRanges()) {
-    auto R = Lexer::makeFileCharRange(CR, M, L);
-    if (locationInRange(Loc, R, M))
-      return toRange(R, M);
-  }
-  // The range may be given as a fixit hint instead.
-  for (const auto &F : D.getFixItHints()) {
-    auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L);
-    if (locationInRange(Loc, R, M))
-      return toRange(R, M);
-  }
-  // If no suitable range is found, just use the token at the location.
-  auto R = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Loc), M, L);
-  if (!R.isValid()) // Fall back to location only, let the editor deal with it.
-    R = CharSourceRange::getCharRange(Loc);
-  return toRange(R, M);
-}
-
-TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M,
-                    const LangOptions &L) {
-  TextEdit Result;
-  Result.range = toRange(Lexer::makeFileCharRange(FixIt.RemoveRange, M, L), M);
-  Result.newText = FixIt.CodeToInsert;
-  return Result;
-}
-
-llvm::Optional<DiagWithFixIts> toClangdDiag(const clang::Diagnostic &D,
-                                            DiagnosticsEngine::Level Level,
-                                            const LangOptions &LangOpts) {
-  if (!D.hasSourceManager() || !D.getLocation().isValid() ||
-      !D.getSourceManager().isInMainFile(D.getLocation())) {
-    IgnoreDiagnostics::log(Level, D);
-    return llvm::None;
-  }
-
-  SmallString<64> Message;
-  D.FormatDiagnostic(Message);
-
-  DiagWithFixIts Result;
-  Result.Diag.range = diagnosticRange(D, LangOpts);
-  Result.Diag.severity = getSeverity(Level);
-  Result.Diag.message = Message.str();
-  for (const FixItHint &Fix : D.getFixItHints())
-    Result.FixIts.push_back(toTextEdit(Fix, D.getSourceManager(), LangOpts));
-  return std::move(Result);
-}
-
-class StoreDiagsConsumer : public DiagnosticConsumer {
-public:
-  StoreDiagsConsumer(std::vector<DiagWithFixIts> &Output) : Output(Output) {}
-
-  // Track language options in case we need to expand token ranges.
-  void BeginSourceFile(const LangOptions &Opts, const Preprocessor *) override {
-    LangOpts = Opts;
-  }
-
-  void EndSourceFile() override { LangOpts = llvm::None; }
-
-  void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
-                        const clang::Diagnostic &Info) override {
-    DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
-
-    if (LangOpts)
-      if (auto D = toClangdDiag(Info, DiagLevel, *LangOpts))
-        Output.push_back(std::move(*D));
-  }
-
-private:
-  std::vector<DiagWithFixIts> &Output;
-  llvm::Optional<LangOptions> LangOpts;
-};
-
 } // namespace
 
 void clangd::dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) {
@@ -289,14 +168,13 @@
                  std::unique_ptr<llvm::MemoryBuffer> Buffer,
                  std::shared_ptr<PCHContainerOperations> PCHs,
                  IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
-  std::vector<DiagWithFixIts> ASTDiags;
-  StoreDiagsConsumer UnitDiagsConsumer(/*ref*/ ASTDiags);
-
   const PrecompiledPreamble *PreamblePCH =
       Preamble ? &Preamble->Preamble : nullptr;
-  auto Clang = prepareCompilerInstance(
-      std::move(CI), PreamblePCH, std::move(Buffer), std::move(PCHs),
-      std::move(VFS), /*ref*/ UnitDiagsConsumer);
+
+  StoreDiags ASTDiags;
+  auto Clang =
+      prepareCompilerInstance(std::move(CI), PreamblePCH, std::move(Buffer),
+                              std::move(PCHs), std::move(VFS), ASTDiags);
   if (!Clang)
     return llvm::None;
 
@@ -328,10 +206,12 @@
   // UnitDiagsConsumer is local, we can not store it in CompilerInstance that
   // has a longer lifetime.
   Clang->getDiagnostics().setClient(new IgnoreDiagnostics);
+  // CompilerInstance won't run this callback, do it directly.
+  ASTDiags.EndSourceFile();
 
   std::vector<const Decl *> ParsedDecls = Action->takeTopLevelDecls();
   return ParsedAST(std::move(Preamble), std::move(Clang), std::move(Action),
-                   std::move(ParsedDecls), std::move(ASTDiags),
+                   std::move(ParsedDecls), ASTDiags.take(),
                    std::move(IncLocations));
 }
 
@@ -399,14 +279,12 @@
   return TopLevelDecls;
 }
 
-const std::vector<DiagWithFixIts> &ParsedAST::getDiagnostics() const {
-  return Diags;
-}
+const std::vector<Diag> &ParsedAST::getDiagnostics() const { return Diags; }
 
 std::size_t ParsedAST::getUsedBytes() const {
   auto &AST = getASTContext();
   // FIXME(ibiryukov): we do not account for the dynamically allocated part of
-  // SmallVector<FixIt> inside each Diag.
+  // Message and Fixes inside each diagnostic.
   return AST.getASTAllocatedMemory() + AST.getSideTableAllocatedMemory() +
          ::getUsedBytes(TopLevelDecls) + ::getUsedBytes(Diags);
 }
@@ -417,7 +295,7 @@
 
 PreambleData::PreambleData(PrecompiledPreamble Preamble,
                            std::vector<serialization::DeclID> TopLevelDeclIDs,
-                           std::vector<DiagWithFixIts> Diags,
+                           std::vector<Diag> Diags,
                            InclusionLocations IncLocations)
     : Preamble(std::move(Preamble)),
       TopLevelDeclIDs(std::move(TopLevelDeclIDs)), Diags(std::move(Diags)),
@@ -427,8 +305,7 @@
                      std::unique_ptr<CompilerInstance> Clang,
                      std::unique_ptr<FrontendAction> Action,
                      std::vector<const Decl *> TopLevelDecls,
-                     std::vector<DiagWithFixIts> Diags,
-                     InclusionLocations IncLocations)
+                     std::vector<Diag> Diags, InclusionLocations IncLocations)
     : Preamble(std::move(Preamble)), Clang(std::move(Clang)),
       Action(std::move(Action)), Diags(std::move(Diags)),
       TopLevelDecls(std::move(TopLevelDecls)), PreambleDeclsDeserialized(false),
@@ -445,8 +322,7 @@
   log("Created CppFile for " + FileName);
 }
 
-llvm::Optional<std::vector<DiagWithFixIts>>
-CppFile::rebuild(ParseInputs &&Inputs) {
+llvm::Optional<std::vector<Diag>> CppFile::rebuild(ParseInputs &&Inputs) {
   log("Rebuilding file " + FileName + " with command [" +
       Inputs.CompileCommand.Directory + "] " +
       llvm::join(Inputs.CompileCommand.CommandLine, " "));
@@ -500,12 +376,11 @@
                               std::move(ContentsBuffer), PCHs, Inputs.FS);
   }
 
-  std::vector<DiagWithFixIts> Diagnostics;
+  std::vector<Diag> Diagnostics;
   if (NewAST) {
     // Collect diagnostics from both the preamble and the AST.
     if (NewPreamble)
-      Diagnostics.insert(Diagnostics.begin(), NewPreamble->Diags.begin(),
-                         NewPreamble->Diags.end());
+      Diagnostics = NewPreamble->Diags;
     Diagnostics.insert(Diagnostics.end(), NewAST->getDiagnostics().begin(),
                        NewAST->getDiagnostics().end());
   }
@@ -557,11 +432,10 @@
 
   trace::Span Tracer("Preamble");
   SPAN_ATTACH(Tracer, "File", FileName);
-  std::vector<DiagWithFixIts> PreambleDiags;
-  StoreDiagsConsumer PreambleDiagnosticsConsumer(/*ref*/ PreambleDiags);
+  StoreDiags PreambleDiagnostics;
   IntrusiveRefCntPtr<DiagnosticsEngine> PreambleDiagsEngine =
       CompilerInstance::createDiagnostics(&CI.getDiagnosticOpts(),
-                                          &PreambleDiagnosticsConsumer, false);
+                                          &PreambleDiagnostics, false);
 
   // Skip function bodies when building the preamble to speed up building
   // the preamble and make it smaller.
@@ -584,7 +458,7 @@
     return std::make_shared<PreambleData>(
         std::move(*BuiltPreamble),
         SerializedDeclsCollector.takeTopLevelDeclIDs(),
-        std::move(PreambleDiags),
+        PreambleDiagnostics.take(),
         SerializedDeclsCollector.takeInclusionLocations());
   } else {
     log("Could not build a preamble for file " + Twine(FileName));
diff --git a/clangd/ClangdUnit.h b/clangd/ClangdUnit.h
index df29290..b3535b5 100644
--- a/clangd/ClangdUnit.h
+++ b/clangd/ClangdUnit.h
@@ -10,6 +10,7 @@
 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
 
+#include "Diagnostics.h"
 #include "Function.h"
 #include "Path.h"
 #include "Protocol.h"
@@ -39,24 +40,17 @@
 
 namespace clangd {
 
-/// A diagnostic with its FixIts.
-struct DiagWithFixIts {
-  clangd::Diagnostic Diag;
-  llvm::SmallVector<TextEdit, 1> FixIts;
-};
-
 using InclusionLocations = std::vector<std::pair<Range, Path>>;
 
 // Stores Preamble and associated data.
 struct PreambleData {
   PreambleData(PrecompiledPreamble Preamble,
                std::vector<serialization::DeclID> TopLevelDeclIDs,
-               std::vector<DiagWithFixIts> Diags,
-               InclusionLocations IncLocations);
+               std::vector<Diag> Diags, InclusionLocations IncLocations);
 
   PrecompiledPreamble Preamble;
   std::vector<serialization::DeclID> TopLevelDeclIDs;
-  std::vector<DiagWithFixIts> Diags;
+  std::vector<Diag> Diags;
   InclusionLocations IncLocations;
 };
 
@@ -96,7 +90,7 @@
   /// this call might be expensive.
   ArrayRef<const Decl *> getTopLevelDecls();
 
-  const std::vector<DiagWithFixIts> &getDiagnostics() const;
+  const std::vector<Diag> &getDiagnostics() const;
 
   /// Returns the esitmated size of the AST and the accessory structures, in
   /// bytes. Does not include the size of the preamble.
@@ -107,8 +101,8 @@
   ParsedAST(std::shared_ptr<const PreambleData> Preamble,
             std::unique_ptr<CompilerInstance> Clang,
             std::unique_ptr<FrontendAction> Action,
-            std::vector<const Decl *> TopLevelDecls,
-            std::vector<DiagWithFixIts> Diags, InclusionLocations IncLocations);
+            std::vector<const Decl *> TopLevelDecls, std::vector<Diag> Diags,
+            InclusionLocations IncLocations);
 
 private:
   void ensurePreambleDeclsDeserialized();
@@ -125,7 +119,7 @@
   std::unique_ptr<FrontendAction> Action;
 
   // Data, stored after parsing.
-  std::vector<DiagWithFixIts> Diags;
+  std::vector<Diag> Diags;
   std::vector<const Decl *> TopLevelDecls;
   bool PreambleDeclsDeserialized;
   InclusionLocations IncLocations;
@@ -143,7 +137,7 @@
 
   /// Rebuild the AST and the preamble.
   /// Returns a list of diagnostics or llvm::None, if an error occured.
-  llvm::Optional<std::vector<DiagWithFixIts>> rebuild(ParseInputs &&Inputs);
+  llvm::Optional<std::vector<Diag>> rebuild(ParseInputs &&Inputs);
   /// Returns the last built preamble.
   const std::shared_ptr<const PreambleData> &getPreamble() const;
   /// Returns the last built AST.
diff --git a/clangd/CodeComplete.cpp b/clangd/CodeComplete.cpp
index 6edc076..8753645 100644
--- a/clangd/CodeComplete.cpp
+++ b/clangd/CodeComplete.cpp
@@ -450,8 +450,15 @@
   void ProcessCodeCompleteResults(class Sema &S, CodeCompletionContext Context,
                                   CodeCompletionResult *InResults,
                                   unsigned NumResults) override final {
+    if (CCSema) {
+      log(llvm::formatv(
+          "Multiple code complete callbacks (parser backtracked?). "
+          "Dropping results from context {0}, keeping results from {1}.",
+          getCompletionKindString(this->CCContext.getKind()),
+          getCompletionKindString(Context.getKind())));
+      return;
+    }
     // Record the completion context.
-    assert(!CCSema && "ProcessCodeCompleteResults called multiple times!");
     CCSema = &S;
     CCContext = Context;
 
diff --git a/clangd/Diagnostics.cpp b/clangd/Diagnostics.cpp
new file mode 100644
index 0000000..e497823
--- /dev/null
+++ b/clangd/Diagnostics.cpp
@@ -0,0 +1,364 @@
+//===--- Diagnostics.cpp ----------------------------------------*- C++-*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "Diagnostics.h"
+#include "Compiler.h"
+#include "Logger.h"
+#include "SourceCode.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/Capacity.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+
+namespace clang {
+namespace clangd {
+
+namespace {
+
+bool mentionsMainFile(const Diag &D) {
+  if (D.InsideMainFile)
+    return true;
+  // Fixes are always in the main file.
+  if (!D.Fixes.empty())
+    return true;
+  for (auto &N : D.Notes) {
+    if (N.InsideMainFile)
+      return true;
+  }
+  return false;
+}
+
+// Checks whether a location is within a half-open range.
+// Note that clang also uses closed source ranges, which this can't handle!
+bool locationInRange(SourceLocation L, CharSourceRange R,
+                     const SourceManager &M) {
+  assert(R.isCharRange());
+  if (!R.isValid() || M.getFileID(R.getBegin()) != M.getFileID(R.getEnd()) ||
+      M.getFileID(R.getBegin()) != M.getFileID(L))
+    return false;
+  return L != R.getEnd() && M.isPointWithin(L, R.getBegin(), R.getEnd());
+}
+
+// Clang diags have a location (shown as ^) and 0 or more ranges (~~~~).
+// LSP needs a single range.
+Range diagnosticRange(const clang::Diagnostic &D, const LangOptions &L) {
+  auto &M = D.getSourceManager();
+  auto Loc = M.getFileLoc(D.getLocation());
+  // Accept the first range that contains the location.
+  for (const auto &CR : D.getRanges()) {
+    auto R = Lexer::makeFileCharRange(CR, M, L);
+    if (locationInRange(Loc, R, M))
+      return halfOpenToRange(M, R);
+  }
+  // The range may be given as a fixit hint instead.
+  for (const auto &F : D.getFixItHints()) {
+    auto R = Lexer::makeFileCharRange(F.RemoveRange, M, L);
+    if (locationInRange(Loc, R, M))
+      return halfOpenToRange(M, R);
+  }
+  // If no suitable range is found, just use the token at the location.
+  auto R = Lexer::makeFileCharRange(CharSourceRange::getTokenRange(Loc), M, L);
+  if (!R.isValid()) // Fall back to location only, let the editor deal with it.
+    R = CharSourceRange::getCharRange(Loc);
+  return halfOpenToRange(M, R);
+}
+
+TextEdit toTextEdit(const FixItHint &FixIt, const SourceManager &M,
+                    const LangOptions &L) {
+  TextEdit Result;
+  Result.range =
+      halfOpenToRange(M, Lexer::makeFileCharRange(FixIt.RemoveRange, M, L));
+  Result.newText = FixIt.CodeToInsert;
+  return Result;
+}
+
+bool isInsideMainFile(const SourceLocation Loc, const SourceManager &M) {
+  return Loc.isValid() && M.isInMainFile(Loc);
+}
+
+bool isInsideMainFile(const clang::Diagnostic &D) {
+  if (!D.hasSourceManager())
+    return false;
+
+  return isInsideMainFile(D.getLocation(), D.getSourceManager());
+}
+
+bool isNote(DiagnosticsEngine::Level L) {
+  return L == DiagnosticsEngine::Note || L == DiagnosticsEngine::Remark;
+}
+
+llvm::StringRef diagLeveltoString(DiagnosticsEngine::Level Lvl) {
+  switch (Lvl) {
+  case DiagnosticsEngine::Ignored:
+    return "ignored";
+  case DiagnosticsEngine::Note:
+    return "note";
+  case DiagnosticsEngine::Remark:
+    return "remark";
+  case DiagnosticsEngine::Warning:
+    return "warning";
+  case DiagnosticsEngine::Error:
+    return "error";
+  case DiagnosticsEngine::Fatal:
+    return "fatal error";
+  }
+  llvm_unreachable("unhandled DiagnosticsEngine::Level");
+}
+
+/// Prints a single diagnostic in a clang-like manner, the output includes
+/// location, severity and error message. An example of the output message is:
+///
+///     main.cpp:12:23: error: undeclared identifier
+///
+/// For main file we only print the basename and for all other files we print
+/// the filename on a separate line to provide a slightly more readable output
+/// in the editors:
+///
+///     dir1/dir2/dir3/../../dir4/header.h:12:23
+///     error: undeclared identifier
+void printDiag(llvm::raw_string_ostream &OS, const DiagBase &D) {
+  if (D.InsideMainFile) {
+    // Paths to main files are often taken from compile_command.json, where they
+    // are typically absolute. To reduce noise we print only basename for them,
+    // it should not be confusing and saves space.
+    OS << llvm::sys::path::filename(D.File) << ":";
+  } else {
+    OS << D.File << ":";
+  }
+  // Note +1 to line and character. clangd::Range is zero-based, but when
+  // printing for users we want one-based indexes.
+  auto Pos = D.Range.start;
+  OS << (Pos.line + 1) << ":" << (Pos.character + 1) << ":";
+  // The non-main-file paths are often too long, putting them on a separate
+  // line improves readability.
+  if (D.InsideMainFile)
+    OS << " ";
+  else
+    OS << "\n";
+  OS << diagLeveltoString(D.Severity) << ": " << D.Message;
+}
+
+/// Returns a message sent to LSP for the main diagnostic in \p D.
+/// The message includes all the notes with their corresponding locations.
+/// However, notes with fix-its are excluded as those usually only contain a
+/// fix-it message and just add noise if included in the message for diagnostic.
+/// Example output:
+///
+///     no matching function for call to 'foo'
+///
+///     main.cpp:3:5: note: candidate function not viable: requires 2 arguments
+///
+///     dir1/dir2/dir3/../../dir4/header.h:12:23
+///     note: candidate function not viable: requires 3 arguments
+std::string mainMessage(const Diag &D) {
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+  OS << D.Message;
+  for (auto &Note : D.Notes) {
+    OS << "\n\n";
+    printDiag(OS, Note);
+  }
+  OS.flush();
+  return Result;
+}
+
+/// Returns a message sent to LSP for the note of the main diagnostic.
+/// The message includes the main diagnostic to provide the necessary context
+/// for the user to understand the note.
+std::string noteMessage(const Diag &Main, const DiagBase &Note) {
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+  OS << Note.Message;
+  OS << "\n\n";
+  printDiag(OS, Main);
+  OS.flush();
+  return Result;
+}
+} // namespace
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const DiagBase &D) {
+  if (!D.InsideMainFile)
+    OS << "[in " << D.File << "] ";
+  return OS << D.Message;
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Fix &F) {
+  OS << F.Message << " {";
+  const char *Sep = "";
+  for (const auto &Edit : F.Edits) {
+    OS << Sep << Edit;
+    Sep = ", ";
+  }
+  return OS << "}";
+}
+
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diag &D) {
+  OS << static_cast<const DiagBase &>(D);
+  if (!D.Notes.empty()) {
+    OS << ", notes: {";
+    const char *Sep = "";
+    for (auto &Note : D.Notes) {
+      OS << Sep << Note;
+      Sep = ", ";
+    }
+    OS << "}";
+  }
+  if (!D.Fixes.empty()) {
+    OS << ", fixes: {";
+    const char *Sep = "";
+    for (auto &Fix : D.Fixes) {
+      OS << Sep << Fix;
+      Sep = ", ";
+    }
+  }
+  return OS;
+}
+
+void toLSPDiags(
+    const Diag &D,
+    llvm::function_ref<void(clangd::Diagnostic, llvm::ArrayRef<Fix>)> OutFn) {
+  auto FillBasicFields = [](const DiagBase &D) -> clangd::Diagnostic {
+    clangd::Diagnostic Res;
+    Res.range = D.Range;
+    Res.severity = getSeverity(D.Severity);
+    return Res;
+  };
+
+  {
+    clangd::Diagnostic Main = FillBasicFields(D);
+    Main.message = mainMessage(D);
+    OutFn(std::move(Main), D.Fixes);
+  }
+
+  for (auto &Note : D.Notes) {
+    if (!Note.InsideMainFile)
+      continue;
+    clangd::Diagnostic Res = FillBasicFields(Note);
+    Res.message = noteMessage(D, Note);
+    OutFn(std::move(Res), llvm::ArrayRef<Fix>());
+  }
+}
+
+int getSeverity(DiagnosticsEngine::Level L) {
+  switch (L) {
+  case DiagnosticsEngine::Remark:
+    return 4;
+  case DiagnosticsEngine::Note:
+    return 3;
+  case DiagnosticsEngine::Warning:
+    return 2;
+  case DiagnosticsEngine::Fatal:
+  case DiagnosticsEngine::Error:
+    return 1;
+  case DiagnosticsEngine::Ignored:
+    return 0;
+  }
+  llvm_unreachable("Unknown diagnostic level!");
+}
+
+std::vector<Diag> StoreDiags::take() { return std::move(Output); }
+
+void StoreDiags::BeginSourceFile(const LangOptions &Opts,
+                                 const Preprocessor *) {
+  LangOpts = Opts;
+}
+
+void StoreDiags::EndSourceFile() {
+  flushLastDiag();
+  LangOpts = llvm::None;
+}
+
+void StoreDiags::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+                                  const clang::Diagnostic &Info) {
+  DiagnosticConsumer::HandleDiagnostic(DiagLevel, Info);
+
+  if (!LangOpts || !Info.hasSourceManager()) {
+    IgnoreDiagnostics::log(DiagLevel, Info);
+    return;
+  }
+
+  bool InsideMainFile = isInsideMainFile(Info);
+
+  auto FillDiagBase = [&](DiagBase &D) {
+    D.Range = diagnosticRange(Info, *LangOpts);
+    llvm::SmallString<64> Message;
+    Info.FormatDiagnostic(Message);
+    D.Message = Message.str();
+    D.InsideMainFile = InsideMainFile;
+    D.File = Info.getSourceManager().getFilename(Info.getLocation());
+    D.Severity = DiagLevel;
+    return D;
+  };
+
+  auto AddFix = [&]() -> bool {
+    assert(!Info.getFixItHints().empty() &&
+           "diagnostic does not have attached fix-its");
+    if (!InsideMainFile)
+      return false;
+
+    llvm::SmallVector<TextEdit, 1> Edits;
+    for (auto &FixIt : Info.getFixItHints()) {
+      if (!isInsideMainFile(FixIt.RemoveRange.getBegin(),
+                            Info.getSourceManager()))
+        return false;
+      Edits.push_back(toTextEdit(FixIt, Info.getSourceManager(), *LangOpts));
+    }
+
+    llvm::SmallString<64> Message;
+    Info.FormatDiagnostic(Message);
+    LastDiag->Fixes.push_back(Fix{Message.str(), std::move(Edits)});
+    return true;
+  };
+
+  if (!isNote(DiagLevel)) {
+    // Handle the new main diagnostic.
+    flushLastDiag();
+
+    LastDiag = Diag();
+    FillDiagBase(*LastDiag);
+
+    if (!Info.getFixItHints().empty())
+      AddFix();
+  } else {
+    // Handle a note to an existing diagnostic.
+    if (!LastDiag) {
+      assert(false && "Adding a note without main diagnostic");
+      IgnoreDiagnostics::log(DiagLevel, Info);
+      return;
+    }
+
+    if (!Info.getFixItHints().empty()) {
+      // A clang note with fix-it is not a separate diagnostic in clangd. We
+      // attach it as a Fix to the main diagnostic instead.
+      if (!AddFix())
+        IgnoreDiagnostics::log(DiagLevel, Info);
+    } else {
+      // A clang note without fix-its corresponds to clangd::Note.
+      Note N;
+      FillDiagBase(N);
+
+      LastDiag->Notes.push_back(std::move(N));
+    }
+  }
+}
+
+void StoreDiags::flushLastDiag() {
+  if (!LastDiag)
+    return;
+  if (mentionsMainFile(*LastDiag))
+    Output.push_back(std::move(*LastDiag));
+  else
+    log(Twine("Dropped diagnostic outside main file:") + LastDiag->File + ":" +
+        LastDiag->Message);
+  LastDiag.reset();
+}
+
+} // namespace clangd
+} // namespace clang
diff --git a/clangd/Diagnostics.h b/clangd/Diagnostics.h
new file mode 100644
index 0000000..b2174f6
--- /dev/null
+++ b/clangd/Diagnostics.h
@@ -0,0 +1,103 @@
+//===--- Diagnostics.h ------------------------------------------*- C++-*-===//
+//
+//                     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_EXTRA_CLANGD_DIAGNOSTICS_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DIAGNOSTICS_H
+
+#include "Path.h"
+#include "Protocol.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringSet.h"
+#include <cassert>
+#include <string>
+
+namespace clang {
+namespace clangd {
+
+/// Contains basic information about a diagnostic.
+struct DiagBase {
+  std::string Message;
+  // Intended to be used only in error messages.
+  // May be relative, absolute or even artifically constructed.
+  std::string File;
+  clangd::Range Range;
+  DiagnosticsEngine::Level Severity = DiagnosticsEngine::Note;
+  // Since File is only descriptive, we store a separate flag to distinguish
+  // diags from the main file.
+  bool InsideMainFile = false;
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const DiagBase &D);
+
+/// Represents a single fix-it that editor can apply to fix the error.
+struct Fix {
+  /// Message for the fix-it.
+  std::string Message;
+  /// TextEdits from clang's fix-its. Must be non-empty.
+  llvm::SmallVector<TextEdit, 1> Edits;
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Fix &F);
+
+/// Represents a note for the diagnostic. Severity of notes can only be 'note'
+/// or 'remark'.
+struct Note : DiagBase {};
+
+/// A top-level diagnostic that may have Notes and Fixes.
+struct Diag : DiagBase {
+  /// Elaborate on the problem, usually pointing to a related piece of code.
+  std::vector<Note> Notes;
+  /// *Alternative* fixes for this diagnostic, one should be chosen.
+  std::vector<Fix> Fixes;
+};
+llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Diag &D);
+
+/// Conversion to LSP diagnostics. Formats the error message of each diagnostic
+/// to include all its notes. Notes inside main file are also provided as
+/// separate diagnostics with their corresponding fixits. Notes outside main
+/// file do not have a corresponding LSP diagnostic, but can still be included
+/// as part of their main diagnostic's message.
+void toLSPDiags(
+    const Diag &D,
+    llvm::function_ref<void(clangd::Diagnostic, llvm::ArrayRef<Fix>)> OutFn);
+
+/// Convert from clang diagnostic level to LSP severity.
+int getSeverity(DiagnosticsEngine::Level L);
+
+/// StoreDiags collects the diagnostics that can later be reported by
+/// clangd. It groups all notes for a diagnostic into a single Diag
+/// and filters out diagnostics that don't mention the main file (i.e. neither
+/// the diag itself nor its notes are in the main file).
+class StoreDiags : public DiagnosticConsumer {
+public:
+  std::vector<Diag> take();
+
+  void BeginSourceFile(const LangOptions &Opts, const Preprocessor *) override;
+  void EndSourceFile() override;
+  void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+                        const clang::Diagnostic &Info) override;
+
+private:
+  bool shouldIgnore(DiagnosticsEngine::Level DiagLevel,
+                    const clang::Diagnostic &Info);
+
+  void flushLastDiag();
+
+  std::vector<Diag> Output;
+  llvm::Optional<LangOptions> LangOpts;
+  llvm::Optional<Diag> LastDiag;
+  /// Is any diag or note from LastDiag in the main file?
+  bool LastDiagMentionsMainFile = false;
+};
+
+} // namespace clangd
+} // namespace clang
+
+#endif
diff --git a/clangd/DraftStore.cpp b/clangd/DraftStore.cpp
index 4bda859..8e1cf88 100644
--- a/clangd/DraftStore.cpp
+++ b/clangd/DraftStore.cpp
@@ -8,16 +8,19 @@
 //===----------------------------------------------------------------------===//
 
 #include "DraftStore.h"
+#include "SourceCode.h"
+#include "llvm/Support/Errc.h"
 
 using namespace clang;
 using namespace clang::clangd;
 
-VersionedDraft DraftStore::getDraft(PathRef File) const {
+llvm::Optional<std::string> DraftStore::getDraft(PathRef File) const {
   std::lock_guard<std::mutex> Lock(Mutex);
 
   auto It = Drafts.find(File);
   if (It == Drafts.end())
-    return {0, llvm::None};
+    return llvm::None;
+
   return It->second;
 }
 
@@ -26,35 +29,79 @@
   std::vector<Path> ResultVector;
 
   for (auto DraftIt = Drafts.begin(); DraftIt != Drafts.end(); DraftIt++)
-    if (DraftIt->second.Draft)
-      ResultVector.push_back(DraftIt->getKey());
+    ResultVector.push_back(DraftIt->getKey());
 
   return ResultVector;
 }
 
-DocVersion DraftStore::getVersion(PathRef File) const {
+void DraftStore::addDraft(PathRef File, StringRef Contents) {
   std::lock_guard<std::mutex> Lock(Mutex);
 
-  auto It = Drafts.find(File);
-  if (It == Drafts.end())
-    return 0;
-  return It->second.Version;
+  Drafts[File] = Contents;
 }
 
-DocVersion DraftStore::updateDraft(PathRef File, StringRef Contents) {
+llvm::Expected<std::string> DraftStore::updateDraft(
+    PathRef File, llvm::ArrayRef<TextDocumentContentChangeEvent> Changes) {
   std::lock_guard<std::mutex> Lock(Mutex);
 
-  auto &Entry = Drafts[File];
-  DocVersion NewVersion = ++Entry.Version;
-  Entry.Draft = Contents;
-  return NewVersion;
+  auto EntryIt = Drafts.find(File);
+  if (EntryIt == Drafts.end()) {
+    return llvm::make_error<llvm::StringError>(
+        "Trying to do incremental update on non-added document: " + File,
+        llvm::errc::invalid_argument);
+  }
+
+  std::string Contents = EntryIt->second;
+
+  for (const TextDocumentContentChangeEvent &Change : Changes) {
+    if (!Change.range) {
+      Contents = Change.text;
+      continue;
+    }
+
+    const Position &Start = Change.range->start;
+    llvm::Expected<size_t> StartIndex =
+        positionToOffset(Contents, Start, false);
+    if (!StartIndex)
+      return StartIndex.takeError();
+
+    const Position &End = Change.range->end;
+    llvm::Expected<size_t> EndIndex = positionToOffset(Contents, End, false);
+    if (!EndIndex)
+      return EndIndex.takeError();
+
+    if (*EndIndex < *StartIndex)
+      return llvm::make_error<llvm::StringError>(
+          llvm::formatv(
+              "Range's end position ({0}) is before start position ({1})", End,
+              Start),
+          llvm::errc::invalid_argument);
+
+    if (Change.rangeLength &&
+        (ssize_t)(*EndIndex - *StartIndex) != *Change.rangeLength)
+      return llvm::make_error<llvm::StringError>(
+          llvm::formatv("Change's rangeLength ({0}) doesn't match the "
+                        "computed range length ({1}).",
+                        *Change.rangeLength, *EndIndex - *StartIndex),
+          llvm::errc::invalid_argument);
+
+    std::string NewContents;
+    NewContents.reserve(*StartIndex + Change.text.length() +
+                        (Contents.length() - *EndIndex));
+
+    NewContents = Contents.substr(0, *StartIndex);
+    NewContents += Change.text;
+    NewContents += Contents.substr(*EndIndex);
+
+    Contents = std::move(NewContents);
+  }
+
+  EntryIt->second = Contents;
+  return Contents;
 }
 
-DocVersion DraftStore::removeDraft(PathRef File) {
+void DraftStore::removeDraft(PathRef File) {
   std::lock_guard<std::mutex> Lock(Mutex);
 
-  auto &Entry = Drafts[File];
-  DocVersion NewVersion = ++Entry.Version;
-  Entry.Draft = llvm::None;
-  return NewVersion;
+  Drafts.erase(File);
 }
diff --git a/clangd/DraftStore.h b/clangd/DraftStore.h
index 4757768..90a2d2c 100644
--- a/clangd/DraftStore.h
+++ b/clangd/DraftStore.h
@@ -11,9 +11,9 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_DRAFTSTORE_H
 
 #include "Path.h"
+#include "Protocol.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/StringMap.h"
-#include <cstdint>
 #include <mutex>
 #include <string>
 #include <vector>
@@ -21,45 +21,37 @@
 namespace clang {
 namespace clangd {
 
-/// Using unsigned int type here to avoid undefined behaviour on overflow.
-typedef uint64_t DocVersion;
-
-/// Document draft with a version of this draft.
-struct VersionedDraft {
-  DocVersion Version;
-  /// If the value of the field is None, draft is now deleted
-  llvm::Optional<std::string> Draft;
-};
-
 /// A thread-safe container for files opened in a workspace, addressed by
-/// filenames. The contents are owned by the DraftStore. Versions are mantained
-/// for the all added documents, including removed ones. The document version is
-/// incremented on each update and removal of the document.
+/// filenames. The contents are owned by the DraftStore. This class supports
+/// both whole and incremental updates of the documents.
 class DraftStore {
 public:
-  /// \return version and contents of the stored document.
-  /// For untracked files, a (0, None) pair is returned.
-  VersionedDraft getDraft(PathRef File) const;
+  /// \return Contents of the stored document.
+  /// For untracked files, a llvm::None is returned.
+  llvm::Optional<std::string> getDraft(PathRef File) const;
 
-  /// \return List of names of active drafts in this store.  Drafts that were
-  /// removed (which still have an entry in the Drafts map) are not returned by
-  /// this function.
+  /// \return List of names of the drafts in this store.
   std::vector<Path> getActiveFiles() const;
 
-  /// \return version of the tracked document.
-  /// For untracked files, 0 is returned.
-  DocVersion getVersion(PathRef File) const;
-
   /// Replace contents of the draft for \p File with \p Contents.
-  /// \return The new version of the draft for \p File.
-  DocVersion updateDraft(PathRef File, StringRef Contents);
-  /// Remove the contents of the draft
-  /// \return The new version of the draft for \p File.
-  DocVersion removeDraft(PathRef File);
+  void addDraft(PathRef File, StringRef Contents);
+
+  /// Update the contents of the draft for \p File based on \p Changes.
+  /// If a position in \p Changes is invalid (e.g. out-of-range), the
+  /// draft is not modified.
+  ///
+  /// \return The new version of the draft for \p File, or an error if the
+  /// changes couldn't be applied.
+  llvm::Expected<std::string>
+  updateDraft(PathRef File,
+              llvm::ArrayRef<TextDocumentContentChangeEvent> Changes);
+
+  /// Remove the draft from the store.
+  void removeDraft(PathRef File);
 
 private:
   mutable std::mutex Mutex;
-  llvm::StringMap<VersionedDraft> Drafts;
+  llvm::StringMap<std::string> Drafts;
 };
 
 } // namespace clangd
diff --git a/clangd/Function.h b/clangd/Function.h
index de3ed5a..975134b 100644
--- a/clangd/Function.h
+++ b/clangd/Function.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H
 
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/Support/Error.h"
 #include <cassert>
 #include <memory>
 #include <tuple>
@@ -27,6 +28,9 @@
 /// A move-only type-erasing function wrapper. Similar to `std::function`, but
 /// allows to store move-only callables.
 template <class> class UniqueFunction;
+/// A Callback<T> is a void function that accepts Expected<T>.
+/// This is accepted by ClangdServer functions that logically return T.
+template <typename T> using Callback = UniqueFunction<void(llvm::Expected<T>)>;
 
 template <class Ret, class... Args> class UniqueFunction<Ret(Args...)> {
 public:
diff --git a/clangd/JSONExpr.cpp b/clangd/JSONExpr.cpp
index a6e6a55..3f87c28 100644
--- a/clangd/JSONExpr.cpp
+++ b/clangd/JSONExpr.cpp
@@ -113,7 +113,7 @@
       ++P;
   }
 
-  // On invalid syntax, parseX() functions return false and and set Err.
+  // On invalid syntax, parseX() functions return false and set Err.
   bool parseNumber(char First, double &Out);
   bool parseString(std::string &Out);
   bool parseUnicode(std::string &Out);
diff --git a/clangd/Protocol.cpp b/clangd/Protocol.cpp
index 8f2f8c6..566104b 100644
--- a/clangd/Protocol.cpp
+++ b/clangd/Protocol.cpp
@@ -248,7 +248,8 @@
 
 bool fromJSON(const json::Expr &Params, TextDocumentContentChangeEvent &R) {
   json::ObjectMapper O(Params);
-  return O && O.map("text", R.text);
+  return O && O.map("range", R.range) && O.map("rangeLength", R.rangeLength) &&
+         O.map("text", R.text);
 }
 
 bool fromJSON(const json::Expr &Params, FormattingOptions &R) {
diff --git a/clangd/Protocol.h b/clangd/Protocol.h
index 968ebfc..77cf8d2 100644
--- a/clangd/Protocol.h
+++ b/clangd/Protocol.h
@@ -119,6 +119,9 @@
   friend bool operator==(const Range &LHS, const Range &RHS) {
     return std::tie(LHS.start, LHS.end) == std::tie(RHS.start, RHS.end);
   }
+  friend bool operator!=(const Range &LHS, const Range &RHS) {
+    return !(LHS == RHS);
+  }
   friend bool operator<(const Range &LHS, const Range &RHS) {
     return std::tie(LHS.start, LHS.end) < std::tie(RHS.start, RHS.end);
   }
@@ -194,6 +197,20 @@
 using ShutdownParams = NoParams;
 using ExitParams = NoParams;
 
+/// Defines how the host (editor) should sync document changes to the language
+/// server.
+enum class TextDocumentSyncKind {
+  /// Documents should not be synced at all.
+  None = 0,
+
+  /// Documents are synced by always sending the full content of the document.
+  Full = 1,
+
+  /// Documents are synced by sending the full content on open.  After that
+  /// only incremental updates to the document are send.
+  Incremental = 2,
+};
+
 struct CompletionItemClientCapabilities {
   /// Client supports snippets as insert text.
   bool snippetSupport = false;
@@ -284,7 +301,13 @@
 bool fromJSON(const json::Expr &, DidCloseTextDocumentParams &);
 
 struct TextDocumentContentChangeEvent {
-  /// The new text of the document.
+  /// The range of the document that changed.
+  llvm::Optional<Range> range;
+
+  /// The length of the range that got replaced.
+  llvm::Optional<int> rangeLength;
+
+  /// The new text of the range/document.
   std::string text;
 };
 bool fromJSON(const json::Expr &, TextDocumentContentChangeEvent &);
@@ -410,13 +433,14 @@
   /// The diagnostic's message.
   std::string message;
 };
+
 /// A LSP-specific comparator used to find diagnostic in a container like
 /// std:map.
 /// We only use the required fields of Diagnostic to do the comparsion to avoid
 /// any regression issues from LSP clients (e.g. VScode), see
 /// https://git.io/vbr29
 struct LSPDiagnosticCompare {
-  bool operator()(const Diagnostic& LHS, const Diagnostic& RHS) const {
+  bool operator()(const Diagnostic &LHS, const Diagnostic &RHS) const {
     return std::tie(LHS.range, LHS.message) < std::tie(RHS.range, RHS.message);
   }
 };
@@ -741,4 +765,14 @@
 } // namespace clangd
 } // namespace clang
 
+namespace llvm {
+template <> struct format_provider<clang::clangd::Position> {
+  static void format(const clang::clangd::Position &Pos, raw_ostream &OS,
+                     StringRef Style) {
+    assert(Style.empty() && "style modifiers for this type are not supported");
+    OS << Pos;
+  }
+};
+} // namespace llvm
+
 #endif
diff --git a/clangd/ProtocolHandlers.cpp b/clangd/ProtocolHandlers.cpp
index 32cfd2f..f5b4669 100644
--- a/clangd/ProtocolHandlers.cpp
+++ b/clangd/ProtocolHandlers.cpp
@@ -38,16 +38,14 @@
   }
 
   JSONRPCDispatcher &Dispatcher;
-  JSONOutput *Out;
   ProtocolCallbacks *Callbacks;
 };
 
 } // namespace
 
 void clangd::registerCallbackHandlers(JSONRPCDispatcher &Dispatcher,
-                                      JSONOutput &Out,
                                       ProtocolCallbacks &Callbacks) {
-  HandlerRegisterer Register{Dispatcher, &Out, &Callbacks};
+  HandlerRegisterer Register{Dispatcher, &Callbacks};
 
   Register("initialize", &ProtocolCallbacks::onInitialize);
   Register("shutdown", &ProtocolCallbacks::onShutdown);
diff --git a/clangd/ProtocolHandlers.h b/clangd/ProtocolHandlers.h
index 7599ece..6ed062c 100644
--- a/clangd/ProtocolHandlers.h
+++ b/clangd/ProtocolHandlers.h
@@ -55,7 +55,7 @@
   virtual void onChangeConfiguration(DidChangeConfigurationParams &Params) = 0;
 };
 
-void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher, JSONOutput &Out,
+void registerCallbackHandlers(JSONRPCDispatcher &Dispatcher,
                               ProtocolCallbacks &Callbacks);
 
 } // namespace clangd
diff --git a/clangd/SourceCode.cpp b/clangd/SourceCode.cpp
index 4495b53..8e1db83 100644
--- a/clangd/SourceCode.cpp
+++ b/clangd/SourceCode.cpp
@@ -9,23 +9,43 @@
 #include "SourceCode.h"
 
 #include "clang/Basic/SourceManager.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
 
 namespace clang {
 namespace clangd {
 using namespace llvm;
 
-size_t positionToOffset(StringRef Code, Position P) {
+llvm::Expected<size_t> positionToOffset(StringRef Code, Position P,
+                                        bool AllowColumnsBeyondLineLength) {
   if (P.line < 0)
-    return 0;
+    return llvm::make_error<llvm::StringError>(
+        llvm::formatv("Line value can't be negative ({0})", P.line),
+        llvm::errc::invalid_argument);
+  if (P.character < 0)
+    return llvm::make_error<llvm::StringError>(
+        llvm::formatv("Character value can't be negative ({0})", P.character),
+        llvm::errc::invalid_argument);
   size_t StartOfLine = 0;
   for (int I = 0; I != P.line; ++I) {
     size_t NextNL = Code.find('\n', StartOfLine);
     if (NextNL == StringRef::npos)
-      return Code.size();
+      return llvm::make_error<llvm::StringError>(
+          llvm::formatv("Line value is out of range ({0})", P.line),
+          llvm::errc::invalid_argument);
     StartOfLine = NextNL + 1;
   }
+
+  size_t NextNL = Code.find('\n', StartOfLine);
+  if (NextNL == StringRef::npos)
+    NextNL = Code.size();
+
+  if (StartOfLine + P.character > NextNL && !AllowColumnsBeyondLineLength)
+    return llvm::make_error<llvm::StringError>(
+        llvm::formatv("Character value is out of range ({0})", P.character),
+        llvm::errc::invalid_argument);
   // FIXME: officially P.character counts UTF-16 code units, not UTF-8 bytes!
-  return std::min(Code.size(), StartOfLine + std::max(0, P.character));
+  return std::min(NextNL, StartOfLine + P.character);
 }
 
 Position offsetToPosition(StringRef Code, size_t Offset) {
@@ -48,5 +68,13 @@
   return P;
 }
 
+Range halfOpenToRange(const SourceManager &SM, CharSourceRange R) {
+  // Clang is 1-based, LSP uses 0-based indexes.
+  Position Begin = sourceLocToPosition(SM, R.getBegin());
+  Position End = sourceLocToPosition(SM, R.getEnd());
+
+  return {Begin, End};
+}
+
 } // namespace clangd
 } // namespace clang
diff --git a/clangd/SourceCode.h b/clangd/SourceCode.h
index cd0578b..6a2efd9 100644
--- a/clangd/SourceCode.h
+++ b/clangd/SourceCode.h
@@ -22,14 +22,33 @@
 namespace clangd {
 
 /// Turn a [line, column] pair into an offset in Code.
-size_t positionToOffset(llvm::StringRef Code, Position P);
+///
+/// If the character value is greater than the line length, the behavior depends
+/// on AllowColumnsBeyondLineLength:
+///
+/// - if true: default back to the end of the line
+/// - if false: return an error
+///
+/// If the line number is greater than the number of lines in the document,
+/// always return an error.
+///
+/// The returned value is in the range [0, Code.size()].
+llvm::Expected<size_t>
+positionToOffset(llvm::StringRef Code, Position P,
+                 bool AllowColumnsBeyondLineLength = true);
 
 /// Turn an offset in Code into a [line, column] pair.
+/// FIXME: This should return an error if the offset is invalid.
 Position offsetToPosition(llvm::StringRef Code, size_t Offset);
 
 /// Turn a SourceLocation into a [line, column] pair.
+/// FIXME: This should return an error if the location is invalid.
 Position sourceLocToPosition(const SourceManager &SM, SourceLocation Loc);
 
+// Converts a half-open clang source range to an LSP range.
+// Note that clang also uses closed source ranges, which this can't handle!
+Range halfOpenToRange(const SourceManager &SM, CharSourceRange R);
+
 } // namespace clangd
 } // namespace clang
 #endif
diff --git a/clangd/TUScheduler.cpp b/clangd/TUScheduler.cpp
index 5dad70a..51b13e2 100644
--- a/clangd/TUScheduler.cpp
+++ b/clangd/TUScheduler.cpp
@@ -85,7 +85,7 @@
   ~ASTWorker();
 
   void update(ParseInputs Inputs, WantDiagnostics,
-              UniqueFunction<void(std::vector<DiagWithFixIts>)> OnUpdated);
+              UniqueFunction<void(std::vector<Diag>)> OnUpdated);
   void runWithAST(llvm::StringRef Name,
                   UniqueFunction<void(llvm::Expected<InputsAndAST>)> Action);
   bool blockUntilIdle(Deadline Timeout) const;
@@ -135,8 +135,8 @@
   // Result of getUsedBytes() after the last rebuild or read of AST.
   std::size_t LastASTSize; /* GUARDED_BY(Mutex) */
   // Set to true to signal run() to finish processing.
-  bool Done;                           /* GUARDED_BY(Mutex) */
-  std::deque<Request> Requests;        /* GUARDED_BY(Mutex) */
+  bool Done;                    /* GUARDED_BY(Mutex) */
+  std::deque<Request> Requests; /* GUARDED_BY(Mutex) */
   mutable std::condition_variable RequestsCV;
 };
 
@@ -210,9 +210,8 @@
 #endif
 }
 
-void ASTWorker::update(
-    ParseInputs Inputs, WantDiagnostics WantDiags,
-    UniqueFunction<void(std::vector<DiagWithFixIts>)> OnUpdated) {
+void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags,
+                       UniqueFunction<void(std::vector<Diag>)> OnUpdated) {
   auto Task = [=](decltype(OnUpdated) OnUpdated) mutable {
     FileInputs = Inputs;
     auto Diags = AST.rebuild(std::move(Inputs));
@@ -408,7 +407,8 @@
 
 struct TUScheduler::FileData {
   /// Latest inputs, passed to TUScheduler::update().
-  ParseInputs Inputs;
+  std::string Contents;
+  tooling::CompileCommand Command;
   ASTWorkerHandle Worker;
 };
 
@@ -447,9 +447,9 @@
   return true;
 }
 
-void TUScheduler::update(
-    PathRef File, ParseInputs Inputs, WantDiagnostics WantDiags,
-    UniqueFunction<void(std::vector<DiagWithFixIts>)> OnUpdated) {
+void TUScheduler::update(PathRef File, ParseInputs Inputs,
+                         WantDiagnostics WantDiags,
+                         UniqueFunction<void(std::vector<Diag>)> OnUpdated) {
   std::unique_ptr<FileData> &FD = Files[File];
   if (!FD) {
     // Create a new worker to process the AST-related tasks.
@@ -457,9 +457,11 @@
         File, WorkerThreads ? WorkerThreads.getPointer() : nullptr, Barrier,
         CppFile(File, StorePreamblesInMemory, PCHOps, ASTCallback),
         UpdateDebounce);
-    FD = std::unique_ptr<FileData>(new FileData{Inputs, std::move(Worker)});
+    FD = std::unique_ptr<FileData>(new FileData{
+        Inputs.Contents, Inputs.CompileCommand, std::move(Worker)});
   } else {
-    FD->Inputs = Inputs;
+    FD->Contents = Inputs.Contents;
+    FD->Command = Inputs.CompileCommand;
   }
   FD->Worker->update(std::move(Inputs), WantDiags, std::move(OnUpdated));
 }
@@ -501,26 +503,28 @@
     SPAN_ATTACH(Tracer, "file", File);
     std::shared_ptr<const PreambleData> Preamble =
         It->second->Worker->getPossiblyStalePreamble();
-    Action(InputsAndPreamble{It->second->Inputs, Preamble.get()});
+    Action(InputsAndPreamble{It->second->Contents, It->second->Command,
+                             Preamble.get()});
     return;
   }
 
-  ParseInputs InputsCopy = It->second->Inputs;
   std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
-  auto Task = [InputsCopy, Worker, this](std::string Name, std::string File,
-                                         Context Ctx,
-                                         decltype(Action) Action) mutable {
+  auto Task = [Worker, this](std::string Name, std::string File,
+                             std::string Contents,
+                             tooling::CompileCommand Command, Context Ctx,
+                             decltype(Action) Action) mutable {
     std::lock_guard<Semaphore> BarrierLock(Barrier);
     WithContext Guard(std::move(Ctx));
     trace::Span Tracer(Name);
     SPAN_ATTACH(Tracer, "file", File);
     std::shared_ptr<const PreambleData> Preamble =
         Worker->getPossiblyStalePreamble();
-    Action(InputsAndPreamble{InputsCopy, Preamble.get()});
+    Action(InputsAndPreamble{Contents, Command, Preamble.get()});
   };
 
   PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File),
                           Bind(Task, std::string(Name), std::string(File),
+                               It->second->Contents, It->second->Command,
                                Context::current().clone(), std::move(Action)));
 }
 
diff --git a/clangd/TUScheduler.h b/clangd/TUScheduler.h
index 828db6e..aea669d 100644
--- a/clangd/TUScheduler.h
+++ b/clangd/TUScheduler.h
@@ -29,7 +29,8 @@
 };
 
 struct InputsAndPreamble {
-  const ParseInputs &Inputs;
+  llvm::StringRef Contents;
+  const tooling::CompileCommand &Command;
   const PreambleData *Preamble;
 };
 
@@ -63,7 +64,7 @@
   /// \p File was not part of it before.
   /// FIXME(ibiryukov): remove the callback from this function.
   void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD,
-              UniqueFunction<void(std::vector<DiagWithFixIts>)> OnUpdated);
+              UniqueFunction<void(std::vector<Diag>)> OnUpdated);
 
   /// Remove \p File from the list of tracked files and schedule removal of its
   /// resources.
@@ -76,16 +77,19 @@
   /// If an error occurs during processing, it is forwarded to the \p Action
   /// callback.
   void runWithAST(llvm::StringRef Name, PathRef File,
-                  UniqueFunction<void(llvm::Expected<InputsAndAST>)> Action);
+                  Callback<InputsAndAST> Action);
 
-  /// Schedule an async read of the Preamble. Preamble passed to \p Action may
-  /// be built for any version of the file, callers must not rely on it being
-  /// consistent with the current version of the file.
+  /// Schedule an async read of the Preamble.
+  /// The preamble may be stale, generated from an older version of the file.
+  /// Reading from locations in the preamble may cause the files to be re-read.
+  /// This gives callers two options:
+  /// - validate that the preamble is still valid, and only use it in this case
+  /// - accept that preamble contents may be outdated, and try to avoid reading
+  ///   source code from headers.
   /// If an error occurs during processing, it is forwarded to the \p Action
   /// callback.
-  void runWithPreamble(
-      llvm::StringRef Name, PathRef File,
-      UniqueFunction<void(llvm::Expected<InputsAndPreamble>)> Action);
+  void runWithPreamble(llvm::StringRef Name, PathRef File,
+                       Callback<InputsAndPreamble> Action);
 
   /// Wait until there are no scheduled or running tasks.
   /// Mostly useful for synchronizing tests.
diff --git a/clangd/XRefs.cpp b/clangd/XRefs.cpp
index 6cc27ec..b502efe 100644
--- a/clangd/XRefs.cpp
+++ b/clangd/XRefs.cpp
@@ -7,6 +7,7 @@
 //
 //===---------------------------------------------------------------------===//
 #include "XRefs.h"
+#include "AST.h"
 #include "Logger.h"
 #include "SourceCode.h"
 #include "URI.h"
@@ -126,6 +127,16 @@
         MacroInfo *MacroInf = MacroDef.getMacroInfo();
         if (MacroInf) {
           MacroInfos.push_back(MacroDecl{IdentifierInfo->getName(), MacroInf});
+          // Clear all collected delcarations if this is a macro search.
+          //
+          // In theory, there should be no declarataions being collected when we
+          // search a source location that refers to a macro.
+          // The occurrence location returned by `handleDeclOccurence` is
+          // limited (FID, Offset are from expansion location), we will collect
+          // all declarations inside the macro.
+          //
+          // FIXME: Avoid adding decls from inside macros in handlDeclOccurence.
+          Decls.clear();
         }
       }
     }
@@ -133,7 +144,7 @@
 };
 
 llvm::Optional<Location>
-getDeclarationLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
+makeLocation(ParsedAST &AST, const SourceRange &ValSourceRange) {
   const SourceManager &SourceMgr = AST.getASTContext().getSourceManager();
   const LangOptions &LangOpts = AST.getASTContext().getLangOpts();
   SourceLocation LocStart = ValSourceRange.getBegin();
@@ -174,6 +185,18 @@
 
   SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE);
 
+  std::vector<Location> Result;
+  // Handle goto definition for #include.
+  for (auto &IncludeLoc : AST.getInclusionLocations()) {
+    Range R = IncludeLoc.first;
+    Position Pos = sourceLocToPosition(SourceMgr, SourceLocationBeg);
+
+    if (R.contains(Pos))
+      Result.push_back(Location{URIForFile{IncludeLoc.second}, {}});
+  }
+  if (!Result.empty())
+    return Result;
+
   auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>(
       llvm::errs(), SourceLocationBeg, AST.getASTContext(),
       AST.getPreprocessor());
@@ -187,31 +210,21 @@
 
   std::vector<const Decl *> Decls = DeclMacrosFinder->takeDecls();
   std::vector<MacroDecl> MacroInfos = DeclMacrosFinder->takeMacroInfos();
-  std::vector<Location> Result;
 
-  for (auto Item : Decls) {
-    auto L = getDeclarationLocation(AST, Item->getSourceRange());
+  for (auto D : Decls) {
+    auto Loc = findNameLoc(D);
+    auto L = makeLocation(AST, SourceRange(Loc, Loc));
     if (L)
       Result.push_back(*L);
   }
 
   for (auto Item : MacroInfos) {
-    SourceRange SR(Item.Info->getDefinitionLoc(),
-                   Item.Info->getDefinitionEndLoc());
-    auto L = getDeclarationLocation(AST, SR);
+    auto Loc = Item.Info->getDefinitionLoc();
+    auto L = makeLocation(AST, SourceRange(Loc, Loc));
     if (L)
       Result.push_back(*L);
   }
 
-  /// Process targets for paths inside #include directive.
-  for (auto &IncludeLoc : AST.getInclusionLocations()) {
-    Range R = IncludeLoc.first;
-    Position Pos = sourceLocToPosition(SourceMgr, SourceLocationBeg);
-
-    if (R.contains(Pos))
-      Result.push_back(Location{URIForFile{IncludeLoc.second}, {}});
-  }
-
   return Result;
 }
 
diff --git a/clangd/clients/clangd-vscode/.gitignore b/clangd/clients/clangd-vscode/.gitignore
index 8e5962e..1294fe2 100644
--- a/clangd/clients/clangd-vscode/.gitignore
+++ b/clangd/clients/clangd-vscode/.gitignore
@@ -1,2 +1,3 @@
 out
-node_modules
\ No newline at end of file
+node_modules
+package-lock.json
diff --git a/clangd/clients/clangd-vscode/package.json b/clangd/clients/clangd-vscode/package.json
index a25cf45..18d8bc5 100644
--- a/clangd/clients/clangd-vscode/package.json
+++ b/clangd/clients/clangd-vscode/package.json
@@ -2,7 +2,7 @@
     "name": "vscode-clangd",
     "displayName": "vscode-clangd",
     "description": "Clang Language Server",
-    "version": "0.0.4",
+    "version": "0.0.5",
     "publisher": "llvm-vs-code-extensions",
     "homepage": "https://clang.llvm.org/extra/clangd.html",
     "engines": {
diff --git a/clangd/clients/clangd-vscode/src/extension.ts b/clangd/clients/clangd-vscode/src/extension.ts
index 3f9e95f..a126a19 100644
--- a/clangd/clients/clangd-vscode/src/extension.ts
+++ b/clangd/clients/clangd-vscode/src/extension.ts
@@ -1,12 +1,13 @@
 import * as vscode from 'vscode';
 import * as vscodelc from 'vscode-languageclient';
+import { realpathSync } from 'fs';
 
 /**
  * Method to get workspace configuration option
  * @param option name of the option (e.g. for clangd.path should be path)
  * @param defaultValue default value to return if option is not set
  */
-function getConfig<T>(option: string, defaultValue?: any) : T {
+function getConfig<T>(option: string, defaultValue?: any): T {
     const config = vscode.workspace.getConfiguration('clangd');
     return config.get<T>(option, defaultValue);
 }
@@ -24,18 +25,29 @@
     };
     const traceFile = getConfig<string>('trace');
     if (!!traceFile) {
-      const trace = {CLANGD_TRACE : traceFile};
-      clangd.options = {env : {...process.env, ...trace}};
+        const trace = { CLANGD_TRACE: traceFile };
+        clangd.options = { env: { ...process.env, ...trace } };
     }
     const serverOptions: vscodelc.ServerOptions = clangd;
 
     const filePattern: string = '**/*.{' +
-      ['cpp', 'c', 'cc', 'cxx', 'c++', 'm', 'mm', 'h', 'hh', 'hpp', 'hxx', 'inc'].join() + '}';
+        ['cpp', 'c', 'cc', 'cxx', 'c++', 'm', 'mm', 'h', 'hh', 'hpp', 'hxx', 'inc'].join() + '}';
     const clientOptions: vscodelc.LanguageClientOptions = {
         // Register the server for C/C++ files
-        documentSelector: [{scheme: 'file', pattern: filePattern}],
+        documentSelector: [{ scheme: 'file', pattern: filePattern }],
         synchronize: !syncFileEvents ? undefined : {
             fileEvents: vscode.workspace.createFileSystemWatcher(filePattern)
+        },
+        // Resolve symlinks for all files provided by clangd.
+        // This is a workaround for a bazel + clangd issue - bazel produces a symlink tree to build in,
+        // and when navigating to the included file, clangd passes its path inside the symlink tree
+        // rather than its filesystem path.
+        // FIXME: remove this once clangd knows enough about bazel to resolve the
+        // symlinks where needed (or if this causes problems for other workflows).
+        uriConverters: {
+            code2Protocol: (value: vscode.Uri) => value.toString(),
+            protocol2Code: (value: string) =>
+                vscode.Uri.file(realpathSync(vscode.Uri.parse(value).fsPath))
         }
     };
 
diff --git a/clangd/fuzzer/ClangdFuzzer.cpp b/clangd/fuzzer/ClangdFuzzer.cpp
index 266da4e..3321222 100644
--- a/clangd/fuzzer/ClangdFuzzer.cpp
+++ b/clangd/fuzzer/ClangdFuzzer.cpp
@@ -14,6 +14,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "ClangdLSPServer.h"
+#include "ClangdServer.h"
 #include "CodeComplete.h"
 #include <sstream>
 
@@ -21,12 +22,10 @@
   clang::clangd::JSONOutput Out(llvm::nulls(), llvm::nulls(), nullptr);
   clang::clangd::CodeCompleteOptions CCOpts;
   CCOpts.EnableSnippets = false;
+  clang::clangd::ClangdServer::Options Opts;
 
   // Initialize and run ClangdLSPServer.
-  clang::clangd::ClangdLSPServer LSPServer(
-      Out, clang::clangd::getDefaultAsyncThreadsCount(),
-      /*StorePreamblesInMemory=*/false, CCOpts, llvm::None, llvm::None,
-      /*BuildDynamicSymbolIndex=*/false);
+  clang::clangd::ClangdLSPServer LSPServer(Out, CCOpts, llvm::None, Opts);
 
   std::istringstream In(std::string(reinterpret_cast<char *>(data), size));
   LSPServer.run(In);
diff --git a/clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp b/clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp
index b4f7f0b..7d62cf1 100644
--- a/clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp
+++ b/clangd/global-symbol-builder/GlobalSymbolBuilderMain.cpp
@@ -99,6 +99,7 @@
     auto CollectorOpts = SymbolCollector::Options();
     CollectorOpts.FallbackDir = AssumedHeaderDir;
     CollectorOpts.CollectIncludePath = true;
+    CollectorOpts.CountReferences = true;
     auto Includes = llvm::make_unique<CanonicalIncludes>();
     addSystemHeadersMapping(Includes.get());
     CollectorOpts.Includes = Includes.get();
diff --git a/clangd/index/FileIndex.cpp b/clangd/index/FileIndex.cpp
index 4f1f10a..2cf8b12 100644
--- a/clangd/index/FileIndex.cpp
+++ b/clangd/index/FileIndex.cpp
@@ -26,12 +26,14 @@
   // AST at this point, but we also need preprocessor callbacks (e.g.
   // CommentHandler for IWYU pragma) to canonicalize includes.
   CollectorOpts.CollectIncludePath = false;
+  CollectorOpts.CountReferences = false;
 
   auto Collector = std::make_shared<SymbolCollector>(std::move(CollectorOpts));
   Collector->setPreprocessor(std::move(PP));
   index::IndexingOptions IndexOpts;
+  // We only need declarations, because we don't count references.
   IndexOpts.SystemSymbolFilter =
-      index::IndexingOptions::SystemSymbolFilterKind::All;
+      index::IndexingOptions::SystemSymbolFilterKind::DeclarationsOnly;
   IndexOpts.IndexFunctionLocals = false;
 
   index::indexTopLevelDecls(Ctx, Decls, Collector, IndexOpts);
@@ -91,5 +93,11 @@
   return Index.fuzzyFind(Req, Callback);
 }
 
+void FileIndex::lookup(
+    const LookupRequest &Req,
+    llvm::function_ref<void(const Symbol &)> Callback) const {
+  Index.lookup(Req, Callback);
+}
+
 } // namespace clangd
 } // namespace clang
diff --git a/clangd/index/FileIndex.h b/clangd/index/FileIndex.h
index cbb4755..d6d3631 100644
--- a/clangd/index/FileIndex.h
+++ b/clangd/index/FileIndex.h
@@ -63,6 +63,9 @@
   fuzzyFind(const FuzzyFindRequest &Req,
             llvm::function_ref<void(const Symbol &)> Callback) const override;
 
+  void lookup(const LookupRequest &Req,
+              llvm::function_ref<void(const Symbol &)> Callback) const override;
+
 private:
   FileSymbols FSymbols;
   MemIndex Index;
diff --git a/clangd/index/Index.h b/clangd/index/Index.h
index 629db53..42f23ce 100644
--- a/clangd/index/Index.h
+++ b/clangd/index/Index.h
@@ -1,4 +1,4 @@
-//===--- Symbol.h -----------------------------------------------*- C++-*-===//
+//===--- Index.h ------------------------------------------------*- C++-*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -56,16 +56,20 @@
   }
 
 private:
+  static constexpr unsigned HashByteLength = 20;
+
   friend llvm::hash_code hash_value(const SymbolID &ID) {
     // We already have a good hash, just return the first bytes.
-    static_assert(sizeof(size_t) <= 20, "size_t longer than SHA1!");
-    return *reinterpret_cast<const size_t *>(ID.HashValue.data());
+    static_assert(sizeof(size_t) <= HashByteLength, "size_t longer than SHA1!");
+    size_t Result;
+    memcpy(&Result, ID.HashValue.data(), sizeof(size_t));
+    return llvm::hash_code(Result);
   }
   friend llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
                                        const SymbolID &ID);
   friend void operator>>(llvm::StringRef Str, SymbolID &ID);
 
-  std::array<uint8_t, 20> HashValue;
+  std::array<uint8_t, HashByteLength> HashValue;
 };
 
 // Write SymbolID into the given stream. SymbolID is encoded as a 40-bytes
@@ -131,6 +135,9 @@
   //   * For non-inline functions, the canonical declaration typically appears
   //     in the ".h" file corresponding to the definition.
   SymbolLocation CanonicalDeclaration;
+  // The number of translation units that reference this symbol from their main
+  // file. This number is only meaningful if aggregated in an index.
+  unsigned References = 0;
 
   /// A brief description of the symbol that can be displayed in the completion
   /// candidate list. For example, "Foo(X x, Y y) const" is a labal for a
@@ -245,6 +252,10 @@
   size_t MaxCandidateCount = UINT_MAX;
 };
 
+struct LookupRequest {
+  llvm::DenseSet<SymbolID> IDs;
+};
+
 /// \brief Interface for symbol indexes that can be used for searching or
 /// matching symbols among a set of symbols based on names or unique IDs.
 class SymbolIndex {
@@ -260,8 +271,14 @@
   fuzzyFind(const FuzzyFindRequest &Req,
             llvm::function_ref<void(const Symbol &)> Callback) const = 0;
 
+  /// Looks up symbols with any of the given symbol IDs and applies \p Callback
+  /// on each matched symbol.
+  /// The returned symbol must be deep-copied if it's used outside Callback.
+  virtual void
+  lookup(const LookupRequest &Req,
+         llvm::function_ref<void(const Symbol &)> Callback) const = 0;
+
   // FIXME: add interfaces for more index use cases:
-  //  - Symbol getSymbolInfo(SymbolID);
   //  - getAllOccurrences(SymbolID);
 };
 
diff --git a/clangd/index/MemIndex.cpp b/clangd/index/MemIndex.cpp
index df7dbc8..6a4d307 100644
--- a/clangd/index/MemIndex.cpp
+++ b/clangd/index/MemIndex.cpp
@@ -60,6 +60,15 @@
   return More;
 }
 
+void MemIndex::lookup(const LookupRequest &Req,
+                      llvm::function_ref<void(const Symbol &)> Callback) const {
+  for (const auto &ID : Req.IDs) {
+    auto I = Index.find(ID);
+    if (I != Index.end())
+      Callback(*I->second);
+  }
+}
+
 std::unique_ptr<SymbolIndex> MemIndex::build(SymbolSlab Slab) {
   struct Snapshot {
     SymbolSlab Slab;
diff --git a/clangd/index/MemIndex.h b/clangd/index/MemIndex.h
index e2f7f0e..3147a6c 100644
--- a/clangd/index/MemIndex.h
+++ b/clangd/index/MemIndex.h
@@ -31,6 +31,10 @@
   fuzzyFind(const FuzzyFindRequest &Req,
             llvm::function_ref<void(const Symbol &)> Callback) const override;
 
+  virtual void
+  lookup(const LookupRequest &Req,
+         llvm::function_ref<void(const Symbol &)> Callback) const override;
+
 private:
   std::shared_ptr<std::vector<const Symbol *>> Symbols;
   // Index is a set of symbols that are deduplicated by symbol IDs.
diff --git a/clangd/index/Merge.cpp b/clangd/index/Merge.cpp
index 57c62c5..41d5345 100644
--- a/clangd/index/Merge.cpp
+++ b/clangd/index/Merge.cpp
@@ -52,6 +52,28 @@
      return More;
   }
 
+  void
+  lookup(const LookupRequest &Req,
+         llvm::function_ref<void(const Symbol &)> Callback) const override {
+    SymbolSlab::Builder B;
+
+    Dynamic->lookup(Req, [&](const Symbol &S) { B.insert(S); });
+
+    auto RemainingIDs = Req.IDs;
+    Symbol::Details Scratch;
+    Static->lookup(Req, [&](const Symbol &S) {
+      const Symbol *Sym = B.find(S.ID);
+      RemainingIDs.erase(S.ID);
+      if (!Sym)
+        Callback(S);
+      else
+        Callback(mergeSymbol(*Sym, S, &Scratch));
+    });
+    for (const auto &ID : RemainingIDs)
+      if (const Symbol *Sym = B.find(ID))
+        Callback(*Sym);
+  }
+
 private:
   const SymbolIndex *Dynamic, *Static;
 };
@@ -73,6 +95,7 @@
     S.Definition = O.Definition;
   if (!S.CanonicalDeclaration)
     S.CanonicalDeclaration = O.CanonicalDeclaration;
+  S.References += O.References;
   if (S.CompletionLabel == "")
     S.CompletionLabel = O.CompletionLabel;
   if (S.CompletionFilterText == "")
diff --git a/clangd/index/SymbolCollector.cpp b/clangd/index/SymbolCollector.cpp
index fe994d0..c595e56 100644
--- a/clangd/index/SymbolCollector.cpp
+++ b/clangd/index/SymbolCollector.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "SymbolCollector.h"
+#include "../AST.h"
 #include "../CodeCompletionStrings.h"
 #include "../Logger.h"
 #include "../URI.h"
@@ -115,10 +116,16 @@
   //   * enum constants in unscoped enum decl (e.g. "red" in "enum {red};")
   auto InTopLevelScope = hasDeclContext(
       anyOf(namespaceDecl(), translationUnitDecl(), linkageSpecDecl()));
+  // Don't index template specializations.
+  auto IsSpecialization =
+      anyOf(functionDecl(isExplicitTemplateSpecialization()),
+            cxxRecordDecl(isExplicitTemplateSpecialization()),
+            varDecl(isExplicitTemplateSpecialization()));
   if (match(decl(allOf(unless(isExpansionInMainFile()),
                        anyOf(InTopLevelScope,
                              hasDeclContext(enumDecl(InTopLevelScope,
-                                                     unless(isScoped())))))),
+                                                     unless(isScoped())))),
+                       unless(IsSpecialization))),
             *ND, *ASTCtx)
           .empty())
     return true;
@@ -178,30 +185,16 @@
 llvm::Optional<SymbolLocation> getSymbolLocation(
     const NamedDecl &D, SourceManager &SM, const SymbolCollector::Options &Opts,
     const clang::LangOptions &LangOpts, std::string &FileURIStorage) {
-  SourceLocation SpellingLoc = SM.getSpellingLoc(D.getLocation());
-  if (D.getLocation().isMacroID()) {
-    std::string PrintLoc = SpellingLoc.printToString(SM);
-    if (llvm::StringRef(PrintLoc).startswith("<scratch") ||
-        llvm::StringRef(PrintLoc).startswith("<command line>")) {
-      // We use the expansion location for the following symbols, as spelling
-      // locations of these symbols are not interesting to us:
-      //   * symbols formed via macro concatenation, the spelling location will
-      //     be "<scratch space>"
-      //   * symbols controlled and defined by a compile command-line option
-      //     `-DName=foo`, the spelling location will be "<command line>".
-      SpellingLoc = SM.getExpansionRange(D.getLocation()).first;
-    }
-  }
-
-  auto U = toURI(SM, SM.getFilename(SpellingLoc), Opts);
+  SourceLocation NameLoc = findNameLoc(&D);
+  auto U = toURI(SM, SM.getFilename(NameLoc), Opts);
   if (!U)
     return llvm::None;
   FileURIStorage = std::move(*U);
   SymbolLocation Result;
   Result.FileURI = FileURIStorage;
-  Result.StartOffset = SM.getFileOffset(SpellingLoc);
+  Result.StartOffset = SM.getFileOffset(NameLoc);
   Result.EndOffset = Result.StartOffset + clang::Lexer::MeasureTokenLength(
-                                              SpellingLoc, SM, LangOpts);
+                                              NameLoc, SM, LangOpts);
   return std::move(Result);
 }
 
@@ -209,7 +202,7 @@
 // in a header file, in which case clangd would prefer to use ND as a canonical
 // declaration.
 // FIXME: handle symbol types that are not TagDecl (e.g. functions), if using
-// the the first seen declaration as canonical declaration is not a good enough
+// the first seen declaration as canonical declaration is not a good enough
 // heuristic.
 bool isPreferredDeclaration(const NamedDecl &ND, index::SymbolRoleSet Roles) {
   using namespace clang::ast_matchers;
@@ -235,39 +228,60 @@
     ArrayRef<index::SymbolRelation> Relations, FileID FID, unsigned Offset,
     index::IndexDataConsumer::ASTNodeInfo ASTNode) {
   assert(ASTCtx && PP.get() && "ASTContext and Preprocessor must be set.");
+  assert(CompletionAllocator && CompletionTUInfo);
+  const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(D);
+  if (!ND)
+    return true;
 
-  // FIXME: collect all symbol references.
+  // Mark D as referenced if this is a reference coming from the main file.
+  // D may not be an interesting symbol, but it's cheaper to check at the end.
+  if (Opts.CountReferences &&
+      (Roles & static_cast<unsigned>(index::SymbolRole::Reference)) &&
+      ASTCtx->getSourceManager().getMainFileID() == FID)
+    ReferencedDecls.insert(ND);
+
+  // Don't continue indexing if this is a mere reference.
   if (!(Roles & static_cast<unsigned>(index::SymbolRole::Declaration) ||
         Roles & static_cast<unsigned>(index::SymbolRole::Definition)))
     return true;
+  if (shouldFilterDecl(ND, ASTCtx, Opts))
+    return true;
 
-  assert(CompletionAllocator && CompletionTUInfo);
+  llvm::SmallString<128> USR;
+  if (index::generateUSRForDecl(ND, USR))
+    return true;
+  SymbolID ID(USR);
 
-  if (const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(D)) {
-    if (shouldFilterDecl(ND, ASTCtx, Opts))
-      return true;
-    llvm::SmallString<128> USR;
-    if (index::generateUSRForDecl(ND, USR))
-      return true;
+  const NamedDecl &OriginalDecl = *cast<NamedDecl>(ASTNode.OrigD);
+  const Symbol *BasicSymbol = Symbols.find(ID);
+  if (!BasicSymbol) // Regardless of role, ND is the canonical declaration.
+    BasicSymbol = addDeclaration(*ND, std::move(ID));
+  else if (isPreferredDeclaration(OriginalDecl, Roles))
+    // If OriginalDecl is preferred, replace the existing canonical
+    // declaration (e.g. a class forward declaration). There should be at most
+    // one duplicate as we expect to see only one preferred declaration per
+    // TU, because in practice they are definitions.
+    BasicSymbol = addDeclaration(OriginalDecl, std::move(ID));
 
-    const NamedDecl &OriginalDecl = *cast<NamedDecl>(ASTNode.OrigD);
-    auto ID = SymbolID(USR);
-    const Symbol *BasicSymbol = Symbols.find(ID);
-    if (!BasicSymbol) // Regardless of role, ND is the canonical declaration.
-      BasicSymbol = addDeclaration(*ND, std::move(ID));
-    else if (isPreferredDeclaration(OriginalDecl, Roles))
-      // If OriginalDecl is preferred, replace the existing canonical
-      // declaration (e.g. a class forward declaration). There should be at most
-      // one duplicate as we expect to see only one preferred declaration per
-      // TU, because in practice they are definitions.
-      BasicSymbol = addDeclaration(OriginalDecl, std::move(ID));
-
-    if (Roles & static_cast<unsigned>(index::SymbolRole::Definition))
-      addDefinition(OriginalDecl, *BasicSymbol);
-  }
+  if (Roles & static_cast<unsigned>(index::SymbolRole::Definition))
+    addDefinition(OriginalDecl, *BasicSymbol);
   return true;
 }
 
+void SymbolCollector::finish() {
+  // At the end of the TU, add 1 to the refcount of the ReferencedDecls.
+  for (const auto *ND : ReferencedDecls) {
+    llvm::SmallString<128> USR;
+    if (!index::generateUSRForDecl(ND, USR))
+      if (const auto *S = Symbols.find(SymbolID(USR))) {
+        Symbol Inc = *S;
+        ++Inc.References;
+        Symbols.insert(Inc);
+      }
+  }
+  ReferencedDecls.clear();
+}
+
 const Symbol *SymbolCollector::addDeclaration(const NamedDecl &ND,
                                               SymbolID ID) {
   auto &SM = ND.getASTContext().getSourceManager();
diff --git a/clangd/index/SymbolCollector.h b/clangd/index/SymbolCollector.h
index c18f74a..7237e39 100644
--- a/clangd/index/SymbolCollector.h
+++ b/clangd/index/SymbolCollector.h
@@ -45,6 +45,8 @@
     /// If set, this is used to map symbol #include path to a potentially
     /// different #include path.
     const CanonicalIncludes *Includes = nullptr;
+    // Populate the Symbol.References field.
+    bool CountReferences = false;
   };
 
   SymbolCollector(Options Opts);
@@ -63,6 +65,8 @@
 
   SymbolSlab takeSymbols() { return std::move(Symbols).build(); }
 
+  void finish() override;
+
 private:
   const Symbol *addDeclaration(const NamedDecl &, SymbolID);
   void addDefinition(const NamedDecl &, const Symbol &DeclSymbol);
@@ -74,6 +78,8 @@
   std::shared_ptr<GlobalCodeCompletionAllocator> CompletionAllocator;
   std::unique_ptr<CodeCompletionTUInfo> CompletionTUInfo;
   Options Opts;
+  // Decls referenced from the current TU, flushed on finish().
+  llvm::DenseSet<const NamedDecl *> ReferencedDecls;
 };
 
 } // namespace clangd
diff --git a/clangd/index/SymbolYAML.cpp b/clangd/index/SymbolYAML.cpp
index 379cb33..307b0af 100644
--- a/clangd/index/SymbolYAML.cpp
+++ b/clangd/index/SymbolYAML.cpp
@@ -100,6 +100,7 @@
     IO.mapOptional("CanonicalDeclaration", Sym.CanonicalDeclaration,
                    SymbolLocation());
     IO.mapOptional("Definition", Sym.Definition, SymbolLocation());
+    IO.mapOptional("References", Sym.References, 0u);
     IO.mapRequired("CompletionLabel", Sym.CompletionLabel);
     IO.mapRequired("CompletionFilterText", Sym.CompletionFilterText);
     IO.mapRequired("CompletionPlainInsertText", Sym.CompletionPlainInsertText);
diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst
index ef7e74e..e71e616 100644
--- a/docs/ReleaseNotes.rst
+++ b/docs/ReleaseNotes.rst
@@ -57,96 +57,136 @@
 Improvements to clang-tidy
 --------------------------
 
-- New `bugprone-throw-keyword-missing
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-throw-keyword-missing.html>`_ check
+- New module `abseil` for checks related to the `Abseil <https://abseil.io>`_
+  library.
+
+- New module ``portability``.
+
+- New module ``zircon`` for checks related to Fuchsia's Zircon kernel.
+
+- New :doc:`bugprone-throw-keyword-missing
+  <clang-tidy/checks/bugprone-throw-keyword-missing>` check
 
   Diagnoses when a temporary object that appears to be an exception is
   constructed but not thrown.
 
-- New `cppcoreguidelines-avoid-goto
-  <http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-avoid-goto.html>`_ check
+- New :doc:`bugprone-unused-return-value
+  <clang-tidy/checks/bugprone-unused-return-value>` check
+
+  Warns on unused function return values.
+
+- New :doc:`cppcoreguidelines-avoid-goto
+  <clang-tidy/checks/cppcoreguidelines-avoid-goto>` check
 
   The usage of ``goto`` for control flow is error prone and should be replaced
   with looping constructs. Every backward jump is rejected. Forward jumps are
   only allowed in nested loops.
 
-- New `fuchsia-multiple-inheritance
-  <http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-multiple-inheritance.html>`_ check
+- New :doc:`fuchsia-multiple-inheritance
+  <clang-tidy/checks/fuchsia-multiple-inheritance>` check
 
   Warns if a class inherits from multiple classes that are not pure virtual.
 
-- New `fuchsia-statically-constructed-objects
-  <http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-statically-constructed-objects.html>`_ check
+- New :doc:`abseil-string-find-startswith
+  <clang-tidy/checks/abseil-string-find-startswith>` check
+
+  Checks whether a ``std::string::find()`` result is compared with 0, and
+  suggests replacing with ``absl::StartsWith()``.
+
+- New :doc:`fuchsia-statically-constructed-objects
+  <clang-tidy/checks/fuchsia-statically-constructed-objects>` check
 
   Warns if global, non-trivial objects with static storage are constructed,
   unless the object is statically initialized with a ``constexpr`` constructor
   or has no explicit constructor.
-  
-- New `fuchsia-trailing-return
-  <http://clang.llvm.org/extra/clang-tidy/checks/fuchsia-trailing-return.html>`_ check
 
-  Functions that have trailing returns are disallowed, except for those 
-  using ``decltype`` specifiers and lambda with otherwise unutterable 
+- New :doc:`fuchsia-trailing-return
+  <clang-tidy/checks/fuchsia-trailing-return>` check
+
+  Functions that have trailing returns are disallowed, except for those
+  using ``decltype`` specifiers and lambda with otherwise unutterable
   return types.
 
-- New `modernize-use-uncaught-exceptions
-  <http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-uncaught-exceptions.html>`_ check
+- New :doc:`hicpp-multiway-paths-covered
+  <clang-tidy/checks/hicpp-multiway-paths-covered>` check
+
+  Checks on ``switch`` and ``if`` - ``else if`` constructs that do not cover all possible code paths.
+
+- New :doc:`modernize-use-uncaught-exceptions
+  <clang-tidy/checks/modernize-use-uncaught-exceptions>` check
 
   Finds and replaces deprecated uses of ``std::uncaught_exception`` to
   ``std::uncaught_exceptions``.
 
-- New `readability-simd-intrinsics
-  <http://clang.llvm.org/extra/clang-tidy/checks/readability-simd-intrinsics.html>`_ check
+- New :doc:`portability-simd-intrinsics
+  <clang-tidy/checks/portability-simd-intrinsics>` check
 
-  Warns if SIMD intrinsics are used which can be replaced by
+  Warns or suggests alternatives if SIMD intrinsics are used which can be replaced by
   ``std::experimental::simd`` operations.
 
-- New alias `hicpp-avoid-goto
-  <http://clang.llvm.org/extra/clang-tidy/checks/hicpp-avoid-goto.html>`_ to
-  `cppcoreguidelines-avoid-goto <http://clang.llvm.org/extra/clang-tidy/checks/cppcoreguidelines-avoid-goto.html>`_
+- New :doc:`zircon-temporary-objects
+  <clang-tidy/checks/zircon-temporary-objects>` check
+
+  Warns on construction of specific temporary objects in the Zircon kernel.
+
+- New alias :doc:`hicpp-avoid-goto
+  <clang-tidy/checks/hicpp-avoid-goto>` to :doc:`cppcoreguidelines-avoid-goto
+  <clang-tidy/checks/cppcoreguidelines-avoid-goto>`
   added.
 
-- The 'misc-forwarding-reference-overload' check was renamed to `bugprone-forwarding-reference-overload
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-forwarding-reference-overload.html>`_
+- The 'misc-forwarding-reference-overload' check was renamed to :doc:`bugprone-forwarding-reference-overload
+  <clang-tidy/checks/bugprone-forwarding-reference-overload>`
 
-- The 'misc-incorrect-roundings' check was renamed to `bugprone-incorrect-roundings
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-incorrect-roundings.html>`_
+- The 'misc-incorrect-roundings' check was renamed to :doc:`bugprone-incorrect-roundings
+  <clang-tidy/checks/bugprone-incorrect-roundings>`
 
-- The 'misc-lambda-function-name' check was renamed to `bugprone-lambda-function-name
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-lambda-function-name.html>`_
+- The 'misc-lambda-function-name' check was renamed to :doc:`bugprone-lambda-function-name
+  <clang-tidy/checks/bugprone-lambda-function-name>`
 
-- The 'misc-macro-repeated-side-effects' check was renamed to `bugprone-macro-repeated-side-effects
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-macro-repeated-side-effects.html>`_
+- The 'misc-macro-parentheses' check was renamed to :doc:`bugprone-macro-parentheses
+  <clang-tidy/checks/bugprone-macro-parentheses>`
 
-- The 'misc-misplaced-widening-cast' check was renamed to `bugprone-misplaced-widening-cast
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-misplaced-widening-cast.html>`_
+- The 'misc-macro-repeated-side-effects' check was renamed to :doc:`bugprone-macro-repeated-side-effects
+  <clang-tidy/checks/bugprone-macro-repeated-side-effects>`
 
-- The 'misc-string-compare' check was renamed to `readability-string-compare
-  <http://clang.llvm.org/extra/clang-tidy/checks/readability-string-compare.html>`_
+- The 'misc-misplaced-widening-cast' check was renamed to :doc:`bugprone-misplaced-widening-cast
+  <clang-tidy/checks/bugprone-misplaced-widening-cast>`
 
-- The 'misc-string-integer-assignment' check was renamed to `bugprone-string-integer-assignment
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-string-integer-assignment.html>`_
+- The 'misc-sizeof-container' check was renamed to :doc:`bugprone-sizeof-container
+  <clang-tidy/checks/bugprone-sizeof-container>`
 
-- The 'misc-string-literal-with-embedded-nul' check was renamed to `bugprone-string-literal-with-embedded-nul
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-string-literal-with-embedded-nul.html>`_
+- The 'misc-sizeof-expression' check was renamed to :doc:`bugprone-sizeof-expression
+  <clang-tidy/checks/bugprone-sizeof-expression>`
 
-- The 'misc-suspicious-enum-usage' check was renamed to `bugprone-suspicious-enum-usage
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-enum-usage.html>`_
+- The 'misc-string-compare' check was renamed to :doc:`readability-string-compare
+  <clang-tidy/checks/readability-string-compare>`
 
-- The 'misc-suspicious-missing-comma' check was renamed to `bugprone-suspicious-missing-comma
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-missing-comma.html>`_
+- The 'misc-string-integer-assignment' check was renamed to :doc:`bugprone-string-integer-assignment
+  <clang-tidy/checks/bugprone-string-integer-assignment>`
 
-- The 'misc-suspicious-semicolon' check was renamed to `bugprone-suspicious-semicolon
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-semicolon.html>`_
+- The 'misc-string-literal-with-embedded-nul' check was renamed to :doc:`bugprone-string-literal-with-embedded-nul
+  <clang-tidy/checks/bugprone-string-literal-with-embedded-nul>`
 
-- The 'misc-suspicious-string-compare' check was renamed to `bugprone-suspicious-string-compare
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-suspicious-string-compare.html>`_
+- The 'misc-suspicious-enum-usage' check was renamed to :doc:`bugprone-suspicious-enum-usage
+  <clang-tidy/checks/bugprone-suspicious-enum-usage>`
 
-- The 'misc-swapped-arguments' check was renamed to `bugprone-swapped-arguments
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-swapped-arguments.html>`_
+- The 'misc-suspicious-missing-comma' check was renamed to :doc:`bugprone-suspicious-missing-comma
+  <clang-tidy/checks/bugprone-suspicious-missing-comma>`
 
-- The 'misc-undelegated-constructor' check was renamed to `bugprone-undelegated-constructor
-  <http://clang.llvm.org/extra/clang-tidy/checks/bugprone-undelegated-constructor.html>`_
+- The 'misc-suspicious-semicolon' check was renamed to :doc:`bugprone-suspicious-semicolon
+  <clang-tidy/checks/bugprone-suspicious-semicolon>`
+
+- The 'misc-suspicious-string-compare' check was renamed to :doc:`bugprone-suspicious-string-compare
+  <clang-tidy/checks/bugprone-suspicious-string-compare>`
+
+- The 'misc-swapped-arguments' check was renamed to :doc:`bugprone-swapped-arguments
+  <clang-tidy/checks/bugprone-swapped-arguments>`
+
+- The 'misc-undelegated-constructor' check was renamed to :doc:`bugprone-undelegated-constructor
+  <clang-tidy/checks/bugprone-undelegated-constructor>`
+
+- The 'misc-unused-raii' check was renamed to :doc:`bugprone-unused-raii
+  <clang-tidy/checks/bugprone-unused-raii>`
 
 Improvements to include-fixer
 -----------------------------
diff --git a/docs/clang-doc.rst b/docs/clang-doc.rst
new file mode 100644
index 0000000..f891b71
--- /dev/null
+++ b/docs/clang-doc.rst
@@ -0,0 +1,65 @@
+===================
+Clang-Doc
+===================
+
+.. contents::
+
+.. toctree::
+   :maxdepth: 1
+
+:program:`clang-doc` is a tool for generating C and C++ documenation from 
+source code and comments. 
+
+The tool is in a very early development stage, so you might encounter bugs and
+crashes. Submitting reports with information about how to reproduce the issue
+to `the LLVM bugtracker <https://llvm.org/bugs>`_ will definitely help the
+project. If you have any ideas or suggestions, please to put a feature request
+there.
+
+Use
+=====
+
+:program:`clang-doc` is a `LibTooling
+<http://clang.llvm.org/docs/LibTooling.html>`_-based tool, and so requires a
+compile command database for your project (for an example of how to do this 
+see `How To Setup Tooling For LLVM
+<http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html>`_).
+
+The tool can be used on a single file or multiple files as defined in 
+the compile commands database:
+
+.. code-block:: console
+
+  $ clang-doc /path/to/file.cpp -p /path/to/compile/commands
+
+This generates an intermediate representation of the declarations and their
+associated information in the specified TUs, serialized to LLVM bitcode.
+
+As currently implemented, the tool is only able to parse TUs that can be 
+stored in-memory. Future additions will extend the current framework to use
+map-reduce frameworks to allow for use with large codebases.
+
+:program:`clang-doc` offers the following options:
+
+.. code-block:: console
+
+	$ clang-doc --help
+  USAGE: clang-doc [options] <source0> [... <sourceN>]
+
+  OPTIONS:
+
+  Generic Options:
+
+    -help                      - Display available options (-help-hidden for more)
+    -help-list                 - Display list of available options (-help-list-hidden for more)
+    -version                   - Display the version of this program
+
+  clang-doc options:
+
+    -doxygen                   - Use only doxygen-style comments to generate docs.
+    -dump                      - Dump intermediate results to bitcode file.
+    -extra-arg=<string>        - Additional argument to append to the compiler command line
+    -extra-arg-before=<string> - Additional argument to prepend to the compiler command line
+    -omit-filenames            - Omit filenames in output.
+    -output=<string>           - Directory for outputting generated files.
+    -p=<string>                - Build path
diff --git a/docs/clang-tidy/checks/abseil-string-find-startswith.rst b/docs/clang-tidy/checks/abseil-string-find-startswith.rst
new file mode 100644
index 0000000..43f35ac
--- /dev/null
+++ b/docs/clang-tidy/checks/abseil-string-find-startswith.rst
@@ -0,0 +1,41 @@
+.. title:: clang-tidy - abseil-string-find-startswith
+
+abseil-string-find-startswith
+=============================
+
+Checks whether a ``std::string::find()`` result is compared with 0, and
+suggests replacing with ``absl::StartsWith()``. This is both a readability and
+performance issue.
+
+.. code-block:: c++
+
+  string s = "...";
+  if (s.find("Hello World") == 0) { /* do something */ }
+
+becomes
+
+
+.. code-block:: c++
+
+  string s = "...";
+  if (absl::StartsWith(s, "Hello World")) { /* do something */ }
+
+
+Options
+-------
+
+.. option:: StringLikeClasses
+
+   Semicolon-separated list of names of string-like classes. By default only
+   ``std::basic_string`` is considered. The list of methods to considered is
+   fixed.
+
+.. option:: IncludeStyle
+
+   A string specifying which include-style is used, `llvm` or `google`. Default
+   is `llvm`.
+
+.. option:: AbseilStringsMatchHeader
+
+   The location of Abseil's ``strings/match.h``. Defaults to
+   ``absl/strings/match.h``.
diff --git a/docs/clang-tidy/checks/misc-macro-parentheses.rst b/docs/clang-tidy/checks/bugprone-macro-parentheses.rst
similarity index 85%
rename from docs/clang-tidy/checks/misc-macro-parentheses.rst
rename to docs/clang-tidy/checks/bugprone-macro-parentheses.rst
index 6120170..f827080 100644
--- a/docs/clang-tidy/checks/misc-macro-parentheses.rst
+++ b/docs/clang-tidy/checks/bugprone-macro-parentheses.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - misc-macro-parentheses
+.. title:: clang-tidy - bugprone-macro-parentheses
 
-misc-macro-parentheses
-======================
+bugprone-macro-parentheses
+==========================
 
 
 Finds macros that can have unexpected behaviour due to missing parentheses.
diff --git a/docs/clang-tidy/checks/misc-sizeof-container.rst b/docs/clang-tidy/checks/bugprone-sizeof-container.rst
similarity index 88%
rename from docs/clang-tidy/checks/misc-sizeof-container.rst
rename to docs/clang-tidy/checks/bugprone-sizeof-container.rst
index 9ee4440..fb2f0b2 100644
--- a/docs/clang-tidy/checks/misc-sizeof-container.rst
+++ b/docs/clang-tidy/checks/bugprone-sizeof-container.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - misc-sizeof-container
+.. title:: clang-tidy - bugprone-sizeof-container
 
-misc-sizeof-container
-=====================
+bugprone-sizeof-container
+=========================
 
 The check finds usages of ``sizeof`` on expressions of STL container types. Most
 likely the user wanted to use ``.size()`` instead.
diff --git a/docs/clang-tidy/checks/misc-sizeof-expression.rst b/docs/clang-tidy/checks/bugprone-sizeof-expression.rst
similarity index 97%
rename from docs/clang-tidy/checks/misc-sizeof-expression.rst
rename to docs/clang-tidy/checks/bugprone-sizeof-expression.rst
index d3e3790..8190c00 100644
--- a/docs/clang-tidy/checks/misc-sizeof-expression.rst
+++ b/docs/clang-tidy/checks/bugprone-sizeof-expression.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - misc-sizeof-expression
+.. title:: clang-tidy - bugprone-sizeof-expression
 
-misc-sizeof-expression
-======================
+bugprone-sizeof-expression
+==========================
 
 The check finds usages of ``sizeof`` expressions which are most likely errors.
 
diff --git a/docs/clang-tidy/checks/misc-unused-raii.rst b/docs/clang-tidy/checks/bugprone-unused-raii.rst
similarity index 89%
rename from docs/clang-tidy/checks/misc-unused-raii.rst
rename to docs/clang-tidy/checks/bugprone-unused-raii.rst
index d081702..f1987c5 100644
--- a/docs/clang-tidy/checks/misc-unused-raii.rst
+++ b/docs/clang-tidy/checks/bugprone-unused-raii.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - misc-unused-raii
+.. title:: clang-tidy - bugprone-unused-raii
 
-misc-unused-raii
-================
+bugprone-unused-raii
+====================
 
 Finds temporaries that look like RAII objects.
 
diff --git a/docs/clang-tidy/checks/bugprone-unused-return-value.rst b/docs/clang-tidy/checks/bugprone-unused-return-value.rst
new file mode 100644
index 0000000..83b243f
--- /dev/null
+++ b/docs/clang-tidy/checks/bugprone-unused-return-value.rst
@@ -0,0 +1,24 @@
+.. title:: clang-tidy - bugprone-unused-return-value
+
+bugprone-unused-return-value
+============================
+
+Warns on unused function return values. The checked funtions can be configured.
+
+Options
+-------
+
+.. option:: CheckedFunctions
+
+   Semicolon-separated list of functions to check. Defaults to
+   ``::std::async;::std::launder;::std::remove;::std::remove_if;::std::unique``.
+   This means that the calls to following functions are checked by default:
+
+   - ``std::async()``. Not using the return value makes the call synchronous.
+   - ``std::launder()``. Not using the return value usually means that the
+     function interface was misunderstood by the programmer. Only the returned
+     pointer is "laundered", not the argument.
+   - ``std::remove()``, ``std::remove_if()`` and ``std::unique()``. The returned
+     iterator indicates the boundary between elements to keep and elements to be
+     removed. Not using the return value means that the information about which
+     elements to remove is lost.
diff --git a/docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst b/docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst
new file mode 100644
index 0000000..2cace63
--- /dev/null
+++ b/docs/clang-tidy/checks/hicpp-multiway-paths-covered.rst
@@ -0,0 +1,96 @@
+.. title:: clang-tidy - hicpp-multiway-paths-covered
+
+hicpp-multiway-paths-covered
+============================
+
+This check discovers situations where code paths are not fully-covered.
+It furthermore suggests using ``if`` instead of ``switch`` if the code will be more clear.
+The `rule 6.1.2 <http://www.codingstandard.com/rule/6-1-2-explicitly-cover-all-paths-through-multi-way-selection-statements/>`_
+and `rule 6.1.4 <http://www.codingstandard.com/rule/6-1-4-ensure-that-a-switch-statement-has-at-least-two-case-labels-distinct-from-the-default-label/>`_
+of the High Integrity C++ Coding Standard are enforced.
+
+``if-else if`` chains that miss a final ``else`` branch might lead to unexpected 
+program execution and be the result of a logical error.
+If the missing ``else`` branch is intended you can leave it empty with a clarifying
+comment.
+This warning can be noisy on some code bases, so it is disabled by default.
+
+.. code-block:: c++
+
+  void f1() {
+    int i = determineTheNumber();
+
+     if(i > 0) { 
+       // Some Calculation 
+     } else if (i < 0) { 
+       // Precondition violated or something else. 
+     }
+     // ...
+  }
+
+Similar arguments hold for ``switch`` statements which do not cover all possible code paths.
+
+.. code-block:: c++
+
+  // The missing default branch might be a logical error. It can be kept empty
+  // if there is nothing to do, making it explicit.
+  void f2(int i) {
+    switch (i) {
+    case 0: // something
+      break;
+    case 1: // something else
+      break;
+    }
+    // All other numbers?
+  }
+
+  // Violates this rule as well, but already emits a compiler warning (-Wswitch).
+  enum Color { Red, Green, Blue, Yellow };
+  void f3(enum Color c) {
+    switch (c) {
+    case Red: // We can't drive for now.
+      break;
+    case Green:  // We are allowed to drive.
+      break;
+    }
+    // Other cases missing
+  }
+
+
+The `rule 6.1.4 <http://www.codingstandard.com/rule/6-1-4-ensure-that-a-switch-statement-has-at-least-two-case-labels-distinct-from-the-default-label/>`_
+requires every ``switch`` statement to have at least two ``case`` labels other than a `default` label.
+Otherwise, the ``switch`` could be better expressed with an ``if`` statement.
+Degenerated ``switch`` statements without any labels are caught as well.
+
+.. code-block:: c++
+
+  // Degenerated switch that could be better written as `if`
+  int i = 42;
+  switch(i) {
+    case 1: // do something here
+    default: // do somethe else here
+  }
+
+  // Should rather be the following:
+  if (i == 1) { 
+    // do something here 
+  }
+  else { 
+    // do something here 
+  }
+
+
+.. code-block:: c++
+  
+  // A completly degenerated switch will be diagnosed.
+  int i = 42;
+  switch(i) {}
+
+
+Options
+-------
+
+.. option:: WarnOnMissingElse
+
+  Boolean flag that activates a warning for missing ``else`` branches.
+  Default is `0`.
diff --git a/docs/clang-tidy/checks/list.rst b/docs/clang-tidy/checks/list.rst
index a186b4b..cb1ef44 100644
--- a/docs/clang-tidy/checks/list.rst
+++ b/docs/clang-tidy/checks/list.rst
@@ -4,6 +4,7 @@
 =================
 
 .. toctree::
+   abseil-string-find-startswith
    android-cloexec-accept
    android-cloexec-accept4
    android-cloexec-creat
@@ -29,11 +30,14 @@
    bugprone-incorrect-roundings
    bugprone-integer-division
    bugprone-lambda-function-name
+   bugprone-macro-parentheses
    bugprone-macro-repeated-side-effects
    bugprone-misplaced-operator-in-strlen-in-alloc
    bugprone-misplaced-widening-cast
    bugprone-move-forwarding-reference
    bugprone-multiple-statement-macro
+   bugprone-sizeof-container
+   bugprone-sizeof-expression
    bugprone-string-constructor
    bugprone-string-integer-assignment
    bugprone-string-literal-with-embedded-nul
@@ -46,6 +50,8 @@
    bugprone-throw-keyword-missing
    bugprone-undefined-memory-manipulation
    bugprone-undelegated-constructor
+   bugprone-unused-raii
+   bugprone-unused-return-value
    bugprone-use-after-move
    bugprone-virtual-near-miss
    cert-dcl03-c (redirects to misc-static-assert) <cert-dcl03-c>
@@ -116,6 +122,7 @@
    hicpp-invalid-access-moved (redirects to bugprone-use-after-move) <hicpp-invalid-access-moved>
    hicpp-member-init (redirects to cppcoreguidelines-pro-type-member-init) <hicpp-member-init>
    hicpp-move-const-arg (redirects to performance-move-const-arg) <hicpp-move-const-arg>
+   hicpp-multiway-paths-covered
    hicpp-named-parameter (redirects to readability-named-parameter) <hicpp-named-parameter>
    hicpp-new-delete-operators (redirects to misc-new-delete-overloads) <hicpp-new-delete-operators>
    hicpp-no-array-decay (redirects to cppcoreguidelines-pro-bounds-array-to-pointer-decay) <hicpp-no-array-decay>
@@ -139,20 +146,16 @@
    llvm-namespace-comment
    llvm-twine-local
    misc-definitions-in-headers
-   misc-macro-parentheses
    misc-misplaced-const
    misc-new-delete-overloads
    misc-non-copyable-objects
    misc-redundant-expression
-   misc-sizeof-container
-   misc-sizeof-expression
    misc-static-assert
    misc-throw-by-value-catch-by-reference
    misc-unconventional-assign-operator
    misc-uniqueptr-reset-release
    misc-unused-alias-decls
    misc-unused-parameters
-   misc-unused-raii
    misc-unused-using-decls
    modernize-avoid-bind
    modernize-deprecated-headers
@@ -197,6 +200,7 @@
    performance-type-promotion-in-math-fn
    performance-unnecessary-copy-initialization
    performance-unnecessary-value-param
+   portability-simd-intrinsics
    readability-avoid-const-params-in-decls
    readability-braces-around-statements
    readability-container-size-empty
@@ -218,9 +222,9 @@
    readability-redundant-smartptr-get
    readability-redundant-string-cstr
    readability-redundant-string-init
-   readability-simd-intrinsics
    readability-simplify-boolean-expr
    readability-static-accessed-through-instance
    readability-static-definition-in-anonymous-namespace
    readability-string-compare
    readability-uniqueptr-delete-release
+   zircon-temporary-objects
diff --git a/docs/clang-tidy/checks/readability-simd-intrinsics.rst b/docs/clang-tidy/checks/portability-simd-intrinsics.rst
similarity index 84%
rename from docs/clang-tidy/checks/readability-simd-intrinsics.rst
rename to docs/clang-tidy/checks/portability-simd-intrinsics.rst
index 49d442c..2cd9d9f 100644
--- a/docs/clang-tidy/checks/readability-simd-intrinsics.rst
+++ b/docs/clang-tidy/checks/portability-simd-intrinsics.rst
@@ -1,6 +1,6 @@
-.. title:: clang-tidy - readability-simd-intrinsics
+.. title:: clang-tidy - portability-simd-intrinsics
 
-readability-simd-intrinsics
+portability-simd-intrinsics
 ===========================
 
 Finds SIMD intrinsics calls and suggests ``std::experimental::simd`` (`P0214`_)
@@ -41,4 +41,9 @@
    `P0214`_ alternatives, otherwise it only points out the intrinsic function is
    non-portable.
 
+.. option:: Std
+
+   The namespace used to suggest `P0214`_ alternatives. If not specified, `std::`
+   for `-std=c++2a` and `std::experimental::` for `-std=c++11`.
+
 .. _P0214: http://wg21.link/p0214
diff --git a/docs/clang-tidy/checks/zircon-temporary-objects.rst b/docs/clang-tidy/checks/zircon-temporary-objects.rst
new file mode 100644
index 0000000..7491f77
--- /dev/null
+++ b/docs/clang-tidy/checks/zircon-temporary-objects.rst
@@ -0,0 +1,53 @@
+.. title:: clang-tidy - zircon-temporary-objects
+
+zircon-temporary-objects
+========================
+
+Warns on construction of specific temporary objects in the Zircon kernel. 
+If the object should be flagged, If the object should be flagged, the fully 
+qualified type name must be explicitly passed to the check.
+
+For example, given the list of classes "Foo" and "NS::Bar", all of the 
+following will trigger the warning: 
+
+.. code-block:: c++
+
+  Foo();
+  Foo F = Foo();
+  func(Foo());
+
+  namespace NS {
+
+  Bar();
+
+  }
+
+With the same list, the following will not trigger the warning:
+
+.. code-block:: c++
+
+  Foo F;				         // Non-temporary construction okay
+  Foo F(param);			     // Non-temporary construction okay
+  Foo *F = new Foo();	   // New construction okay
+
+  Bar(); 				         // Not NS::Bar, so okay
+  NS::Bar B;			       // Non-temporary construction okay
+
+Note that objects must be explicitly specified in order to be flagged, 
+and so objects that inherit a specified object will not be flagged.
+
+This check matches temporary objects without regard for inheritance and so a
+prohibited base class type does not similarly prohibit derived class types.
+
+.. code-block:: c++
+
+  class Derived : Foo {} // Derived is not explicitly disallowed
+  Derived();             // and so temporary construction is okay
+
+Options
+-------
+
+.. option:: Names
+
+   A semi-colon-separated list of fully-qualified names of C++ classes that 
+   should not be constructed as temporaries. Default is empty.
diff --git a/docs/clang-tidy/index.rst b/docs/clang-tidy/index.rst
index 35292d0..dc601ec 100644
--- a/docs/clang-tidy/index.rst
+++ b/docs/clang-tidy/index.rst
@@ -71,8 +71,11 @@
 ``mpi-``               Checks related to MPI (Message Passing Interface).
 ``objc-``              Checks related to Objective-C coding conventions.
 ``performance-``       Checks that target performance-related issues.
+``portability-``       Checks that target portability-related issues that don't
+                       relate to any particular coding style.
 ``readability-``       Checks that target readability-related issues that don't
                        relate to any particular coding style.
+``zircon-``            Checks related to Zircon kernel coding conventions.
 ====================== =========================================================
 
 Clang diagnostics are treated in a similar way as check diagnostics. Clang
diff --git a/docs/clangd.rst b/docs/clangd.rst
index c70cf7c..8218e3c 100644
--- a/docs/clangd.rst
+++ b/docs/clangd.rst
@@ -75,7 +75,7 @@
 +-------------------------------------+------------+----------+
 | Rename                              | Yes        |   Yes    |
 +-------------------------------------+------------+----------+
-| Source hover                        | Yes        |   No     |
+| Source hover                        | Yes        |   Yes    |
 +-------------------------------------+------------+----------+
 | Find References                     | Yes        |   No     |
 +-------------------------------------+------------+----------+
diff --git a/docs/index.rst b/docs/index.rst
index 1dc2f93..8e6beb3 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -26,6 +26,7 @@
    pp-trace
    clang-rename
    clangd
+   clang-doc
 
 
 Doxygen Documentation
diff --git a/modularize/Modularize.cpp b/modularize/Modularize.cpp
index e5f19de..83f2340 100644
--- a/modularize/Modularize.cpp
+++ b/modularize/Modularize.cpp
@@ -825,7 +825,7 @@
   // No go if we have no header list file.
   if (ListFileNames.size() == 0) {
     cl::PrintHelpMessage();
-    return 0;
+    return 1;
   }
 
   std::unique_ptr<ModularizeUtilities> ModUtil;
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 26d3405..fafe6c0 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -37,10 +37,14 @@
   # For the clang-apply-replacements test that uses clang-rename.
   clang-rename
 
+  # For the clang-doc tests that emit bitcode files.
+  llvm-bcanalyzer
+
   # Individual tools we test.
   clang-apply-replacements
   clang-change-namespace
   clangd
+  clang-doc
   clang-include-fixer
   clang-move
   clang-query
diff --git a/test/clang-doc/mapper-class-in-class.cpp b/test/clang-doc/mapper-class-in-class.cpp
new file mode 100644
index 0000000..909f00d
--- /dev/null
+++ b/test/clang-doc/mapper-class-in-class.cpp
@@ -0,0 +1,35 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/641AB4A3D36399954ACDE29C7A8833032BF40472.bc --dump | FileCheck %s --check-prefix CHECK-X-Y
+// RUN: llvm-bcanalyzer %t/docs/bc/CA7C7935730B5EACD25F080E9C83FA087CCDC75E.bc --dump | FileCheck %s --check-prefix CHECK-X
+
+class X {
+  class Y {};
+};
+
+// CHECK-X: <BLOCKINFO_BLOCK/>
+// CHECK-X-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-X-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-X-NEXT: </VersionBlock>
+// CHECK-X-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-X-NEXT: <USR abbrevid=4 op0=20 op1=202 op2=124 op3=121 op4=53 op5=115 op6=11 op7=94 op8=172 op9=210 op10=95 op11=8 op12=14 op13=156 op14=131 op15=250 op16=8 op17=124 op18=205 op19=199 op20=94/>
+  // CHECK-X-NEXT: <Name abbrevid=5 op0=1/> blob data = 'X'
+  // CHECK-X-NEXT: <DefLocation abbrevid=7 op0=9 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-X-NEXT: <TagType abbrevid=9 op0=3/>
+// CHECK-X-NEXT: </RecordBlock>
+
+
+// CHECK-X-Y: <BLOCKINFO_BLOCK/>
+// CHECK-X-Y-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-X-Y-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-X-Y-NEXT: </VersionBlock>
+// CHECK-X-Y-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-X-Y-NEXT: <USR abbrevid=4 op0=20 op1=100 op2=26 op3=180 op4=163 op5=211 op6=99 op7=153 op8=149 op9=74 op10=205 op11=226 op12=156 op13=122 op14=136 op15=51 op16=3 op17=43 op18=244 op19=4 op20=114/>
+  // CHECK-X-Y-NEXT: <Name abbrevid=5 op0=1/> blob data = 'Y'
+  // CHECK-X-Y-NEXT: <Namespace abbrevid=6 op0=1 op1=40/> blob data = 'CA7C7935730B5EACD25F080E9C83FA087CCDC75E'
+  // CHECK-X-Y-NEXT: <DefLocation abbrevid=7 op0=10 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-X-Y-NEXT: <TagType abbrevid=9 op0=3/>
+// CHECK-X-Y-NEXT: </RecordBlock>
diff --git a/test/clang-doc/mapper-class-in-function.cpp b/test/clang-doc/mapper-class-in-function.cpp
new file mode 100644
index 0000000..e572c07
--- /dev/null
+++ b/test/clang-doc/mapper-class-in-function.cpp
@@ -0,0 +1,41 @@
+// This test requires Linux due to the system-dependent USR for the
+// inner class.
+// REQUIRES: system-linux
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E.bc --dump | FileCheck %s --check-prefix CHECK-H
+// RUN: llvm-bcanalyzer %t/docs/bc/01A95F3F73F53281B3E50109A577FD2493159365.bc --dump | FileCheck %s --check-prefix CHECK-H-I
+
+void H() {
+  class I {};
+}
+
+// CHECK-H: <BLOCKINFO_BLOCK/>
+// CHECK-H-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-H-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-H-NEXT: </VersionBlock>
+// CHECK-H-NEXT: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-H-NEXT: <USR abbrevid=4 op0=20 op1=182 op2=172 op3=76 op4=92 op5=159 op6=46 op7=163 op8=242 op9=179 op10=236 op11=225 op12=163 op13=61 op14=52 op15=159 op16=78 op17=229 op18=2 op19=178 op20=78/>
+  // CHECK-H-NEXT: <Name abbrevid=5 op0=1/> blob data = 'H'
+  // CHECK-H-NEXT: <DefLocation abbrevid=7 op0=12 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-H-NEXT: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK-H-NEXT: <Type abbrevid=4 op0=4 op1=4/> blob data = 'void'
+  // CHECK-H-NEXT: </TypeBlock>
+// CHECK-H-NEXT: </FunctionBlock>
+
+// CHECK-H-I: <BLOCKINFO_BLOCK/>
+// CHECK-H-I-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-H-I-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-H-I-NEXT: </VersionBlock>
+// CHECK-H-I-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-H-I-NEXT: <USR abbrevid=4 op0=20 op1=1 op2=169 op3=95 op4=63 op5=115 op6=245 op7=50 op8=129 op9=179 op10=229 op11=1 op12=9 op13=165 op14=119 op15=253 op16=36 op17=147 op18=21 op19=147 op20=101/>
+  // CHECK-H-I-NEXT: <Name abbrevid=5 op0=1/> blob data = 'I'
+  // CHECK-H-I-NEXT: <Namespace abbrevid=6 op0=2 op1=40/> blob data = 'B6AC4C5C9F2EA3F2B3ECE1A33D349F4EE502B24E'
+  // CHECK-H-I-NEXT: <DefLocation abbrevid=7 op0=13 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-H-I-NEXT: <TagType abbrevid=9 op0=3/>
+// CHECK-H-I-NEXT: </RecordBlock>
+
+
diff --git a/test/clang-doc/mapper-class.cpp b/test/clang-doc/mapper-class.cpp
new file mode 100644
index 0000000..7c0965c
--- /dev/null
+++ b/test/clang-doc/mapper-class.cpp
@@ -0,0 +1,19 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/289584A8E0FF4178A794622A547AA622503967A1.bc --dump | FileCheck %s
+
+class E {};
+
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-NEXT: </VersionBlock>
+// CHECK-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-NEXT: <USR abbrevid=4 op0=20 op1=40 op2=149 op3=132 op4=168 op5=224 op6=255 op7=65 op8=120 op9=167 op10=148 op11=98 op12=42 op13=84 op14=122 op15=166 op16=34 op17=80 op18=57 op19=103 op20=161/>
+  // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'E'
+  // CHECK-NEXT: <DefLocation abbrevid=7 op0=8 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-NEXT: <TagType abbrevid=9 op0=3/>
+// CHECK-NEXT: </RecordBlock>
diff --git a/test/clang-doc/mapper-comments.cpp b/test/clang-doc/mapper-comments.cpp
new file mode 100644
index 0000000..91620ca
--- /dev/null
+++ b/test/clang-doc/mapper-comments.cpp
@@ -0,0 +1,172 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/7574630614A535710E5A6ABCFFF98BCA2D06A4CA.bc --dump | FileCheck %s
+
+/// \brief Brief description.
+///
+/// Extended description that
+/// continues onto the next line.
+/// 
+/// <ul> class="test">
+///   <li> Testing.
+/// </ul>
+///
+/// \verbatim
+/// The description continues.
+/// \endverbatim
+///
+/// \param [out] I is a parameter.
+/// \param J is a parameter.
+/// \return int
+int F(int I, int J);
+
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-NEXT: </VersionBlock>
+// CHECK-NEXT: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-NEXT: <USR abbrevid=4 op0=20 op1=117 op2=116 op3=99 op4=6 op5=20 op6=165 op7=53 op8=113 op9=14 op10=90 op11=106 op12=188 op13=255 op14=249 op15=139 op16=202 op17=45 op18=6 op19=164 op20=202/>
+  // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F'
+  // CHECK-NEXT: <CommentBlock NumWords=351 BlockCodeSize=4>
+    // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'FullComment'
+    // CHECK-NEXT: <CommentBlock NumWords=13 BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords=31 BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment'
+      // CHECK-NEXT: <Name abbrevid=6 op0=5/> blob data = 'brief'
+      // CHECK-NEXT: <CommentBlock NumWords=19 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+        // CHECK-NEXT: <CommentBlock NumWords=11 BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+          // CHECK-NEXT: <Text abbrevid=5 op0=19/> blob data = ' Brief description.'
+        // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords=37 BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords=13 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=26/> blob data = ' Extended description that'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords=14 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=30/> blob data = ' continues onto the next line.'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords=83 BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords=9 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'HTMLStartTagComment'
+        // CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'ul'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords=10 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=14/> blob data = ' class="test">'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords=9 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'HTMLStartTagComment'
+        // CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'li'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords=9 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=9/> blob data = ' Testing.'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: <CommentBlock NumWords=9 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=17/> blob data = 'HTMLEndTagComment'
+        // CHECK-NEXT: <Name abbrevid=6 op0=2/> blob data = 'ul'
+        // CHECK-NEXT: <SelfClosing abbrevid=10 op0=1/>
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords=13 BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords=32 BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=20/> blob data = 'VerbatimBlockComment'
+      // CHECK-NEXT: <Name abbrevid=6 op0=8/> blob data = 'verbatim'
+      // CHECK-NEXT: <CloseName abbrevid=9 op0=11/> blob data = 'endverbatim'
+      // CHECK-NEXT: <CommentBlock NumWords=16 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=24/> blob data = 'VerbatimBlockLineComment'
+        // CHECK-NEXT: <Text abbrevid=5 op0=27/> blob data = ' The description continues.'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords=13 BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+      // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords=39 BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'ParamCommandComment'
+      // CHECK-NEXT: <Direction abbrevid=7 op0=5/> blob data = '[out]'
+      // CHECK-NEXT: <ParamName abbrevid=8 op0=1/> blob data = 'I'
+      // CHECK-NEXT: <Explicit abbrevid=11 op0=1/>
+      // CHECK-NEXT: <CommentBlock NumWords=25 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+        // CHECK-NEXT: <CommentBlock NumWords=10 BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+          // CHECK-NEXT: <Text abbrevid=5 op0=16/> blob data = ' is a parameter.'
+        // CHECK-NEXT: </CommentBlock>
+        // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords=38 BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'ParamCommandComment'
+      // CHECK-NEXT: <Direction abbrevid=7 op0=4/> blob data = '[in]'
+      // CHECK-NEXT: <ParamName abbrevid=8 op0=1/> blob data = 'J'
+      // CHECK-NEXT: <CommentBlock NumWords=25 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+        // CHECK-NEXT: <CommentBlock NumWords=10 BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+          // CHECK-NEXT: <Text abbrevid=5 op0=16/> blob data = ' is a parameter.'
+        // CHECK-NEXT: </CommentBlock>
+        // CHECK-NEXT: <CommentBlock NumWords=5 BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+        // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: <CommentBlock NumWords=27 BlockCodeSize=4>
+      // CHECK-NEXT: <Kind abbrevid=4 op0=19/> blob data = 'BlockCommandComment'
+      // CHECK-NEXT: <Name abbrevid=6 op0=6/> blob data = 'return'
+      // CHECK-NEXT: <CommentBlock NumWords=15 BlockCodeSize=4>
+        // CHECK-NEXT: <Kind abbrevid=4 op0=16/> blob data = 'ParagraphComment'
+        // CHECK-NEXT: <CommentBlock NumWords=7 BlockCodeSize=4>
+          // CHECK-NEXT: <Kind abbrevid=4 op0=11/> blob data = 'TextComment'
+          // CHECK-NEXT: <Text abbrevid=5 op0=4/> blob data = ' int'
+        // CHECK-NEXT: </CommentBlock>
+      // CHECK-NEXT: </CommentBlock>
+    // CHECK-NEXT: </CommentBlock>
+  // CHECK-NEXT: </CommentBlock>
+  // CHECK-NEXT: <Location abbrevid=8 op0=24 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-NEXT: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+  // CHECK-NEXT: </TypeBlock>
+  // CHECK-NEXT: <FieldTypeBlock NumWords=6 BlockCodeSize=4>
+    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'I'
+  // CHECK-NEXT: </FieldTypeBlock>
+  // CHECK-NEXT: <FieldTypeBlock NumWords=6 BlockCodeSize=4>
+    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'J'
+  // CHECK-NEXT: </FieldTypeBlock>
+// CHECK-NEXT: </FunctionBlock>
diff --git a/test/clang-doc/mapper-enum.cpp b/test/clang-doc/mapper-enum.cpp
new file mode 100644
index 0000000..a4db097
--- /dev/null
+++ b/test/clang-doc/mapper-enum.cpp
@@ -0,0 +1,36 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/FC07BD34D5E77782C263FA944447929EA8753740.bc --dump | FileCheck %s --check-prefix CHECK-B
+// RUN: llvm-bcanalyzer %t/docs/bc/020E6C32A700C3170C009FCCD41671EDDBEAF575.bc --dump | FileCheck %s --check-prefix CHECK-C
+
+enum B { X, Y };
+
+// CHECK-B: <BLOCKINFO_BLOCK/>
+// CHECK-B-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-B-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-B-NEXT: </VersionBlock>
+// CHECK-B-NEXT: <EnumBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-B-NEXT: <USR abbrevid=4 op0=20 op1=252 op2=7 op3=189 op4=52 op5=213 op6=231 op7=119 op8=130 op9=194 op10=99 op11=250 op12=148 op13=68 op14=71 op15=146 op16=158 op17=168 op18=117 op19=55 op20=64/>
+  // CHECK-B-NEXT: <Name abbrevid=5 op0=1/> blob data = 'B'
+  // CHECK-B-NEXT: <DefLocation abbrevid=7 op0=9 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-B-NEXT: <Member abbrevid=9 op0=1/> blob data = 'X'
+  // CHECK-B-NEXT: <Member abbrevid=9 op0=1/> blob data = 'Y'
+// CHECK-B-NEXT: </EnumBlock>
+
+enum class C { A, B };
+
+// CHECK-C: <BLOCKINFO_BLOCK/>
+// CHECK-C-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-C-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-C-NEXT: </VersionBlock>
+// CHECK-C-NEXT: <EnumBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-C-NEXT: <USR abbrevid=4 op0=20 op1=2 op2=14 op3=108 op4=50 op5=167 op6=0 op7=195 op8=23 op9=12 op10=0 op11=159 op12=204 op13=212 op14=22 op15=113 op16=237 op17=219 op18=234 op19=245 op20=117/>
+  // CHECK-C-NEXT: <Name abbrevid=5 op0=1/> blob data = 'C'
+  // CHECK-C-NEXT: <DefLocation abbrevid=7 op0=23 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-C-NEXT: <Scoped abbrevid=10 op0=1/>
+  // CHECK-C-NEXT: <Member abbrevid=9 op0=1/> blob data = 'A'
+  // CHECK-C-NEXT: <Member abbrevid=9 op0=1/> blob data = 'B'
+// CHECK-C-NEXT: </EnumBlock>
diff --git a/test/clang-doc/mapper-function.cpp b/test/clang-doc/mapper-function.cpp
new file mode 100644
index 0000000..07a6ecf
--- /dev/null
+++ b/test/clang-doc/mapper-function.cpp
@@ -0,0 +1,25 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/A44B32CC3C087C9AF75DAF50DE193E85E7B2C16B.bc --dump | FileCheck %s
+
+int F(int param) { return param; }
+
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-NEXT: </VersionBlock>
+// CHECK-NEXT: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-NEXT: <USR abbrevid=4 op0=20 op1=164 op2=75 op3=50 op4=204 op5=60 op6=8 op7=124 op8=154 op9=247 op10=93 op11=175 op12=80 op13=222 op14=25 op15=62 op16=133 op17=231 op18=178 op19=193 op20=107/>
+  // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'F'
+  // CHECK-NEXT: <DefLocation abbrevid=7 op0=8 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-NEXT: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+  // CHECK-NEXT: </TypeBlock>
+  // CHECK-NEXT: <FieldTypeBlock NumWords=7 BlockCodeSize=4>
+    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK-NEXT: <Name abbrevid=5 op0=5/> blob data = 'param'
+  // CHECK-NEXT: </FieldTypeBlock>
+// CHECK-NEXT: </FunctionBlock>
diff --git a/test/clang-doc/mapper-method.cpp b/test/clang-doc/mapper-method.cpp
new file mode 100644
index 0000000..7d16d7c
--- /dev/null
+++ b/test/clang-doc/mapper-method.cpp
@@ -0,0 +1,43 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/F0F9FC65FC90F54F690144A7AFB15DFC3D69B6E6.bc --dump | FileCheck %s --check-prefix CHECK-G-F
+// RUN: llvm-bcanalyzer %t/docs/bc/4202E8BF0ECB12AE354C8499C52725B0EE30AED5.bc --dump | FileCheck %s --check-prefix CHECK-G
+
+class G {
+public: 
+	int Method(int param) { return param; }
+};
+
+// CHECK-G: <BLOCKINFO_BLOCK/>
+// CHECK-G-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-G-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-G-NEXT: </VersionBlock>
+// CHECK-G-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-G-NEXT: <USR abbrevid=4 op0=20 op1=66 op2=2 op3=232 op4=191 op5=14 op6=203 op7=18 op8=174 op9=53 op10=76 op11=132 op12=153 op13=197 op14=39 op15=37 op16=176 op17=238 op18=48 op19=174 op20=213/>
+  // CHECK-G-NEXT: <Name abbrevid=5 op0=1/> blob data = 'G'
+  // CHECK-G-NEXT: <DefLocation abbrevid=7 op0=9 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-G-NEXT: <TagType abbrevid=9 op0=3/>
+// CHECK-G-NEXT: </RecordBlock>
+
+// CHECK-G-F: <BLOCKINFO_BLOCK/>
+// CHECK-G-F-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-G-F-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-G-F-NEXT: </VersionBlock>
+// CHECK-G-F-NEXT: <FunctionBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-G-F-NEXT: <USR abbrevid=4 op0=20 op1=240 op2=249 op3=252 op4=101 op5=252 op6=144 op7=245 op8=79 op9=105 op10=1 op11=68 op12=167 op13=175 op14=177 op15=93 op16=252 op17=61 op18=105 op19=182 op20=230/>
+  // CHECK-G-F-NEXT: <Name abbrevid=5 op0=6/> blob data = 'Method'
+  // CHECK-G-F-NEXT: <Namespace abbrevid=6 op0=1 op1=40/> blob data = '4202E8BF0ECB12AE354C8499C52725B0EE30AED5'
+  // CHECK-G-F-NEXT: <IsMethod abbrevid=11 op0=1/>
+  // CHECK-G-F-NEXT: <DefLocation abbrevid=7 op0=11 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-G-F-NEXT: <Parent abbrevid=9 op0=1 op1=40/> blob data = '4202E8BF0ECB12AE354C8499C52725B0EE30AED5'
+  // CHECK-G-F-NEXT: <TypeBlock NumWords=4 BlockCodeSize=4>
+    // CHECK-G-F-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+  // CHECK-G-F-NEXT: </TypeBlock>
+  // CHECK-G-F-NEXT: <FieldTypeBlock NumWords=7 BlockCodeSize=4>
+    // CHECK-G-F-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK-G-F-NEXT: <Name abbrevid=5 op0=5/> blob data = 'param'
+  // CHECK-G-F-NEXT: </FieldTypeBlock>
+// CHECK-G-F-NEXT: </FunctionBlock>
diff --git a/test/clang-doc/mapper-namespace.cpp b/test/clang-doc/mapper-namespace.cpp
new file mode 100644
index 0000000..e46dfda
--- /dev/null
+++ b/test/clang-doc/mapper-namespace.cpp
@@ -0,0 +1,17 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/8D042EFFC98B373450BC6B5B90A330C25A150E9C.bc --dump | FileCheck %s
+
+namespace A {}
+
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-NEXT: </VersionBlock>
+// CHECK-NEXT: <NamespaceBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-NEXT: <USR abbrevid=4 op0=20 op1=141 op2=4 op3=46 op4=255 op5=201 op6=139 op7=55 op8=52 op9=80 op10=188 op11=107 op12=91 op13=144 op14=163 op15=48 op16=194 op17=90 op18=21 op19=14 op20=156/>
+  // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'A'
+// CHECK-NEXT: </NamespaceBlock>
diff --git a/test/clang-doc/mapper-struct.cpp b/test/clang-doc/mapper-struct.cpp
new file mode 100644
index 0000000..f13dd60
--- /dev/null
+++ b/test/clang-doc/mapper-struct.cpp
@@ -0,0 +1,23 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/06B5F6A19BA9F6A832E127C9968282B94619B210.bc --dump | FileCheck %s
+
+struct C { int i; };
+
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-NEXT: </VersionBlock>
+// CHECK-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-NEXT: <USR abbrevid=4 op0=20 op1=6 op2=181 op3=246 op4=161 op5=155 op6=169 op7=246 op8=168 op9=50 op10=225 op11=39 op12=201 op13=150 op14=130 op15=130 op16=185 op17=70 op18=25 op19=178 op20=16/>
+  // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'C'
+  // CHECK-NEXT: <DefLocation abbrevid=7 op0=8 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-NEXT: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
+    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK-NEXT: <Name abbrevid=5 op0=4/> blob data = 'C::i'
+    // CHECK-NEXT: <Access abbrevid=6 op0=3/>
+  // CHECK-NEXT: </MemberTypeBlock>
+// CHECK-NEXT: </RecordBlock>
diff --git a/test/clang-doc/mapper-union.cpp b/test/clang-doc/mapper-union.cpp
new file mode 100644
index 0000000..33b0aa9
--- /dev/null
+++ b/test/clang-doc/mapper-union.cpp
@@ -0,0 +1,29 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --dump-mapper -doxygen -p %t %t/test.cpp -output=%t/docs
+// RUN: llvm-bcanalyzer %t/docs/bc/0B8A6B938B939B77C6325CCCC8AA3E938BF9E2E8.bc --dump | FileCheck %s
+
+union D { int X; int Y; };
+
+// CHECK: <BLOCKINFO_BLOCK/>
+// CHECK-NEXT: <VersionBlock NumWords=1 BlockCodeSize=4>
+  // CHECK-NEXT: <Version abbrevid=4 op0=1/>
+// CHECK-NEXT: </VersionBlock>
+// CHECK-NEXT: <RecordBlock NumWords={{[0-9]*}} BlockCodeSize=4>
+  // CHECK-NEXT: <USR abbrevid=4 op0=20 op1=11 op2=138 op3=107 op4=147 op5=139 op6=147 op7=155 op8=119 op9=198 op10=50 op11=92 op12=204 op13=200 op14=170 op15=62 op16=147 op17=139 op18=249 op19=226 op20=232/>
+  // CHECK-NEXT: <Name abbrevid=5 op0=1/> blob data = 'D'
+  // CHECK-NEXT: <DefLocation abbrevid=7 op0=8 op1={{[0-9]*}}/> blob data = '{{.*}}'
+  // CHECK-NEXT: <TagType abbrevid=9 op0=2/>
+  // CHECK-NEXT: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
+    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK-NEXT: <Name abbrevid=5 op0=4/> blob data = 'D::X'
+    // CHECK-NEXT: <Access abbrevid=6 op0=3/>
+  // CHECK-NEXT: </MemberTypeBlock>
+  // CHECK-NEXT: <MemberTypeBlock NumWords=6 BlockCodeSize=4>
+    // CHECK-NEXT: <Type abbrevid=4 op0=4 op1=3/> blob data = 'int'
+    // CHECK-NEXT: <Name abbrevid=5 op0=4/> blob data = 'D::Y'
+    // CHECK-NEXT: <Access abbrevid=6 op0=3/>
+  // CHECK-NEXT: </MemberTypeBlock>
+// CHECK-NEXT: </RecordBlock>
diff --git a/test/clang-tidy/abseil-string-find-startswith.cpp b/test/clang-tidy/abseil-string-find-startswith.cpp
new file mode 100644
index 0000000..194e795
--- /dev/null
+++ b/test/clang-tidy/abseil-string-find-startswith.cpp
@@ -0,0 +1,55 @@
+// RUN: %check_clang_tidy %s abseil-string-find-startswith %t
+
+namespace std {
+template <typename T> class allocator {};
+template <typename T> class char_traits {};
+template <typename C, typename T = std::char_traits<C>,
+          typename A = std::allocator<C>>
+struct basic_string {
+  basic_string();
+  basic_string(const basic_string &);
+  basic_string(const C *, const A &a = A());
+  ~basic_string();
+  int find(basic_string<C> s, int pos = 0);
+  int find(const char *s, int pos = 0);
+};
+typedef basic_string<char> string;
+typedef basic_string<wchar_t> wstring;
+} // namespace std
+
+std::string foo(std::string);
+std::string bar();
+
+#define A_MACRO(x, y) ((x) == (y))
+
+void tests(std::string s) {
+  s.find("a") == 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith instead of find() == 0 [abseil-string-find-startswith]
+  // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s, "a");{{$}}
+
+  s.find(s) == 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use absl::StartsWith
+  // CHECK-FIXES: {{^[[:space:]]*}}absl::StartsWith(s, s);{{$}}
+
+  s.find("aaa") != 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
+  // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, "aaa");{{$}}
+
+  s.find(foo(foo(bar()))) != 0;
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
+  // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, foo(foo(bar())));{{$}}
+
+  if (s.find("....") == 0) { /* do something */ }
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use absl::StartsWith
+  // CHECK-FIXES: {{^[[:space:]]*}}if (absl::StartsWith(s, "....")) { /* do something */ }{{$}}
+
+  0 != s.find("a");
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use !absl::StartsWith
+  // CHECK-FIXES: {{^[[:space:]]*}}!absl::StartsWith(s, "a");{{$}}
+
+  // expressions that don't trigger the check are here.
+  A_MACRO(s.find("a"), 0);
+  s.find("a", 1) == 0;
+  s.find("a", 1) == 1;
+  s.find("a") == 1;
+}
diff --git a/test/clang-tidy/misc-macro-parentheses-cmdline.cpp b/test/clang-tidy/bugprone-macro-parentheses-cmdline.cpp
similarity index 79%
rename from test/clang-tidy/misc-macro-parentheses-cmdline.cpp
rename to test/clang-tidy/bugprone-macro-parentheses-cmdline.cpp
index f7e8088..9ff757d 100644
--- a/test/clang-tidy/misc-macro-parentheses-cmdline.cpp
+++ b/test/clang-tidy/bugprone-macro-parentheses-cmdline.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-macro-parentheses %t -- -- -DVAL=0+0
+// RUN: %check_clang_tidy %s bugprone-macro-parentheses %t -- -- -DVAL=0+0
 
 // The previous command-line is producing warnings and fixes with the source
 // locations from a virtual buffer. VAL is replaced by '0+0'.
diff --git a/test/clang-tidy/misc-macro-parentheses.cpp b/test/clang-tidy/bugprone-macro-parentheses.cpp
similarity index 82%
rename from test/clang-tidy/misc-macro-parentheses.cpp
rename to test/clang-tidy/bugprone-macro-parentheses.cpp
index 11d7c7b..2cc45e8 100644
--- a/test/clang-tidy/misc-macro-parentheses.cpp
+++ b/test/clang-tidy/bugprone-macro-parentheses.cpp
@@ -1,15 +1,15 @@
-// RUN: %check_clang_tidy %s misc-macro-parentheses %t
+// RUN: %check_clang_tidy %s bugprone-macro-parentheses %t
 
 #define BAD1              -1
-// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: macro replacement list should be enclosed in parentheses [misc-macro-parentheses]
+// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: macro replacement list should be enclosed in parentheses [bugprone-macro-parentheses]
 #define BAD2              1+2
-// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: macro replacement list should be enclosed in parentheses [misc-macro-parentheses]
+// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: macro replacement list should be enclosed in parentheses [bugprone-macro-parentheses]
 #define BAD3(A)           (A+1)
-// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: macro argument should be enclosed in parentheses [misc-macro-parentheses]
+// CHECK-MESSAGES: :[[@LINE-1]]:28: warning: macro argument should be enclosed in parentheses [bugprone-macro-parentheses]
 #define BAD4(x)           ((unsigned char)(x & 0xff))
-// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: macro argument should be enclosed in parentheses [misc-macro-parentheses]
+// CHECK-MESSAGES: :[[@LINE-1]]:44: warning: macro argument should be enclosed in parentheses [bugprone-macro-parentheses]
 #define BAD5(X)           A*B=(C*)X+2
-// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: macro argument should be enclosed in parentheses [misc-macro-parentheses]
+// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: macro argument should be enclosed in parentheses [bugprone-macro-parentheses]
 
 #define GOOD1             1
 #define GOOD2             (1+2)
diff --git a/test/clang-tidy/misc-sizeof-container.cpp b/test/clang-tidy/bugprone-sizeof-container.cpp
similarity index 91%
rename from test/clang-tidy/misc-sizeof-container.cpp
rename to test/clang-tidy/bugprone-sizeof-container.cpp
index 472587e..27798d6 100644
--- a/test/clang-tidy/misc-sizeof-container.cpp
+++ b/test/clang-tidy/bugprone-sizeof-container.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-sizeof-container %t -- -- -std=c++11 -target x86_64-unknown-unknown
+// RUN: %check_clang_tidy %s bugprone-sizeof-container %t -- -- -std=c++11 -target x86_64-unknown-unknown
 
 namespace std {
 
@@ -64,7 +64,7 @@
   std::vector<int> v;
 
   int a = 42 + sizeof(s1);
-// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: sizeof() doesn't return the size of the container; did you mean .size()? [misc-sizeof-container]
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: sizeof() doesn't return the size of the container; did you mean .size()? [bugprone-sizeof-container]
   a = 123 * sizeof(s2);
 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: sizeof() doesn't return the size
   a = 45 + sizeof(s2 + "asdf");
diff --git a/test/clang-tidy/misc-sizeof-expression.cpp b/test/clang-tidy/bugprone-sizeof-expression.cpp
similarity index 99%
rename from test/clang-tidy/misc-sizeof-expression.cpp
rename to test/clang-tidy/bugprone-sizeof-expression.cpp
index f9d798d..1a14f68 100644
--- a/test/clang-tidy/misc-sizeof-expression.cpp
+++ b/test/clang-tidy/bugprone-sizeof-expression.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-sizeof-expression %t
+// RUN: %check_clang_tidy %s bugprone-sizeof-expression %t
 
 class C {
   int size() { return sizeof(this); }
diff --git a/test/clang-tidy/misc-unused-raii.cpp b/test/clang-tidy/bugprone-unused-raii.cpp
similarity index 95%
rename from test/clang-tidy/misc-unused-raii.cpp
rename to test/clang-tidy/bugprone-unused-raii.cpp
index f22746c..91ade52 100644
--- a/test/clang-tidy/misc-unused-raii.cpp
+++ b/test/clang-tidy/bugprone-unused-raii.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s misc-unused-raii %t
+// RUN: %check_clang_tidy %s bugprone-unused-raii %t
 
 struct Foo {
   Foo();
diff --git a/test/clang-tidy/bugprone-unused-return-value-custom.cpp b/test/clang-tidy/bugprone-unused-return-value-custom.cpp
new file mode 100644
index 0000000..4f498dd
--- /dev/null
+++ b/test/clang-tidy/bugprone-unused-return-value-custom.cpp
@@ -0,0 +1,82 @@
+// RUN: %check_clang_tidy %s bugprone-unused-return-value %t \
+// RUN: -config='{CheckOptions: \
+// RUN:  [{key: bugprone-unused-return-value.CheckedFunctions, \
+// RUN:    value: "::fun;::ns::Outer::Inner::memFun;::ns::Type::staticFun"}]}' \
+// RUN: --
+
+namespace std {
+
+template <typename T>
+T *launder(T *);
+
+} // namespace std
+
+namespace ns {
+
+struct Outer {
+  struct Inner {
+    bool memFun();
+  };
+};
+
+using AliasName = Outer;
+
+struct Derived : public Outer::Inner {};
+
+struct Retval {
+  int *P;
+  Retval() { P = new int; }
+  ~Retval() { delete P; }
+};
+
+struct Type {
+  Retval memFun();
+  static Retval staticFun();
+};
+
+} // namespace ns
+
+int fun();
+void fun(int);
+
+void warning() {
+  fun();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  (fun());
+  // CHECK-MESSAGES: [[@LINE-1]]:4: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  ns::Outer::Inner ObjA1;
+  ObjA1.memFun();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  ns::AliasName::Inner ObjA2;
+  ObjA2.memFun();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  ns::Derived ObjA3;
+  ObjA3.memFun();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  ns::Type::staticFun();
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+}
+
+void noWarning() {
+  auto R1 = fun();
+
+  ns::Outer::Inner ObjB1;
+  auto R2 = ObjB1.memFun();
+
+  auto R3 = ns::Type::staticFun();
+
+  // test calling a void overload of a checked function
+  fun(5);
+
+  // test discarding return value of functions that are not configured to be checked
+  int I = 1;
+  std::launder(&I);
+
+  ns::Type ObjB2;
+  ObjB2.memFun();
+}
diff --git a/test/clang-tidy/bugprone-unused-return-value.cpp b/test/clang-tidy/bugprone-unused-return-value.cpp
new file mode 100644
index 0000000..de9184d
--- /dev/null
+++ b/test/clang-tidy/bugprone-unused-return-value.cpp
@@ -0,0 +1,166 @@
+// RUN: %check_clang_tidy %s bugprone-unused-return-value %t -- -- -fexceptions
+
+namespace std {
+
+struct future {};
+
+enum class launch {
+  async,
+  deferred
+};
+
+template <typename Function, typename... Args>
+future async(Function &&, Args &&...);
+
+template <typename Function, typename... Args>
+future async(launch, Function &&, Args &&...);
+
+template <typename ForwardIt, typename T>
+ForwardIt remove(ForwardIt, ForwardIt, const T &);
+
+template <typename ForwardIt, typename UnaryPredicate>
+ForwardIt remove_if(ForwardIt, ForwardIt, UnaryPredicate);
+
+template <typename ForwardIt>
+ForwardIt unique(ForwardIt, ForwardIt);
+
+// the check should be able to match std lib calls even if the functions are
+// declared inside inline namespaces
+inline namespace v1 {
+
+template <typename T>
+T *launder(T *);
+
+} // namespace v1
+} // namespace std
+
+struct Foo {
+  void f();
+};
+
+int increment(int i) {
+  return i + 1;
+}
+
+void useFuture(const std::future &fut);
+
+void warning() {
+  std::async(increment, 42);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  std::async(std::launch::async, increment, 42);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  Foo F;
+  std::launder(&F);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  std::remove(nullptr, nullptr, 1);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  std::remove_if(nullptr, nullptr, nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  std::unique(nullptr, nullptr);
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  // test discarding return values inside different kinds of statements
+
+  auto Lambda = [] { std::remove(nullptr, nullptr, 1); };
+  // CHECK-MESSAGES: [[@LINE-1]]:22: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  if (true)
+    std::remove(nullptr, nullptr, 1);
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+  else if (true)
+    std::remove(nullptr, nullptr, 1);
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+  else
+    std::remove(nullptr, nullptr, 1);
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  while (true)
+    std::remove(nullptr, nullptr, 1);
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  do
+    std::remove(nullptr, nullptr, 1);
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+  while (true);
+
+  for (;;)
+    std::remove(nullptr, nullptr, 1);
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  for (std::remove(nullptr, nullptr, 1);;)
+    // CHECK-MESSAGES: [[@LINE-1]]:8: warning: the value returned by this function should be used [bugprone-unused-return-value]
+    ;
+
+  for (;; std::remove(nullptr, nullptr, 1))
+    // CHECK-MESSAGES: [[@LINE-1]]:11: warning: the value returned by this function should be used [bugprone-unused-return-value]
+    ;
+
+  for (auto C : "foo")
+    std::remove(nullptr, nullptr, 1);
+  // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+
+  switch (1) {
+  case 1:
+    std::remove(nullptr, nullptr, 1);
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+    break;
+  default:
+    std::remove(nullptr, nullptr, 1);
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+    break;
+  }
+
+  try {
+    std::remove(nullptr, nullptr, 1);
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+  } catch (...) {
+    std::remove(nullptr, nullptr, 1);
+    // CHECK-MESSAGES: [[@LINE-1]]:5: warning: the value returned by this function should be used [bugprone-unused-return-value]
+  }
+}
+
+void noWarning() {
+  auto AsyncRetval1 = std::async(increment, 42);
+  auto AsyncRetval2 = std::async(std::launch::async, increment, 42);
+
+  Foo FNoWarning;
+  auto LaunderRetval = std::launder(&FNoWarning);
+
+  auto RemoveRetval = std::remove(nullptr, nullptr, 1);
+
+  auto RemoveIfRetval = std::remove_if(nullptr, nullptr, nullptr);
+
+  auto UniqueRetval = std::unique(nullptr, nullptr);
+
+  // test using the return value in different kinds of expressions
+  useFuture(std::async(increment, 42));
+  std::launder(&FNoWarning)->f();
+  delete std::launder(&FNoWarning);
+
+  if (std::launder(&FNoWarning))
+    ;
+  for (; std::launder(&FNoWarning);)
+    ;
+  while (std::launder(&FNoWarning))
+    ;
+  do
+    ;
+  while (std::launder(&FNoWarning));
+  switch (std::unique(1, 1))
+    ;
+
+  // cast to void should allow ignoring the return value
+  (void)std::async(increment, 42);
+
+  // test discarding return value of functions that are not configured to be checked
+  increment(1);
+
+  // test that the check is disabled inside GNU statement expressions
+  ({ std::async(increment, 42); });
+  auto StmtExprRetval = ({ std::async(increment, 42); });
+}
diff --git a/test/clang-tidy/hicpp-multiway-paths-covered-else.cpp b/test/clang-tidy/hicpp-multiway-paths-covered-else.cpp
new file mode 100644
index 0000000..34820b5
--- /dev/null
+++ b/test/clang-tidy/hicpp-multiway-paths-covered-else.cpp
@@ -0,0 +1,57 @@
+// RUN: %check_clang_tidy %s hicpp-multiway-paths-covered %t \
+// RUN: -config='{CheckOptions: \
+// RUN:  [{key: hicpp-multiway-paths-covered.WarnOnMissingElse, value: 1}]}'\
+// RUN: --
+
+enum OS { Mac,
+          Windows,
+          Linux };
+
+void problematic_if(int i, enum OS os) {
+  if (i > 0) {
+    return;
+  } else if (i < 0) {
+    // CHECK-MESSAGES: [[@LINE-1]]:10: warning: potentially uncovered codepath; add an ending else statement
+    return;
+  }
+
+  // Could be considered as false positive because all paths are covered logically.
+  // I still think this is valid since the possibility of a final 'everything else'
+  // codepath is expected from if-else if.
+  if (i > 0) {
+    return;
+  } else if (i <= 0) {
+    // CHECK-MESSAGES: [[@LINE-1]]:10: warning: potentially uncovered codepath; add an ending else statement
+    return;
+  }
+
+  // Test if nesting of if-else chains does get caught as well.
+  if (os == Mac) {
+    return;
+  } else if (os == Linux) {
+    // These checks are kind of degenerated, but the check will not try to solve
+    // if logically all paths are covered, which is more the area of the static analyzer.
+    if (true) {
+      return;
+    } else if (false) {
+      // CHECK-MESSAGES: [[@LINE-1]]:12: warning: potentially uncovered codepath; add an ending else statement
+      return;
+    }
+    return;
+  } else {
+    /* unreachable */
+    if (true) // check if the parent would match here as well
+      return;
+    // No warning for simple if statements, since it is common to just test one condition
+    // and ignore the opposite.
+  }
+
+  // Ok, because all paths are covered
+  if (i > 0) {
+    return;
+  } else if (i < 0) {
+    return;
+  } else {
+    /* error, maybe precondition failed */
+  }
+}
diff --git a/test/clang-tidy/hicpp-multiway-paths-covered.cpp b/test/clang-tidy/hicpp-multiway-paths-covered.cpp
new file mode 100644
index 0000000..15a3407
--- /dev/null
+++ b/test/clang-tidy/hicpp-multiway-paths-covered.cpp
@@ -0,0 +1,468 @@
+// RUN: %check_clang_tidy %s hicpp-multiway-paths-covered %t
+
+enum OS { Mac,
+          Windows,
+          Linux };
+
+struct Bitfields {
+  unsigned UInt : 3;
+  int SInt : 1;
+};
+
+int return_integer() { return 42; }
+
+void bad_switch(int i) {
+  switch (i) {
+    // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch with only one case; use an if statement
+  case 0:
+    break;
+  }
+  // No default in this switch
+  switch (i) {
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+  case 0:
+    break;
+  case 1:
+    break;
+  case 2:
+    break;
+  }
+
+  // degenerate, maybe even warning
+  switch (i) {
+    // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch statement without labels has no effect
+  }
+
+  switch (int j = return_integer()) {
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+  case 0:
+  case 1:
+  case 2:
+    break;
+  }
+
+  // Degenerated, only default case.
+  switch (i) {
+    // CHECK-MESSAGES: [[@LINE-1]]:3: warning: degenerated switch with default label only
+  default:
+    break;
+  }
+
+  // Degenerated, only one case label and default case -> Better as if-stmt.
+  switch (i) {
+    // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch could be better written as an if/else statement
+  case 0:
+    break;
+  default:
+    break;
+  }
+
+  unsigned long long BigNumber = 0;
+  switch (BigNumber) {
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+  case 0:
+  case 1:
+    break;
+  }
+
+  const int &IntRef = i;
+  switch (IntRef) {
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+  case 0:
+  case 1:
+    break;
+  }
+
+  char C = 'A';
+  switch (C) {
+  // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+  case 'A':
+    break;
+  case 'B':
+    break;
+  }
+
+  Bitfields Bf;
+  // UInt has 3 bits size.
+  switch (Bf.UInt) {
+    // CHECK-MESSAGES: [[@LINE-1]]:3: warning: potential uncovered code path; add a default label
+  case 0:
+  case 1:
+    break;
+  }
+  // All paths explicitly covered.
+  switch (Bf.UInt) {
+  case 0:
+  case 1:
+  case 2:
+  case 3:
+  case 4:
+  case 5:
+  case 6:
+  case 7:
+    break;
+  }
+  // SInt has 1 bit size, so this is somewhat degenerated.
+  switch (Bf.SInt) {
+    // CHECK-MESSAGES: [[@LINE-1]]:3: warning: switch with only one case; use an if statement
+  case 0:
+    break;
+  }
+  // All paths explicitly covered.
+  switch (Bf.SInt) {
+  case 0:
+  case 1:
+    break;
+  }
+
+  bool Flag = false;
+  switch (Flag) {
+    // CHECK-MESSAGES:[[@LINE-1]]:3: warning: switch with only one case; use an if statement
+  case true:
+    break;
+  }
+
+  switch (Flag) {
+    // CHECK-MESSAGES: [[@LINE-1]]:3: warning: degenerated switch with default label only
+  default:
+    break;
+  }
+
+  // This `switch` will create a frontend warning from '-Wswitch-bool' but is
+  // ok for this check.
+  switch (Flag) {
+  case true:
+    break;
+  case false:
+    break;
+  }
+}
+
+void unproblematic_switch(unsigned char c) {
+  //
+  switch (c) {
+  case 0:
+  case 1:
+  case 2:
+  case 3:
+  case 4:
+  case 5:
+  case 6:
+  case 7:
+  case 8:
+  case 9:
+  case 10:
+  case 11:
+  case 12:
+  case 13:
+  case 14:
+  case 15:
+  case 16:
+  case 17:
+  case 18:
+  case 19:
+  case 20:
+  case 21:
+  case 22:
+  case 23:
+  case 24:
+  case 25:
+  case 26:
+  case 27:
+  case 28:
+  case 29:
+  case 30:
+  case 31:
+  case 32:
+  case 33:
+  case 34:
+  case 35:
+  case 36:
+  case 37:
+  case 38:
+  case 39:
+  case 40:
+  case 41:
+  case 42:
+  case 43:
+  case 44:
+  case 45:
+  case 46:
+  case 47:
+  case 48:
+  case 49:
+  case 50:
+  case 51:
+  case 52:
+  case 53:
+  case 54:
+  case 55:
+  case 56:
+  case 57:
+  case 58:
+  case 59:
+  case 60:
+  case 61:
+  case 62:
+  case 63:
+  case 64:
+  case 65:
+  case 66:
+  case 67:
+  case 68:
+  case 69:
+  case 70:
+  case 71:
+  case 72:
+  case 73:
+  case 74:
+  case 75:
+  case 76:
+  case 77:
+  case 78:
+  case 79:
+  case 80:
+  case 81:
+  case 82:
+  case 83:
+  case 84:
+  case 85:
+  case 86:
+  case 87:
+  case 88:
+  case 89:
+  case 90:
+  case 91:
+  case 92:
+  case 93:
+  case 94:
+  case 95:
+  case 96:
+  case 97:
+  case 98:
+  case 99:
+  case 100:
+  case 101:
+  case 102:
+  case 103:
+  case 104:
+  case 105:
+  case 106:
+  case 107:
+  case 108:
+  case 109:
+  case 110:
+  case 111:
+  case 112:
+  case 113:
+  case 114:
+  case 115:
+  case 116:
+  case 117:
+  case 118:
+  case 119:
+  case 120:
+  case 121:
+  case 122:
+  case 123:
+  case 124:
+  case 125:
+  case 126:
+  case 127:
+  case 128:
+  case 129:
+  case 130:
+  case 131:
+  case 132:
+  case 133:
+  case 134:
+  case 135:
+  case 136:
+  case 137:
+  case 138:
+  case 139:
+  case 140:
+  case 141:
+  case 142:
+  case 143:
+  case 144:
+  case 145:
+  case 146:
+  case 147:
+  case 148:
+  case 149:
+  case 150:
+  case 151:
+  case 152:
+  case 153:
+  case 154:
+  case 155:
+  case 156:
+  case 157:
+  case 158:
+  case 159:
+  case 160:
+  case 161:
+  case 162:
+  case 163:
+  case 164:
+  case 165:
+  case 166:
+  case 167:
+  case 168:
+  case 169:
+  case 170:
+  case 171:
+  case 172:
+  case 173:
+  case 174:
+  case 175:
+  case 176:
+  case 177:
+  case 178:
+  case 179:
+  case 180:
+  case 181:
+  case 182:
+  case 183:
+  case 184:
+  case 185:
+  case 186:
+  case 187:
+  case 188:
+  case 189:
+  case 190:
+  case 191:
+  case 192:
+  case 193:
+  case 194:
+  case 195:
+  case 196:
+  case 197:
+  case 198:
+  case 199:
+  case 200:
+  case 201:
+  case 202:
+  case 203:
+  case 204:
+  case 205:
+  case 206:
+  case 207:
+  case 208:
+  case 209:
+  case 210:
+  case 211:
+  case 212:
+  case 213:
+  case 214:
+  case 215:
+  case 216:
+  case 217:
+  case 218:
+  case 219:
+  case 220:
+  case 221:
+  case 222:
+  case 223:
+  case 224:
+  case 225:
+  case 226:
+  case 227:
+  case 228:
+  case 229:
+  case 230:
+  case 231:
+  case 232:
+  case 233:
+  case 234:
+  case 235:
+  case 236:
+  case 237:
+  case 238:
+  case 239:
+  case 240:
+  case 241:
+  case 242:
+  case 243:
+  case 244:
+  case 245:
+  case 246:
+  case 247:
+  case 248:
+  case 249:
+  case 250:
+  case 251:
+  case 252:
+  case 253:
+  case 254:
+  case 255:
+    break;
+  }
+
+  // Some paths are covered by the switch and a default case is present.
+  switch (c) {
+  case 1:
+  case 2:
+  case 3:
+  default:
+    break;
+  }
+}
+
+OS return_enumerator() {
+  return Linux;
+}
+
+// Enumpaths are already covered by a warning, this is just to ensure, that there is
+// no interference or false positives.
+// -Wswitch warns about uncovered enum paths and each here described case is already
+// covered.
+void switch_enums(OS os) {
+  switch (os) {
+  case Linux:
+    break;
+  }
+
+  switch (OS another_os = return_enumerator()) {
+  case Linux:
+    break;
+  }
+
+  switch (os) {
+  }
+}
+
+/// All of these cases will not emit a warning per default, but with explicit activation.
+/// Covered in extra test file.
+void problematic_if(int i, enum OS os) {
+  if (i > 0) {
+    return;
+  } else if (i < 0) {
+    return;
+  }
+
+  if (os == Mac) {
+    return;
+  } else if (os == Linux) {
+    if (true) {
+      return;
+    } else if (false) {
+      return;
+    }
+    return;
+  } else {
+    /* unreachable */
+    if (true) // check if the parent would match here as well
+      return;
+  }
+
+  // Ok, because all paths are covered
+  if (i > 0) {
+    return;
+  } else if (i < 0) {
+    return;
+  } else {
+    /* error, maybe precondition failed */
+  }
+}
diff --git a/test/clang-tidy/hicpp-no-assembler-msvc.cpp b/test/clang-tidy/hicpp-no-assembler-msvc.cpp
index f89e92b..d29a9e9 100644
--- a/test/clang-tidy/hicpp-no-assembler-msvc.cpp
+++ b/test/clang-tidy/hicpp-no-assembler-msvc.cpp
@@ -1,4 +1,6 @@
 // REQUIRES: system-windows
+// FIXME: Re-enable test on windows (PR36855)
+// UNSUPPORTED: system-windows
 // RUN: %check_clang_tidy %s hicpp-no-assembler %t
 
 void f() {
diff --git a/test/clang-tidy/modernize-make-unique-cxx11.cpp b/test/clang-tidy/modernize-make-unique-cxx11.cpp
new file mode 100644
index 0000000..89beb08
--- /dev/null
+++ b/test/clang-tidy/modernize-make-unique-cxx11.cpp
@@ -0,0 +1,10 @@
+// RUN: %check_clang_tidy %s modernize-make-unique %t -- -- -std=c++11 \
+// RUN:   -I%S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+// CHECK-FIXES: #include "unique_ptr.h"
+
+void f() {
+  auto my_ptr = std::unique_ptr<int>(new int(1));
+  // CHECK-FIXES: auto my_ptr = std::unique_ptr<int>(new int(1));
+}
diff --git a/test/clang-tidy/modernize-make-unique-cxx14.cpp b/test/clang-tidy/modernize-make-unique-cxx14.cpp
new file mode 100644
index 0000000..cd35f75
--- /dev/null
+++ b/test/clang-tidy/modernize-make-unique-cxx14.cpp
@@ -0,0 +1,11 @@
+// RUN: %check_clang_tidy %s modernize-make-unique %t -- -- -std=c++14 \
+// RUN:   -I%S/Inputs/modernize-smart-ptr
+
+#include "unique_ptr.h"
+// CHECK-FIXES: #include <memory>
+
+void f() {
+  auto my_ptr = std::unique_ptr<int>(new int(1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use std::make_unique instead
+  // CHECK-FIXES: auto my_ptr = std::make_unique<int>(1);
+}
diff --git a/test/clang-tidy/modernize-make-unique-macros.cpp b/test/clang-tidy/modernize-make-unique-macros.cpp
index e3e5479..117a45c 100644
--- a/test/clang-tidy/modernize-make-unique-macros.cpp
+++ b/test/clang-tidy/modernize-make-unique-macros.cpp
@@ -1,6 +1,6 @@
 // RUN: %check_clang_tidy %s modernize-make-unique %t -- \
 // RUN:   -config="{CheckOptions: [{key: modernize-make-unique.IgnoreMacros, value: 0}]}" \
-// RUN:   -- -std=c++11  -I%S/Inputs/modernize-smart-ptr
+// RUN:   -- -std=c++14  -I%S/Inputs/modernize-smart-ptr
 
 #include "unique_ptr.h"
 
diff --git a/test/clang-tidy/modernize-make-unique.cpp b/test/clang-tidy/modernize-make-unique.cpp
index 1e06d38..9685203 100644
--- a/test/clang-tidy/modernize-make-unique.cpp
+++ b/test/clang-tidy/modernize-make-unique.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s modernize-make-unique %t -- -- -std=c++11 \
+// RUN: %check_clang_tidy %s modernize-make-unique %t -- -- -std=c++14 \
 // RUN:   -I%S/Inputs/modernize-smart-ptr
 
 #include "unique_ptr.h"
diff --git a/test/clang-tidy/portability-simd-intrinsics-ppc.cpp b/test/clang-tidy/portability-simd-intrinsics-ppc.cpp
new file mode 100644
index 0000000..be0ef76
--- /dev/null
+++ b/test/clang-tidy/portability-simd-intrinsics-ppc.cpp
@@ -0,0 +1,13 @@
+// RUN: %check_clang_tidy %s portability-simd-intrinsics %t -- \
+// RUN:  -config='{CheckOptions: [ \
+// RUN:    {key: portability-simd-intrinsics.Suggest, value: 1} \
+// RUN:  ]}' -- -target ppc64le -maltivec -std=c++11
+
+vector int vec_add(vector int, vector int);
+
+void PPC() {
+  vector int i0, i1;
+
+  vec_add(i0, i1);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'vec_add' can be replaced by operator+ on std::experimental::simd objects [portability-simd-intrinsics]
+}
diff --git a/test/clang-tidy/readability-simd-intrinsics-x86.cpp b/test/clang-tidy/portability-simd-intrinsics-x86.cpp
similarity index 72%
rename from test/clang-tidy/readability-simd-intrinsics-x86.cpp
rename to test/clang-tidy/portability-simd-intrinsics-x86.cpp
index 8ab3556..1fb2289 100644
--- a/test/clang-tidy/readability-simd-intrinsics-x86.cpp
+++ b/test/clang-tidy/portability-simd-intrinsics-x86.cpp
@@ -1,6 +1,6 @@
-// RUN: %check_clang_tidy %s readability-simd-intrinsics %t -- \
+// RUN: %check_clang_tidy %s portability-simd-intrinsics %t -- \
 // RUN:  -config='{CheckOptions: [ \
-// RUN:    {key: readability-simd-intrinsics.Suggest, value: 1} \
+// RUN:    {key: portability-simd-intrinsics.Suggest, value: 1} \
 // RUN:  ]}' -- -target x86_64 -std=c++11
 
 typedef long long __m128i __attribute__((vector_size(16)));
@@ -17,7 +17,7 @@
   __m256 d0;
 
   _mm_add_epi32(i0, i1);
-// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: '_mm_add_epi32' can be replaced by operator+ on std::experimental::simd objects [readability-simd-intrinsics]
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: '_mm_add_epi32' can be replaced by operator+ on std::experimental::simd objects [portability-simd-intrinsics]
   d0 = _mm256_load_pd(0);
   _mm256_store_pd(0, d0);
 
diff --git a/test/clang-tidy/readability-simd-intrinsics-ppc.cpp b/test/clang-tidy/readability-simd-intrinsics-ppc.cpp
deleted file mode 100644
index 387384b..0000000
--- a/test/clang-tidy/readability-simd-intrinsics-ppc.cpp
+++ /dev/null
@@ -1,13 +0,0 @@
-// RUN: %check_clang_tidy %s readability-simd-intrinsics %t -- \
-// RUN:  -config='{CheckOptions: [ \
-// RUN:    {key: readability-simd-intrinsics.Suggest, value: 1} \
-// RUN:  ]}' -- -target ppc64le -maltivec -std=c++11
-
-vector int vec_add(vector int, vector int);
-
-void PPC() {
-  vector int i0, i1;
-
-  vec_add(i0, i1);
-// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: 'vec_add' can be replaced by operator+ on std::experimental::simd objects [readability-simd-intrinsics]
-}
diff --git a/test/clang-tidy/run-clang-tidy.cpp b/test/clang-tidy/run-clang-tidy.cpp
new file mode 100644
index 0000000..28e6d75
--- /dev/null
+++ b/test/clang-tidy/run-clang-tidy.cpp
@@ -0,0 +1,14 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "[{\"directory\":\".\",\"command\":\"clang++ -c %/t/test.cpp\",\"file\":\"%/t/test.cpp\"}]" | sed -e 's/\\/\\\\/g' > %t/compile_commands.json
+// RUN: echo "Checks: '-*,modernize-use-auto'" > %t/.clang-tidy
+// RUN: echo "WarningsAsErrors: '*'" >> %t/.clang-tidy
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: cd "%t"
+// RUN: not %run_clang_tidy "%t/test.cpp"
+
+int main()
+{
+  int* x = new int();
+  delete x;
+}
diff --git a/test/clang-tidy/select-checks.cpp b/test/clang-tidy/select-checks.cpp
index 12d05b4..791def7 100644
--- a/test/clang-tidy/select-checks.cpp
+++ b/test/clang-tidy/select-checks.cpp
@@ -1,5 +1,5 @@
 // RUN: clang-tidy %s -checks='-*,llvm-namespace-*' -- 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' %s
-// RUN: clang-tidy %s -checks='-*,an-unknown-check' -- 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK2 %s
+// RUN: not clang-tidy %s -checks='-*,an-unknown-check' -- 2>&1 | FileCheck -implicit-check-not='{{warning:|error:}}' -check-prefix=CHECK2 %s
 
 // CHECK2: Error: no checks enabled.
 
diff --git a/test/clang-tidy/zircon-temporary-objects.cpp b/test/clang-tidy/zircon-temporary-objects.cpp
new file mode 100644
index 0000000..b29b482
--- /dev/null
+++ b/test/clang-tidy/zircon-temporary-objects.cpp
@@ -0,0 +1,109 @@
+// RUN: %check_clang_tidy %s zircon-temporary-objects %t -- \
+// RUN:   -config="{CheckOptions: [{key: zircon-temporary-objects.Names, value: 'Foo;NS::Bar'}]}" \
+// RUN:   -header-filter=.* \
+// RUN: -- -std=c++11
+
+// Should flag instances of Foo, NS::Bar.
+
+class Foo {
+public:
+  Foo() = default;
+  Foo(int Val) : Val(Val){};
+
+private:
+  int Val;
+};
+
+namespace NS {
+
+class Bar {
+public:
+  Bar() = default;
+  Bar(int Val) : Val(Val){};
+
+private:
+  int Val;
+};
+
+} // namespace NS
+
+class Bar {
+public:
+  Bar() = default;
+  Bar(int Val) : Val(Val){};
+
+private:
+  int Val;
+};
+
+int func(Foo F) { return 1; };
+
+int main() {
+  Foo F;
+  Foo *F2 = new Foo();
+  new Foo();
+  Foo();
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'Foo' is prohibited
+  Foo F3 = Foo();
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: creating a temporary object of type 'Foo' is prohibited
+
+  Bar();
+  NS::Bar();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'NS::Bar' is prohibited
+
+  int A = func(Foo());
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: creating a temporary object of type 'Foo' is prohibited
+
+  Foo F4(0);
+  Foo *F5 = new Foo(0);
+  new Foo(0);
+  Foo(0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'Foo' is prohibited
+  Foo F6 = Foo(0);
+  // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: creating a temporary object of type 'Foo' is prohibited
+
+  Bar(0);
+  NS::Bar(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'NS::Bar' is prohibited
+
+  int B = func(Foo(0));
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: creating a temporary object of type 'Foo' is prohibited
+}
+
+namespace NS {
+
+void f() {
+  Bar();
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'NS::Bar' is prohibited
+  Bar(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: creating a temporary object of type 'NS::Bar' is prohibited
+}
+
+} // namespace NS
+
+template <typename Ty>
+Ty make_ty() { return Ty(); }
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: creating a temporary object of type 'Foo' is prohibited
+// CHECK-MESSAGES: :[[@LINE-2]]:23: warning: creating a temporary object of type 'NS::Bar' is prohibited
+
+void ty_func() {
+  make_ty<Bar>();
+  make_ty<NS::Bar>();
+  make_ty<Foo>();
+}
+
+// Inheriting the disallowed class does not trigger the check.
+
+class Bingo : NS::Bar {}; // Not explicitly disallowed
+
+void f2() {
+  Bingo();
+}
+
+template <typename Ty>
+class Quux : Ty {};
+
+void f3() {
+  Quux<NS::Bar>();
+  Quux<Bar>();
+}
diff --git a/test/clangd/diagnostics.test b/test/clangd/diagnostics.test
index 7c8150e..afd1277 100644
--- a/test/clangd/diagnostics.test
+++ b/test/clangd/diagnostics.test
@@ -18,20 +18,6 @@
 # CHECK-NEXT:          }
 # CHECK-NEXT:        },
 # CHECK-NEXT:        "severity": 2
-# CHECK-NEXT:      },
-# CHECK-NEXT:      {
-# CHECK-NEXT:        "message": "change return type to 'int'",
-# CHECK-NEXT:        "range": {
-# CHECK-NEXT:          "end": {
-# CHECK-NEXT:            "character": 4,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          },
-# CHECK-NEXT:          "start": {
-# CHECK-NEXT:            "character": 0,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          }
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "severity": 3
 # CHECK-NEXT:      }
 # CHECK-NEXT:    ],
 # CHECK-NEXT:    "uri": "file://{{.*}}/foo.c"
diff --git a/test/clangd/execute-command.test b/test/clangd/execute-command.test
index ffd8971..9686d04 100644
--- a/test/clangd/execute-command.test
+++ b/test/clangd/execute-command.test
@@ -18,34 +18,6 @@
 # CHECK-NEXT:          }
 # CHECK-NEXT:        },
 # CHECK-NEXT:        "severity": 2
-# CHECK-NEXT:      },
-# CHECK-NEXT:      {
-# CHECK-NEXT:        "message": "place parentheses around the assignment to silence this warning",
-# CHECK-NEXT:        "range": {
-# CHECK-NEXT:          "end": {
-# CHECK-NEXT:            "character": 35,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          },
-# CHECK-NEXT:          "start": {
-# CHECK-NEXT:            "character": 34,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          }
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "severity": 3
-# CHECK-NEXT:      },
-# CHECK-NEXT:      {
-# CHECK-NEXT:        "message": "use '==' to turn this assignment into an equality comparison",
-# CHECK-NEXT:        "range": {
-# CHECK-NEXT:          "end": {
-# CHECK-NEXT:            "character": 35,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          },
-# CHECK-NEXT:          "start": {
-# CHECK-NEXT:            "character": 34,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          }
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "severity": 3
 # CHECK-NEXT:      }
 # CHECK-NEXT:    ],
 # CHECK-NEXT:    "uri": "file://{{.*}}/foo.c"
diff --git a/test/clangd/extra-flags.test b/test/clangd/extra-flags.test
index 13d1d9e..23b2c65 100644
--- a/test/clangd/extra-flags.test
+++ b/test/clangd/extra-flags.test
@@ -18,20 +18,6 @@
 # CHECK-NEXT:          }
 # CHECK-NEXT:        },
 # CHECK-NEXT:        "severity": 2
-# CHECK-NEXT:      },
-# CHECK-NEXT:      {
-# CHECK-NEXT:        "message": "initialize the variable 'i' to silence this warning",
-# CHECK-NEXT:        "range": {
-# CHECK-NEXT:          "end": {
-# CHECK-NEXT:            "character": 19,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          },
-# CHECK-NEXT:          "start": {
-# CHECK-NEXT:            "character": 18,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          }
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "severity": 3
 # CHECK-NEXT:      }
 # CHECK-NEXT:    ],
 # CHECK-NEXT:    "uri": "file://{{.*}}/foo.c"
@@ -54,20 +40,6 @@
 # CHECK-NEXT:          }
 # CHECK-NEXT:        },
 # CHECK-NEXT:        "severity": 2
-# CHECK-NEXT:      },
-# CHECK-NEXT:      {
-# CHECK-NEXT:        "message": "initialize the variable 'i' to silence this warning",
-# CHECK-NEXT:        "range": {
-# CHECK-NEXT:          "end": {
-# CHECK-NEXT:            "character": 19,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          },
-# CHECK-NEXT:          "start": {
-# CHECK-NEXT:            "character": 18,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          }
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "severity": 3
 # CHECK-NEXT:      }
 # CHECK-NEXT:    ],
 # CHECK-NEXT:    "uri": "file://{{.*}}/foo.c"
diff --git a/test/clangd/fixits.test b/test/clangd/fixits.test
index 6087bc8..f8eb20c 100644
--- a/test/clangd/fixits.test
+++ b/test/clangd/fixits.test
@@ -18,40 +18,12 @@
 # CHECK-NEXT:          }
 # CHECK-NEXT:        },
 # CHECK-NEXT:        "severity": 2
-# CHECK-NEXT:      },
-# CHECK-NEXT:      {
-# CHECK-NEXT:        "message": "place parentheses around the assignment to silence this warning",
-# CHECK-NEXT:        "range": {
-# CHECK-NEXT:          "end": {
-# CHECK-NEXT:            "character": 35,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          },
-# CHECK-NEXT:          "start": {
-# CHECK-NEXT:            "character": 34,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          }
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "severity": 3
-# CHECK-NEXT:      },
-# CHECK-NEXT:      {
-# CHECK-NEXT:        "message": "use '==' to turn this assignment into an equality comparison",
-# CHECK-NEXT:        "range": {
-# CHECK-NEXT:          "end": {
-# CHECK-NEXT:            "character": 35,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          },
-# CHECK-NEXT:          "start": {
-# CHECK-NEXT:            "character": 34,
-# CHECK-NEXT:            "line": 0
-# CHECK-NEXT:          }
-# CHECK-NEXT:        },
-# CHECK-NEXT:        "severity": 3
 # CHECK-NEXT:      }
 # CHECK-NEXT:    ],
 # CHECK-NEXT:    "uri": "file://{{.*}}/foo.c"
 # CHECK-NEXT:  }
 ---
-{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":104,"character":13},"end":{"line":0,"character":35}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 37}},"severity":2,"message":"using the result of an assignment as a condition without parentheses"},{"range":{"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}},"severity":3,"message":"place parentheses around the assignment to silence this warning"},{"range":{"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}},"severity":3,"message":"use '==' to turn this assignment into an equality comparison"}]}}}
+{"jsonrpc":"2.0","id":2,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":104,"character":13},"end":{"line":0,"character":35}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 37}},"severity":2,"message":"using the result of an assignment as a condition without parentheses"}]}}}
 #      CHECK:  "id": 2,
 # CHECK-NEXT:  "jsonrpc": "2.0",
 # CHECK-NEXT:  "result": [
@@ -91,7 +63,7 @@
 # CHECK-NEXT:        }
 # CHECK-NEXT:      ],
 # CHECK-NEXT:      "command": "clangd.applyFix",
-# CHECK-NEXT:      "title": "Apply FixIt place parentheses around the assignment to silence this warning"
+# CHECK-NEXT:      "title": "Apply fix: place parentheses around the assignment to silence this warning"
 # CHECK-NEXT:    },
 # CHECK-NEXT:    {
 # CHECK-NEXT:      "arguments": [
@@ -116,11 +88,11 @@
 # CHECK-NEXT:        }
 # CHECK-NEXT:      ],
 # CHECK-NEXT:      "command": "clangd.applyFix",
-# CHECK-NEXT:      "title": "Apply FixIt use '==' to turn this assignment into an equality comparison"
+# CHECK-NEXT:      "title": "Apply fix: use '==' to turn this assignment into an equality comparison"
 # CHECK-NEXT:    }
 # CHECK-NEXT:  ]
 ---
-{"jsonrpc":"2.0","id":3,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":104,"character":13},"end":{"line":0,"character":35}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 37}},"severity":2,"code":"1","source":"foo","message":"using the result of an assignment as a condition without parentheses"},{"range":{"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}},"severity":3,"message":"place parentheses around the assignment to silence this warning"},{"range":{"start": {"line": 0, "character": 34}, "end": {"line": 0, "character": 35}},"severity":3,"message":"use '==' to turn this assignment into an equality comparison"}]}}}
+{"jsonrpc":"2.0","id":3,"method":"textDocument/codeAction","params":{"textDocument":{"uri":"test:///foo.c"},"range":{"start":{"line":104,"character":13},"end":{"line":0,"character":35}},"context":{"diagnostics":[{"range":{"start": {"line": 0, "character": 32}, "end": {"line": 0, "character": 37}},"severity":2,"message":"using the result of an assignment as a condition without parentheses"}]}}}
 # Make sure unused "code" and "source" fields ignored gracefully
 #      CHECK:  "id": 3,
 # CHECK-NEXT:  "jsonrpc": "2.0",
@@ -161,7 +133,7 @@
 # CHECK-NEXT:        }
 # CHECK-NEXT:      ],
 # CHECK-NEXT:      "command": "clangd.applyFix",
-# CHECK-NEXT:      "title": "Apply FixIt place parentheses around the assignment to silence this warning"
+# CHECK-NEXT:      "title": "Apply fix: place parentheses around the assignment to silence this warning"
 # CHECK-NEXT:    },
 # CHECK-NEXT:    {
 # CHECK-NEXT:      "arguments": [
@@ -186,7 +158,7 @@
 # CHECK-NEXT:        }
 # CHECK-NEXT:      ],
 # CHECK-NEXT:      "command": "clangd.applyFix",
-# CHECK-NEXT:      "title": "Apply FixIt use '==' to turn this assignment into an equality comparison"
+# CHECK-NEXT:      "title": "Apply fix: use '==' to turn this assignment into an equality comparison"
 # CHECK-NEXT:    }
 # CHECK-NEXT:  ]
 ---
diff --git a/test/clangd/initialize-params-invalid.test b/test/clangd/initialize-params-invalid.test
index da921cb..d98e110 100644
--- a/test/clangd/initialize-params-invalid.test
+++ b/test/clangd/initialize-params-invalid.test
@@ -36,7 +36,7 @@
 # CHECK-NEXT:          ","
 # CHECK-NEXT:        ]
 # CHECK-NEXT:      },
-# CHECK-NEXT:      "textDocumentSync": 1
+# CHECK-NEXT:      "textDocumentSync": 2
 # CHECK-NEXT:    }
 # CHECK-NEXT:  }
 ---
diff --git a/test/clangd/initialize-params.test b/test/clangd/initialize-params.test
index a4de1ee..d3bf136 100644
--- a/test/clangd/initialize-params.test
+++ b/test/clangd/initialize-params.test
@@ -36,7 +36,7 @@
 # CHECK-NEXT:          ","
 # CHECK-NEXT:        ]
 # CHECK-NEXT:      },
-# CHECK-NEXT:      "textDocumentSync": 1
+# CHECK-NEXT:      "textDocumentSync": 2
 # CHECK-NEXT:    }
 # CHECK-NEXT:  }
 ---
diff --git a/test/clangd/textdocument-didchange-fail.test b/test/clangd/textdocument-didchange-fail.test
new file mode 100644
index 0000000..3bd01e9
--- /dev/null
+++ b/test/clangd/textdocument-didchange-fail.test
@@ -0,0 +1,37 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+# RUN: clangd -lit-test -pch-storage=memory < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"int main() {}\n"}}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":6}}}
+#      CHECK:  "id": 1,
+# CHECK-NEXT:  "jsonrpc": "2.0",
+# CHECK-NEXT:  "result": [
+# CHECK-NEXT:    {
+# CHECK-NEXT:      "range": {
+# CHECK-NEXT:        "end": {
+# CHECK-NEXT:          "character": 8,
+# CHECK-NEXT:          "line": 0
+# CHECK-NEXT:        },
+# CHECK-NEXT:        "start": {
+# CHECK-NEXT:          "character": 4,
+# CHECK-NEXT:          "line": 0
+# CHECK-NEXT:        }
+# CHECK-NEXT:      },
+# CHECK-NEXT:      "uri": "file://{{.*}}/clangd-test/main.cpp"
+# CHECK-NEXT:    }
+# CHECK-NEXT:  ]
+---
+{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///main.cpp"},"contentChanges":[{"range":{"start":{"line":100,"character":0},"end":{"line":100,"character":0}},"text": "foo"}]}}
+---
+{"jsonrpc":"2.0","id":1,"method":"textDocument/definition","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":6}}}
+#      CHECK:  "error": {
+# CHECK-NEXT:    "code": -32602,
+# CHECK-NEXT:    "message": "trying to get AST for non-added document"
+# CHECK-NEXT:  },
+# CHECK-NEXT:  "id": 1,
+# CHECK-NEXT:  "jsonrpc": "2.0"
+# CHECK-NEXT:}
+---
+{"jsonrpc":"2.0","id":4,"method":"shutdown"}
diff --git a/test/clangd/xrefs.test b/test/clangd/xrefs.test
index 6e0e21f..f2e17c4 100644
--- a/test/clangd/xrefs.test
+++ b/test/clangd/xrefs.test
@@ -10,11 +10,11 @@
 # CHECK-NEXT:    {
 # CHECK-NEXT:      "range": {
 # CHECK-NEXT:        "end": {
-# CHECK-NEXT:          "character": 9,
+# CHECK-NEXT:          "character": 5,
 # CHECK-NEXT:          "line": 0
 # CHECK-NEXT:        },
 # CHECK-NEXT:        "start": {
-# CHECK-NEXT:          "character": 0,
+# CHECK-NEXT:          "character": 4,
 # CHECK-NEXT:          "line": 0
 # CHECK-NEXT:        }
 # CHECK-NEXT:      },
diff --git a/test/lit.cfg b/test/lit.cfg
index 3bffbdb..4b4718a 100644
--- a/test/lit.cfg
+++ b/test/lit.cfg
@@ -129,6 +129,11 @@
     config.substitutions.append(
         ('%clang_tidy_diff',
          '%s %s' % (config.python_executable, clang_tidy_diff)) )
+    run_clang_tidy = os.path.join(
+        config.test_source_root, "..", "clang-tidy", "tool", "run-clang-tidy.py")
+    config.substitutions.append(
+        ('%run_clang_tidy',
+         '%s %s' % (config.python_executable, run_clang_tidy)) )
 else:
     # exclude the clang-tidy test directory
     config.excludes.append('clang-tidy')
diff --git a/test/lit.site.cfg.in b/test/lit.site.cfg.in
index 86e9617..948e469 100644
--- a/test/lit.site.cfg.in
+++ b/test/lit.site.cfg.in
@@ -23,5 +23,7 @@
     key, = e.args
     lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key,key))
 
+@LIT_SITE_CFG_IN_FOOTER@
+
 # Let the main config do the real work.
 lit_config.load_config(config, "@CLANG_TOOLS_SOURCE_DIR@/test/lit.cfg")
diff --git a/test/modularize/NoProblemsNamespace.modularize b/test/modularize/NoProblemsNamespace.modularize
index 1c3f78d..93a4fea 100644
--- a/test/modularize/NoProblemsNamespace.modularize
+++ b/test/modularize/NoProblemsNamespace.modularize
@@ -1,3 +1,3 @@
-# RUN: modularize -block-check-header-list-only
+# RUN: modularize -block-check-header-list-only %s
 
 Inputs/IncludeInNamespace.h
diff --git a/unittests/change-namespace/ChangeNamespaceTests.cpp b/unittests/change-namespace/ChangeNamespaceTests.cpp
index 440a3fe..917f7b0 100644
--- a/unittests/change-namespace/ChangeNamespaceTests.cpp
+++ b/unittests/change-namespace/ChangeNamespaceTests.cpp
@@ -850,22 +850,58 @@
 TEST_F(ChangeNamespaceTest, UsingShadowDeclInGlobal) {
   std::string Code = "namespace glob {\n"
                      "class Glob {};\n"
+                     "void GFunc() {}\n"
                      "}\n"
                      "using glob::Glob;\n"
+                     "using glob::GFunc;\n"
                      "namespace na {\n"
                      "namespace nb {\n"
-                     "void f() { Glob g; }\n"
+                     "void f() { Glob g; GFunc(); }\n"
                      "} // namespace nb\n"
                      "} // namespace na\n";
 
   std::string Expected = "namespace glob {\n"
                          "class Glob {};\n"
+                         "void GFunc() {}\n"
                          "}\n"
                          "using glob::Glob;\n"
+                         "using glob::GFunc;\n"
                          "\n"
                          "namespace x {\n"
                          "namespace y {\n"
-                         "void f() { Glob g; }\n"
+                         "void f() { Glob g; GFunc(); }\n"
+                         "} // namespace y\n"
+                         "} // namespace x\n";
+  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
+}
+
+TEST_F(ChangeNamespaceTest, UsingShadowDeclsInAnonymousNamespaces) {
+  std::string Code = "namespace util {\n"
+                     "class Util {};\n"
+                     "void func() {}\n"
+                     "}\n"
+                     "namespace na {\n"
+                     "namespace nb {\n"
+                     "namespace {\n"
+                     "using ::util::Util;\n"
+                     "using ::util::func;\n"
+                     "void f() { Util u; func(); }\n"
+                     "}\n"
+                     "} // namespace nb\n"
+                     "} // namespace na\n";
+
+  std::string Expected = "namespace util {\n"
+                         "class Util {};\n"
+                         "void func() {}\n"
+                         "} // namespace util\n"
+                         "\n"
+                         "namespace x {\n"
+                         "namespace y {\n"
+                         "namespace {\n"
+                         "using ::util::Util;\n"
+                         "using ::util::func;\n"
+                         "void f() { Util u; func(); }\n"
+                         "}\n"
                          "} // namespace y\n"
                          "} // namespace x\n";
   EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
diff --git a/unittests/clangd/Annotations.cpp b/unittests/clangd/Annotations.cpp
index 92d1cb1..fc9c4cb 100644
--- a/unittests/clangd/Annotations.cpp
+++ b/unittests/clangd/Annotations.cpp
@@ -86,7 +86,11 @@
 std::pair<std::size_t, std::size_t>
 Annotations::offsetRange(llvm::StringRef Name) const {
   auto R = range(Name);
-  return {positionToOffset(Code, R.start), positionToOffset(Code, R.end)};
+  llvm::Expected<size_t> Start = positionToOffset(Code, R.start);
+  llvm::Expected<size_t> End = positionToOffset(Code, R.end);
+  assert(Start);
+  assert(End);
+  return {*Start, *End};
 }
 
 } // namespace clangd
diff --git a/unittests/clangd/CMakeLists.txt b/unittests/clangd/CMakeLists.txt
index 6017868..af2e114 100644
--- a/unittests/clangd/CMakeLists.txt
+++ b/unittests/clangd/CMakeLists.txt
@@ -15,6 +15,7 @@
   CodeCompleteTests.cpp
   CodeCompletionStringsTests.cpp
   ContextTests.cpp
+  DraftStoreTests.cpp
   FileIndexTests.cpp
   FuzzyMatchTests.cpp
   HeadersTests.cpp
@@ -43,4 +44,5 @@
   clangTooling
   clangToolingCore
   LLVMSupport
+  LLVMTestingSupport
   )
diff --git a/unittests/clangd/ClangdTests.cpp b/unittests/clangd/ClangdTests.cpp
index 1102d2c..b0e56ba 100644
--- a/unittests/clangd/ClangdTests.cpp
+++ b/unittests/clangd/ClangdTests.cpp
@@ -42,12 +42,10 @@
 
 namespace {
 
-static bool diagsContainErrors(ArrayRef<DiagWithFixIts> Diagnostics) {
-  for (const auto &DiagAndFixIts : Diagnostics) {
-    // FIXME: severities returned by clangd should have a descriptive
-    // diagnostic severity enum
-    const int ErrorSeverity = 1;
-    if (DiagAndFixIts.Diag.severity == ErrorSeverity)
+bool diagsContainErrors(const std::vector<Diag> &Diagnostics) {
+  for (auto D : Diagnostics) {
+    if (D.Severity == DiagnosticsEngine::Error ||
+        D.Severity == DiagnosticsEngine::Fatal)
       return true;
   }
   return false;
@@ -55,14 +53,11 @@
 
 class ErrorCheckingDiagConsumer : public DiagnosticsConsumer {
 public:
-  void
-  onDiagnosticsReady(PathRef File,
-                     Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {
-    bool HadError = diagsContainErrors(Diagnostics.Value);
-
+  void onDiagnosticsReady(PathRef File,
+                          std::vector<Diag> Diagnostics) override {
+    bool HadError = diagsContainErrors(Diagnostics);
     std::lock_guard<std::mutex> Lock(Mutex);
     HadErrorInLastDiags = HadError;
-    LastVFSTag = Diagnostics.Tag;
   }
 
   bool hadErrorInLastDiags() {
@@ -70,22 +65,18 @@
     return HadErrorInLastDiags;
   }
 
-  VFSTag lastVFSTag() { return LastVFSTag; }
-
 private:
   std::mutex Mutex;
   bool HadErrorInLastDiags = false;
-  VFSTag LastVFSTag = VFSTag();
 };
 
 /// For each file, record whether the last published diagnostics contained at
 /// least one error.
 class MultipleErrorCheckingDiagConsumer : public DiagnosticsConsumer {
 public:
-  void
-  onDiagnosticsReady(PathRef File,
-                     Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {
-    bool HadError = diagsContainErrors(Diagnostics.Value);
+  void onDiagnosticsReady(PathRef File,
+                          std::vector<Diag> Diagnostics) override {
+    bool HadError = diagsContainErrors(Diagnostics);
 
     std::lock_guard<std::mutex> Lock(Mutex);
     LastDiagsHadError[File] = HadError;
@@ -153,7 +144,6 @@
       FS.Files[testPath(FileWithContents.first)] = FileWithContents.second;
 
     auto SourceFilename = testPath(SourceFileRelPath);
-    FS.ExpectedFile = SourceFilename;
     Server.addDocument(SourceFilename, SourceContents);
     auto Result = dumpASTWithoutMemoryLocs(Server, SourceFilename);
     EXPECT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
@@ -212,7 +202,6 @@
 
   FS.Files[testPath("foo.h")] = "int a;";
   FS.Files[FooCpp] = SourceContents;
-  FS.ExpectedFile = FooCpp;
 
   Server.addDocument(FooCpp, SourceContents);
   auto DumpParse1 = dumpASTWithoutMemoryLocs(Server, FooCpp);
@@ -249,7 +238,6 @@
 
   FS.Files[FooH] = "int a;";
   FS.Files[FooCpp] = SourceContents;
-  FS.ExpectedFile = FooCpp;
 
   Server.addDocument(FooCpp, SourceContents);
   auto DumpParse1 = dumpASTWithoutMemoryLocs(Server, FooCpp);
@@ -257,13 +245,13 @@
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
 
   FS.Files[FooH] = "";
-  Server.forceReparse(FooCpp);
+  Server.addDocument(FooCpp, SourceContents);
   auto DumpParseDifferent = dumpASTWithoutMemoryLocs(Server, FooCpp);
   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
 
   FS.Files[FooH] = "int a;";
-  Server.forceReparse(FooCpp);
+  Server.addDocument(FooCpp, SourceContents);
   auto DumpParse2 = dumpASTWithoutMemoryLocs(Server, FooCpp);
   ASSERT_TRUE(Server.blockUntilIdleForTest()) << "Waiting for diagnostics";
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
@@ -272,29 +260,33 @@
   EXPECT_NE(DumpParse1, DumpParseDifferent);
 }
 
-TEST_F(ClangdVFSTest, CheckVersions) {
-  MockFSProvider FS;
-  ErrorCheckingDiagConsumer DiagConsumer;
+TEST_F(ClangdVFSTest, PropagatesContexts) {
+  static Key<int> Secret;
+  struct FSProvider : public FileSystemProvider {
+    IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() override {
+      Got = Context::current().getExisting(Secret);
+      return buildTestFS({});
+    }
+    int Got;
+  } FS;
+  struct DiagConsumer : public DiagnosticsConsumer {
+    void onDiagnosticsReady(PathRef File,
+                            std::vector<Diag> Diagnostics) override {
+      Got = Context::current().getExisting(Secret);
+    }
+    int Got;
+  } DiagConsumer;
   MockCompilationDatabase CDB;
+
+  // Verify that the context is plumbed to the FS provider and diagnostics.
   ClangdServer Server(CDB, FS, DiagConsumer, ClangdServer::optsForTest());
-
-  auto FooCpp = testPath("foo.cpp");
-  const auto SourceContents = "int a;";
-  FS.Files[FooCpp] = SourceContents;
-  FS.ExpectedFile = FooCpp;
-
-  // Use default completion options.
-  clangd::CodeCompleteOptions CCOpts;
-
-  FS.Tag = "123";
-  runAddDocument(Server, FooCpp, SourceContents);
-  EXPECT_EQ(runCodeComplete(Server, FooCpp, Position(), CCOpts).Tag, FS.Tag);
-  EXPECT_EQ(DiagConsumer.lastVFSTag(), FS.Tag);
-
-  FS.Tag = "321";
-  runAddDocument(Server, FooCpp, SourceContents);
-  EXPECT_EQ(DiagConsumer.lastVFSTag(), FS.Tag);
-  EXPECT_EQ(runCodeComplete(Server, FooCpp, Position(), CCOpts).Tag, FS.Tag);
+  {
+    WithContextValue Entrypoint(Secret, 42);
+    Server.addDocument(testPath("foo.cpp"), "void main(){}");
+  }
+  ASSERT_TRUE(Server.blockUntilIdleForTest());
+  EXPECT_EQ(FS.Got, 42);
+  EXPECT_EQ(DiagConsumer.Got, 42);
 }
 
 // Only enable this test on Unix
@@ -366,7 +358,6 @@
 )cpp";
 
   FS.Files[FooCpp] = "";
-  FS.ExpectedFile = FooCpp;
 
   // First parse files in C mode and check they produce errors.
   CDB.ExtraClangFlags = {"-xc"};
@@ -377,15 +368,16 @@
 
   // Now switch to C++ mode.
   CDB.ExtraClangFlags = {"-xc++"};
-  // Currently, addDocument never checks if CompileCommand has changed, so we
+  // By default addDocument does not check if CompileCommand has changed, so we
   // expect to see the errors.
   runAddDocument(Server, FooCpp, SourceContents1);
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
   runAddDocument(Server, FooCpp, SourceContents2);
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
-  // But forceReparse should reparse the file with proper flags.
-  Server.forceReparse(FooCpp);
-  ASSERT_TRUE(Server.blockUntilIdleForTest());
+  // Passing SkipCache=true will force addDocument to reparse the file with
+  // proper flags.
+  runAddDocument(Server, FooCpp, SourceContents2, WantDiagnostics::Auto,
+                 /*SkipCache=*/true);
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
   // Subsequent addDocument calls should finish without errors too.
   runAddDocument(Server, FooCpp, SourceContents1);
@@ -409,7 +401,6 @@
 int main() { return 0; }
 )cpp";
   FS.Files[FooCpp] = "";
-  FS.ExpectedFile = FooCpp;
 
   // Parse with define, we expect to see the errors.
   CDB.ExtraClangFlags = {"-DWITH_ERROR"};
@@ -418,12 +409,14 @@
 
   // Parse without the define, no errors should be produced.
   CDB.ExtraClangFlags = {};
-  // Currently, addDocument never checks if CompileCommand has changed, so we
+  // By default addDocument does not check if CompileCommand has changed, so we
   // expect to see the errors.
   runAddDocument(Server, FooCpp, SourceContents);
   EXPECT_TRUE(DiagConsumer.hadErrorInLastDiags());
-  // But forceReparse should reparse the file with proper flags.
-  Server.forceReparse(FooCpp);
+  // Passing SkipCache=true will force addDocument to reparse the file with
+  // proper flags.
+  runAddDocument(Server, FooCpp, SourceContents, WantDiagnostics::Auto,
+                 /*SkipCache=*/true);
   ASSERT_TRUE(Server.blockUntilIdleForTest());
   EXPECT_FALSE(DiagConsumer.hadErrorInLastDiags());
   // Subsequent addDocument call should finish without errors too.
@@ -435,9 +428,9 @@
 TEST_F(ClangdVFSTest, ReparseOpenedFiles) {
   Annotations FooSource(R"cpp(
 #ifdef MACRO
-$one[[static void bob() {}]]
+static void $one[[bob]]() {}
 #else
-$two[[static void bob() {}]]
+static void $two[[bob]]() {}
 #endif
 
 int main () { bo^b (); return 0; }
@@ -478,14 +471,17 @@
 
   auto Locations = runFindDefinitions(Server, FooCpp, FooSource.point());
   EXPECT_TRUE(bool(Locations));
-  EXPECT_THAT(Locations->Value, ElementsAre(Location{URIForFile{FooCpp},
-                                                     FooSource.range("one")}));
+  EXPECT_THAT(*Locations, ElementsAre(Location{URIForFile{FooCpp},
+                                               FooSource.range("one")}));
 
   // Undefine MACRO, close baz.cpp.
   CDB.ExtraClangFlags.clear();
   DiagConsumer.clear();
   Server.removeDocument(BazCpp);
-  Server.reparseOpenedFiles();
+  Server.addDocument(FooCpp, FooSource.code(), WantDiagnostics::Auto,
+                     /*SkipCache=*/true);
+  Server.addDocument(BarCpp, BarSource.code(), WantDiagnostics::Auto,
+                     /*SkipCache=*/true);
   ASSERT_TRUE(Server.blockUntilIdleForTest());
 
   EXPECT_THAT(DiagConsumer.filesWithDiags(),
@@ -493,8 +489,8 @@
 
   Locations = runFindDefinitions(Server, FooCpp, FooSource.point());
   EXPECT_TRUE(bool(Locations));
-  EXPECT_THAT(Locations->Value, ElementsAre(Location{URIForFile{FooCpp},
-                                                     FooSource.range("two")}));
+  EXPECT_THAT(*Locations, ElementsAre(Location{URIForFile{FooCpp},
+                                               FooSource.range("two")}));
 }
 
 TEST_F(ClangdVFSTest, MemoryUsage) {
@@ -554,13 +550,13 @@
   EXPECT_ERROR(runRename(Server, FooCpp, Position(), "new_name"));
   // FIXME: codeComplete and signatureHelp should also return errors when they
   // can't parse the file.
-  EXPECT_THAT(
-      runCodeComplete(Server, FooCpp, Position(), clangd::CodeCompleteOptions())
-          .Value.items,
-      IsEmpty());
+  EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, Position(),
+                                       clangd::CodeCompleteOptions()))
+                  .items,
+              IsEmpty());
   auto SigHelp = runSignatureHelp(Server, FooCpp, Position());
   ASSERT_TRUE(bool(SigHelp)) << "signatureHelp returned an error";
-  EXPECT_THAT(SigHelp->Value.signatures, IsEmpty());
+  EXPECT_THAT(SigHelp->signatures, IsEmpty());
 }
 
 class ClangdThreadingTest : public ClangdVFSTest {};
@@ -612,15 +608,14 @@
   public:
     TestDiagConsumer() : Stats(FilesCount, FileStat()) {}
 
-    void onDiagnosticsReady(
-        PathRef File,
-        Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {
+    void onDiagnosticsReady(PathRef File,
+                            std::vector<Diag> Diagnostics) override {
       StringRef FileIndexStr = llvm::sys::path::stem(File);
       ASSERT_TRUE(FileIndexStr.consume_front("Foo"));
 
       unsigned long FileIndex = std::stoul(FileIndexStr.str());
 
-      bool HadError = diagsContainErrors(Diagnostics.Value);
+      bool HadError = diagsContainErrors(Diagnostics);
 
       std::lock_guard<std::mutex> Lock(Mutex);
       if (HadError)
@@ -686,44 +681,31 @@
       Stats.FileIsRemoved = true;
     };
 
-    auto UpdateStatsOnForceReparse = [&](unsigned FileIndex) {
-      auto &Stats = ReqStats[FileIndex];
-
-      if (Stats.LastContentsHadErrors)
-        ++Stats.RequestsWithErrors;
-      else
-        ++Stats.RequestsWithoutErrors;
-    };
-
-    auto AddDocument = [&](unsigned FileIndex) {
+    auto AddDocument = [&](unsigned FileIndex, bool SkipCache) {
       bool ShouldHaveErrors = ShouldHaveErrorsDist(RandGen);
       Server.addDocument(FilePaths[FileIndex],
                          ShouldHaveErrors ? SourceContentsWithErrors
-                                          : SourceContentsWithoutErrors);
+                                          : SourceContentsWithoutErrors,
+                         WantDiagnostics::Auto, SkipCache);
       UpdateStatsOnAddDocument(FileIndex, ShouldHaveErrors);
     };
 
     // Various requests that we would randomly run.
     auto AddDocumentRequest = [&]() {
       unsigned FileIndex = FileIndexDist(RandGen);
-      AddDocument(FileIndex);
+      AddDocument(FileIndex, /*SkipCache=*/false);
     };
 
     auto ForceReparseRequest = [&]() {
       unsigned FileIndex = FileIndexDist(RandGen);
-      // Make sure we don't violate the ClangdServer's contract.
-      if (ReqStats[FileIndex].FileIsRemoved)
-        AddDocument(FileIndex);
-
-      Server.forceReparse(FilePaths[FileIndex]);
-      UpdateStatsOnForceReparse(FileIndex);
+      AddDocument(FileIndex, /*SkipCache=*/true);
     };
 
     auto RemoveDocumentRequest = [&]() {
       unsigned FileIndex = FileIndexDist(RandGen);
       // Make sure we don't violate the ClangdServer's contract.
       if (ReqStats[FileIndex].FileIsRemoved)
-        AddDocument(FileIndex);
+        AddDocument(FileIndex, /*SkipCache=*/false);
 
       Server.removeDocument(FilePaths[FileIndex]);
       UpdateStatsOnRemoveDocument(FileIndex);
@@ -733,7 +715,7 @@
       unsigned FileIndex = FileIndexDist(RandGen);
       // Make sure we don't violate the ClangdServer's contract.
       if (ReqStats[FileIndex].FileIsRemoved)
-        AddDocument(FileIndex);
+        AddDocument(FileIndex, /*SkipCache=*/false);
 
       Position Pos;
       Pos.line = LineDist(RandGen);
@@ -744,15 +726,15 @@
       // requests as opposed to AddDocument/RemoveDocument, which are implicitly
       // cancelled by any subsequent AddDocument/RemoveDocument request to the
       // same file.
-      runCodeComplete(Server, FilePaths[FileIndex], Pos,
-                      clangd::CodeCompleteOptions());
+      cantFail(runCodeComplete(Server, FilePaths[FileIndex], Pos,
+                               clangd::CodeCompleteOptions()));
     };
 
     auto FindDefinitionsRequest = [&]() {
       unsigned FileIndex = FileIndexDist(RandGen);
       // Make sure we don't violate the ClangdServer's contract.
       if (ReqStats[FileIndex].FileIsRemoved)
-        AddDocument(FileIndex);
+        AddDocument(FileIndex, /*SkipCache=*/false);
 
       Position Pos;
       Pos.line = LineDist(RandGen);
@@ -881,8 +863,7 @@
     NoConcurrentAccessDiagConsumer(std::promise<void> StartSecondReparse)
         : StartSecondReparse(std::move(StartSecondReparse)) {}
 
-    void onDiagnosticsReady(PathRef,
-                            Tagged<std::vector<DiagWithFixIts>>) override {
+    void onDiagnosticsReady(PathRef, std::vector<Diag>) override {
       ++Count;
       std::unique_lock<std::mutex> Lock(Mutex, std::try_to_lock_t());
       ASSERT_TRUE(Lock.owns_lock())
@@ -945,8 +926,8 @@
 
   auto FooCpp = testPath("foo.cpp");
   const auto Code = R"cpp(
-#include "z.h"
 #include "x.h"
+#include "z.h"
 
 void f() {}
 )cpp";
@@ -967,7 +948,7 @@
         .contains((llvm::Twine("#include ") + Expected + "").str());
   };
 
-  EXPECT_TRUE(Inserted("\"y.h\"", /*Preferred=*/"","\"y.h\""));
+  EXPECT_TRUE(Inserted("\"y.h\"", /*Preferred=*/"", "\"y.h\""));
   EXPECT_TRUE(Inserted("\"y.h\"", /*Preferred=*/"\"Y.h\"", "\"Y.h\""));
   EXPECT_TRUE(Inserted("<string>", /*Preferred=*/"", "<string>"));
   EXPECT_TRUE(Inserted("<string>", /*Preferred=*/"", "<string>"));
@@ -1000,8 +981,8 @@
 
   auto Path = testPath("foo.cpp");
   std::string Code = R"cpp(
-#include "y.h"
 #include "x.h"
+#include "y.h"
 
 void f(  )  {}
 )cpp";
diff --git a/unittests/clangd/ClangdUnitTests.cpp b/unittests/clangd/ClangdUnitTests.cpp
index ee4acbe..0e11082 100644
--- a/unittests/clangd/ClangdUnitTests.cpp
+++ b/unittests/clangd/ClangdUnitTests.cpp
@@ -7,8 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "ClangdUnit.h"
 #include "Annotations.h"
+#include "ClangdUnit.h"
 #include "TestFS.h"
 #include "clang/Frontend/CompilerInvocation.h"
 #include "clang/Frontend/PCHContainerOperations.h"
@@ -20,26 +20,24 @@
 namespace clang {
 namespace clangd {
 using namespace llvm;
-void PrintTo(const DiagWithFixIts &D, std::ostream *O) {
-  llvm::raw_os_ostream OS(*O);
-  OS << D.Diag;
-  if (!D.FixIts.empty()) {
-    OS << " {";
-    const char *Sep = "";
-    for (const auto &F : D.FixIts) {
-      OS << Sep << F;
-      Sep = ", ";
-    }
-    OS << "}";
-  }
-}
 
 namespace {
 using testing::ElementsAre;
+using testing::Field;
+using testing::IsEmpty;
+using testing::Pair;
+
+testing::Matcher<const Diag &> WithFix(testing::Matcher<Fix> FixMatcher) {
+  return Field(&Diag::Fixes, ElementsAre(FixMatcher));
+}
+
+testing::Matcher<const Diag &> WithNote(testing::Matcher<Note> NoteMatcher) {
+  return Field(&Diag::Notes, ElementsAre(NoteMatcher));
+}
 
 // FIXME: this is duplicated with FileIndexTests. Share it.
-ParsedAST build(StringRef Code, std::vector<const char*> Flags = {}) {
-  std::vector<const char*> Cmd = {"clang", "main.cpp"};
+ParsedAST build(StringRef Code, std::vector<const char *> Flags = {}) {
+  std::vector<const char *> Cmd = {"clang", "main.cpp"};
   Cmd.insert(Cmd.begin() + 1, Flags.begin(), Flags.end());
   auto CI = createInvocationFromCommandLine(Cmd);
   auto Buf = MemoryBuffer::getMemBuffer(Code);
@@ -50,18 +48,56 @@
   return std::move(*AST);
 }
 
+std::vector<Diag> buildDiags(llvm::StringRef Code,
+                             std::vector<const char *> Flags = {}) {
+  return build(Code, std::move(Flags)).getDiagnostics();
+}
+
 MATCHER_P2(Diag, Range, Message,
-           "Diagnostic at " + llvm::to_string(Range) + " = [" + Message + "]") {
-  return arg.Diag.range == Range && arg.Diag.message == Message &&
-         arg.FixIts.empty();
+           "Diag at " + llvm::to_string(Range) + " = [" + Message + "]") {
+  return arg.Range == Range && arg.Message == Message;
 }
 
 MATCHER_P3(Fix, Range, Replacement, Message,
            "Fix " + llvm::to_string(Range) + " => " +
                testing::PrintToString(Replacement) + " = [" + Message + "]") {
-  return arg.Diag.range == Range && arg.Diag.message == Message &&
-         arg.FixIts.size() == 1 && arg.FixIts[0].range == Range &&
-         arg.FixIts[0].newText == Replacement;
+  return arg.Message == Message && arg.Edits.size() == 1 &&
+         arg.Edits[0].range == Range && arg.Edits[0].newText == Replacement;
+}
+
+MATCHER_P(EqualToLSPDiag, LSPDiag,
+          "LSP diagnostic " + llvm::to_string(LSPDiag)) {
+  return std::tie(arg.range, arg.severity, arg.message) ==
+         std::tie(LSPDiag.range, LSPDiag.severity, LSPDiag.message);
+}
+
+MATCHER_P(EqualToFix, Fix, "LSP fix " + llvm::to_string(Fix)) {
+  if (arg.Message != Fix.Message)
+    return false;
+  if (arg.Edits.size() != Fix.Edits.size())
+    return false;
+  for (std::size_t I = 0; I < arg.Edits.size(); ++I) {
+    if (arg.Edits[I].range != Fix.Edits[I].range ||
+        arg.Edits[I].newText != Fix.Edits[I].newText)
+      return false;
+  }
+  return true;
+}
+
+// Helper function to make tests shorter.
+Position pos(int line, int character) {
+  Position Res;
+  Res.line = line;
+  Res.character = character;
+  return Res;
+}
+
+/// Matches diagnostic that has exactly one fix with the same range and message
+/// as the diagnostic itself.
+testing::Matcher<const clangd::Diag &> DiagWithEqualFix(clangd::Range Range,
+                                                        std::string Replacement,
+                                                        std::string Message) {
+  return AllOf(Diag(Range, Message), WithFix(Fix(Range, Replacement, Message)));
 }
 
 TEST(DiagnosticsTest, DiagnosticRanges) {
@@ -75,35 +111,34 @@
       $unk[[unknown]]();
     }
   )cpp");
-      llvm::errs() << Test.code();
-      EXPECT_THAT(
-          build(Test.code()).getDiagnostics(),
-          ElementsAre(
-              // This range spans lines.
-              Fix(Test.range("typo"), "foo",
-                  "use of undeclared identifier 'goo'; did you mean 'foo'?"),
-              // This is a pretty normal range.
-              Diag(Test.range("decl"), "'foo' declared here"),
-              // This range is zero-width, and at the end of a line.
-              Fix(Test.range("semicolon"), ";",
-                  "expected ';' after expression"),
-              // This range isn't provided by clang, we expand to the token.
-              Diag(Test.range("unk"),
-                   "use of undeclared identifier 'unknown'")));
+  llvm::errs() << Test.code();
+  EXPECT_THAT(
+      buildDiags(Test.code()),
+      ElementsAre(
+          // This range spans lines.
+          AllOf(DiagWithEqualFix(
+                    Test.range("typo"), "foo",
+                    "use of undeclared identifier 'goo'; did you mean 'foo'?"),
+                // This is a pretty normal range.
+                WithNote(Diag(Test.range("decl"), "'foo' declared here"))),
+          // This range is zero-width, and at the end of a line.
+          DiagWithEqualFix(Test.range("semicolon"), ";",
+                           "expected ';' after expression"),
+          // This range isn't provided by clang, we expand to the token.
+          Diag(Test.range("unk"), "use of undeclared identifier 'unknown'")));
 }
 
 TEST(DiagnosticsTest, FlagsMatter) {
   Annotations Test("[[void]] main() {}");
-  EXPECT_THAT(
-      build(Test.code()).getDiagnostics(),
-      ElementsAre(Fix(Test.range(), "int", "'main' must return 'int'")));
+  EXPECT_THAT(buildDiags(Test.code()),
+              ElementsAre(DiagWithEqualFix(Test.range(), "int",
+                                           "'main' must return 'int'")));
   // Same code built as C gets different diagnostics.
   EXPECT_THAT(
-      build(Test.code(), {"-x", "c"}).getDiagnostics(),
-      ElementsAre(
-          // FIXME: ideally this would be one diagnostic with a named FixIt.
+      buildDiags(Test.code(), {"-x", "c"}),
+      ElementsAre(AllOf(
           Diag(Test.range(), "return type of 'main' is not 'int'"),
-          Fix(Test.range(), "int", "change return type to 'int'")));
+          WithFix(Fix(Test.range(), "int", "change return type to 'int'")))));
 }
 
 TEST(DiagnosticsTest, Preprocessor) {
@@ -121,10 +156,73 @@
     #endif
     )cpp");
   EXPECT_THAT(
-      build(Test.code()).getDiagnostics(),
+      buildDiags(Test.code()),
       ElementsAre(Diag(Test.range(), "use of undeclared identifier 'b'")));
 }
 
+TEST(DiagnosticsTest, ToLSP) {
+  clangd::Diag D;
+  D.Message = "something terrible happened";
+  D.Range = {pos(1, 2), pos(3, 4)};
+  D.InsideMainFile = true;
+  D.Severity = DiagnosticsEngine::Error;
+  D.File = "foo/bar/main.cpp";
+
+  clangd::Note NoteInMain;
+  NoteInMain.Message = "declared somewhere in the main file";
+  NoteInMain.Range = {pos(5, 6), pos(7, 8)};
+  NoteInMain.Severity = DiagnosticsEngine::Remark;
+  NoteInMain.File = "../foo/bar/main.cpp";
+  NoteInMain.InsideMainFile = true;
+  D.Notes.push_back(NoteInMain);
+
+  clangd::Note NoteInHeader;
+  NoteInHeader.Message = "declared somewhere in the header file";
+  NoteInHeader.Range = {pos(9, 10), pos(11, 12)};
+  NoteInHeader.Severity = DiagnosticsEngine::Note;
+  NoteInHeader.File = "../foo/baz/header.h";
+  NoteInHeader.InsideMainFile = false;
+  D.Notes.push_back(NoteInHeader);
+
+  clangd::Fix F;
+  F.Message = "do something";
+  D.Fixes.push_back(F);
+
+  auto MatchingLSP = [](const DiagBase &D, llvm::StringRef Message) {
+    clangd::Diagnostic Res;
+    Res.range = D.Range;
+    Res.severity = getSeverity(D.Severity);
+    Res.message = Message;
+    return Res;
+  };
+
+  // Diagnostics should turn into these:
+  clangd::Diagnostic MainLSP = MatchingLSP(D, R"(something terrible happened
+
+main.cpp:6:7: remark: declared somewhere in the main file
+
+../foo/baz/header.h:10:11:
+note: declared somewhere in the header file)");
+
+  clangd::Diagnostic NoteInMainLSP =
+      MatchingLSP(NoteInMain, R"(declared somewhere in the main file
+
+main.cpp:2:3: error: something terrible happened)");
+
+  // Transform dianostics and check the results.
+  std::vector<std::pair<clangd::Diagnostic, std::vector<clangd::Fix>>> LSPDiags;
+  toLSPDiags(D, [&](clangd::Diagnostic LSPDiag,
+                    llvm::ArrayRef<clangd::Fix> Fixes) {
+    LSPDiags.push_back({std::move(LSPDiag),
+                        std::vector<clangd::Fix>(Fixes.begin(), Fixes.end())});
+  });
+
+  EXPECT_THAT(
+      LSPDiags,
+      ElementsAre(Pair(EqualToLSPDiag(MainLSP), ElementsAre(EqualToFix(F))),
+                  Pair(EqualToLSPDiag(NoteInMainLSP), IsEmpty())));
+}
+
 } // namespace
 } // namespace clangd
 } // namespace clang
diff --git a/unittests/clangd/CodeCompleteTests.cpp b/unittests/clangd/CodeCompleteTests.cpp
index 7ffff71..48771a3 100644
--- a/unittests/clangd/CodeCompleteTests.cpp
+++ b/unittests/clangd/CodeCompleteTests.cpp
@@ -56,13 +56,13 @@
 using ::testing::Contains;
 using ::testing::Each;
 using ::testing::ElementsAre;
+using ::testing::Field;
 using ::testing::Not;
 using ::testing::UnorderedElementsAre;
-using ::testing::Field;
 
 class IgnoreDiagnostics : public DiagnosticsConsumer {
-  void onDiagnosticsReady(
-      PathRef File, Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {}
+  void onDiagnosticsReady(PathRef File,
+                          std::vector<Diag> Diagnostics) override {}
 };
 
 // GMock helpers for matching completion items.
@@ -121,7 +121,8 @@
   auto File = testPath("foo.cpp");
   Annotations Test(Text);
   runAddDocument(Server, File, Test.code());
-  auto CompletionList = runCodeComplete(Server, File, Test.point(), Opts).Value;
+  auto CompletionList =
+      cantFail(runCodeComplete(Server, File, Test.point(), Opts));
   // Sanity-check that filterText is valid.
   EXPECT_THAT(CompletionList.items, Each(NameContainsFilter()));
   return CompletionList;
@@ -319,11 +320,11 @@
   };
   // We used to test every combination of options, but that got too slow (2^N).
   auto Flags = {
-    &clangd::CodeCompleteOptions::IncludeMacros,
-    &clangd::CodeCompleteOptions::IncludeBriefComments,
-    &clangd::CodeCompleteOptions::EnableSnippets,
-    &clangd::CodeCompleteOptions::IncludeCodePatterns,
-    &clangd::CodeCompleteOptions::IncludeIneligibleResults,
+      &clangd::CodeCompleteOptions::IncludeMacros,
+      &clangd::CodeCompleteOptions::IncludeBriefComments,
+      &clangd::CodeCompleteOptions::EnableSnippets,
+      &clangd::CodeCompleteOptions::IncludeCodePatterns,
+      &clangd::CodeCompleteOptions::IncludeIneligibleResults,
   };
   // Test default options.
   Test({});
@@ -536,18 +537,18 @@
 
   auto I = memIndex({var("ns::index")});
   Opts.Index = I.get();
-  auto WithIndex = runCodeComplete(Server, File, Test.point(), Opts).Value;
+  auto WithIndex = cantFail(runCodeComplete(Server, File, Test.point(), Opts));
   EXPECT_THAT(WithIndex.items,
               UnorderedElementsAre(Named("local"), Named("index")));
   auto ClassFromPreamble =
-      runCodeComplete(Server, File, Test.point("2"), Opts).Value;
+      cantFail(runCodeComplete(Server, File, Test.point("2"), Opts));
   EXPECT_THAT(ClassFromPreamble.items, Contains(Named("member")));
 
   Opts.Index = nullptr;
-  auto WithoutIndex = runCodeComplete(Server, File, Test.point(), Opts).Value;
+  auto WithoutIndex =
+      cantFail(runCodeComplete(Server, File, Test.point(), Opts));
   EXPECT_THAT(WithoutIndex.items,
               UnorderedElementsAre(Named("local"), Named("preamble")));
-
 }
 
 TEST(CompletionTest, DynamicIndexMultiFile) {
@@ -576,7 +577,7 @@
   )cpp");
   runAddDocument(Server, File, Test.code());
 
-  auto Results = runCodeComplete(Server, File, Test.point(), {}).Value;
+  auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));
   // "XYZ" and "foo" are not included in the file being completed but are still
   // visible through the index.
   EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
@@ -607,6 +608,43 @@
   EXPECT_THAT(Results.items, Not(Contains(Labeled("clang::"))));
 }
 
+TEST(CompletionTest, BacktrackCrashes) {
+  // Sema calls code completion callbacks twice in these cases.
+  auto Results = completions(R"cpp(
+      namespace ns {
+      struct FooBarBaz {};
+      } // namespace ns
+
+     int foo(ns::FooBar^
+  )cpp");
+
+  EXPECT_THAT(Results.items, ElementsAre(Labeled("FooBarBaz")));
+
+  // Check we don't crash in that case too.
+  completions(R"cpp(
+    struct FooBarBaz {};
+    void test() {
+      if (FooBarBaz * x^) {}
+    }
+)cpp");
+}
+
+TEST(CompletionTest, CompleteInExcludedPPBranch) {
+  auto Results = completions(R"cpp(
+    int bar(int param_in_bar) {
+    }
+
+    int foo(int param_in_foo) {
+#if 0
+  par^
+#endif
+    }
+)cpp");
+
+  EXPECT_THAT(Results.items, Contains(Labeled("param_in_foo")));
+  EXPECT_THAT(Results.items, Not(Contains(Labeled("param_in_bar"))));
+}
+
 SignatureHelp signatures(StringRef Text) {
   MockFSProvider FS;
   MockCompilationDatabase CDB;
@@ -615,9 +653,7 @@
   auto File = testPath("foo.cpp");
   Annotations Test(Text);
   runAddDocument(Server, File, Test.code());
-  auto R = runSignatureHelp(Server, File, Test.point());
-  assert(R);
-  return R.get().Value;
+  return cantFail(runSignatureHelp(Server, File, Test.point()));
 }
 
 MATCHER_P(ParamsAre, P, "") {
@@ -690,6 +726,9 @@
     return true;
   }
 
+  void lookup(const LookupRequest &,
+              llvm::function_ref<void(const Symbol &)>) const override {}
+
   const std::vector<FuzzyFindRequest> allRequests() const { return Requests; }
 
 private:
diff --git a/unittests/clangd/DraftStoreTests.cpp b/unittests/clangd/DraftStoreTests.cpp
new file mode 100644
index 0000000..7443975
--- /dev/null
+++ b/unittests/clangd/DraftStoreTests.cpp
@@ -0,0 +1,350 @@
+//===-- DraftStoreTests.cpp -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Annotations.h"
+#include "DraftStore.h"
+#include "SourceCode.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+struct IncrementalTestStep {
+  StringRef Src;
+  StringRef Contents;
+};
+
+int rangeLength(StringRef Code, const Range &Rng) {
+  llvm::Expected<size_t> Start = positionToOffset(Code, Rng.start);
+  llvm::Expected<size_t> End = positionToOffset(Code, Rng.end);
+  assert(Start);
+  assert(End);
+  return *End - *Start;
+}
+
+/// Send the changes one by one to updateDraft, verify the intermediate results.
+void stepByStep(llvm::ArrayRef<IncrementalTestStep> Steps) {
+  DraftStore DS;
+  Annotations InitialSrc(Steps.front().Src);
+  constexpr llvm::StringLiteral Path("/hello.cpp");
+
+  // Set the initial content.
+  DS.addDraft(Path, InitialSrc.code());
+
+  for (size_t i = 1; i < Steps.size(); i++) {
+    Annotations SrcBefore(Steps[i - 1].Src);
+    Annotations SrcAfter(Steps[i].Src);
+    StringRef Contents = Steps[i - 1].Contents;
+    TextDocumentContentChangeEvent Event{
+        SrcBefore.range(),
+        rangeLength(SrcBefore.code(), SrcBefore.range()),
+        Contents.str(),
+    };
+
+    llvm::Expected<std::string> Result = DS.updateDraft(Path, {Event});
+    ASSERT_TRUE(!!Result);
+    EXPECT_EQ(*Result, SrcAfter.code());
+    EXPECT_EQ(*DS.getDraft(Path), SrcAfter.code());
+  }
+}
+
+/// Send all the changes at once to updateDraft, check only the final result.
+void allAtOnce(llvm::ArrayRef<IncrementalTestStep> Steps) {
+  DraftStore DS;
+  Annotations InitialSrc(Steps.front().Src);
+  Annotations FinalSrc(Steps.back().Src);
+  constexpr llvm::StringLiteral Path("/hello.cpp");
+  std::vector<TextDocumentContentChangeEvent> Changes;
+
+  for (size_t i = 0; i < Steps.size() - 1; i++) {
+    Annotations Src(Steps[i].Src);
+    StringRef Contents = Steps[i].Contents;
+
+    Changes.push_back({
+        Src.range(),
+        rangeLength(Src.code(), Src.range()),
+        Contents.str(),
+    });
+  }
+
+  // Set the initial content.
+  DS.addDraft(Path, InitialSrc.code());
+
+  llvm::Expected<std::string> Result = DS.updateDraft(Path, Changes);
+
+  ASSERT_TRUE(!!Result) << llvm::toString(Result.takeError());
+  EXPECT_EQ(*Result, FinalSrc.code());
+  EXPECT_EQ(*DS.getDraft(Path), FinalSrc.code());
+}
+
+TEST(DraftStoreIncrementalUpdateTest, Simple) {
+  // clang-format off
+  IncrementalTestStep Steps[] =
+    {
+      // Replace a range
+      {
+R"cpp(static int
+hello[[World]]()
+{})cpp",
+        "Universe"
+      },
+      // Delete a range
+      {
+R"cpp(static int
+hello[[Universe]]()
+{})cpp",
+        ""
+      },
+      // Add a range
+      {
+R"cpp(static int
+hello[[]]()
+{})cpp",
+        "Monde"
+      },
+      {
+R"cpp(static int
+helloMonde()
+{})cpp",
+        ""
+      }
+    };
+  // clang-format on
+
+  stepByStep(Steps);
+  allAtOnce(Steps);
+}
+
+TEST(DraftStoreIncrementalUpdateTest, MultiLine) {
+  // clang-format off
+  IncrementalTestStep Steps[] =
+    {
+      // Replace a range
+      {
+R"cpp(static [[int
+helloWorld]]()
+{})cpp",
+R"cpp(char
+welcome)cpp"
+      },
+      // Delete a range
+      {
+R"cpp(static char[[
+welcome]]()
+{})cpp",
+        ""
+      },
+      // Add a range
+      {
+R"cpp(static char[[]]()
+{})cpp",
+        R"cpp(
+cookies)cpp"
+      },
+      // Replace the whole file
+      {
+R"cpp([[static char
+cookies()
+{}]])cpp",
+        R"cpp(#include <stdio.h>
+)cpp"
+      },
+      // Delete the whole file
+      {
+        R"cpp([[#include <stdio.h>
+]])cpp",
+        "",
+      },
+      // Add something to an empty file
+      {
+        "[[]]",
+        R"cpp(int main() {
+)cpp",
+      },
+      {
+        R"cpp(int main() {
+)cpp",
+        ""
+      }
+    };
+  // clang-format on
+
+  stepByStep(Steps);
+  allAtOnce(Steps);
+}
+
+TEST(DraftStoreIncrementalUpdateTest, WrongRangeLength) {
+  DraftStore DS;
+  Path File = "foo.cpp";
+
+  DS.addDraft(File, "int main() {}\n");
+
+  TextDocumentContentChangeEvent Change;
+  Change.range.emplace();
+  Change.range->start.line = 0;
+  Change.range->start.character = 0;
+  Change.range->end.line = 0;
+  Change.range->end.character = 2;
+  Change.rangeLength = 10;
+
+  llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+  EXPECT_TRUE(!Result);
+  EXPECT_EQ(
+      llvm::toString(Result.takeError()),
+      "Change's rangeLength (10) doesn't match the computed range length (2).");
+}
+
+TEST(DraftStoreIncrementalUpdateTest, EndBeforeStart) {
+  DraftStore DS;
+  Path File = "foo.cpp";
+
+  DS.addDraft(File, "int main() {}\n");
+
+  TextDocumentContentChangeEvent Change;
+  Change.range.emplace();
+  Change.range->start.line = 0;
+  Change.range->start.character = 5;
+  Change.range->end.line = 0;
+  Change.range->end.character = 3;
+
+  llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+  EXPECT_TRUE(!Result);
+  EXPECT_EQ(llvm::toString(Result.takeError()),
+            "Range's end position (0:3) is before start position (0:5)");
+}
+
+TEST(DraftStoreIncrementalUpdateTest, StartCharOutOfRange) {
+  DraftStore DS;
+  Path File = "foo.cpp";
+
+  DS.addDraft(File, "int main() {}\n");
+
+  TextDocumentContentChangeEvent Change;
+  Change.range.emplace();
+  Change.range->start.line = 0;
+  Change.range->start.character = 100;
+  Change.range->end.line = 0;
+  Change.range->end.character = 100;
+  Change.text = "foo";
+
+  llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+  EXPECT_TRUE(!Result);
+  EXPECT_EQ(llvm::toString(Result.takeError()),
+            "Character value is out of range (100)");
+}
+
+TEST(DraftStoreIncrementalUpdateTest, EndCharOutOfRange) {
+  DraftStore DS;
+  Path File = "foo.cpp";
+
+  DS.addDraft(File, "int main() {}\n");
+
+  TextDocumentContentChangeEvent Change;
+  Change.range.emplace();
+  Change.range->start.line = 0;
+  Change.range->start.character = 0;
+  Change.range->end.line = 0;
+  Change.range->end.character = 100;
+  Change.text = "foo";
+
+  llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+  EXPECT_TRUE(!Result);
+  EXPECT_EQ(llvm::toString(Result.takeError()),
+            "Character value is out of range (100)");
+}
+
+TEST(DraftStoreIncrementalUpdateTest, StartLineOutOfRange) {
+  DraftStore DS;
+  Path File = "foo.cpp";
+
+  DS.addDraft(File, "int main() {}\n");
+
+  TextDocumentContentChangeEvent Change;
+  Change.range.emplace();
+  Change.range->start.line = 100;
+  Change.range->start.character = 0;
+  Change.range->end.line = 100;
+  Change.range->end.character = 0;
+  Change.text = "foo";
+
+  llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+  EXPECT_TRUE(!Result);
+  EXPECT_EQ(llvm::toString(Result.takeError()),
+            "Line value is out of range (100)");
+}
+
+TEST(DraftStoreIncrementalUpdateTest, EndLineOutOfRange) {
+  DraftStore DS;
+  Path File = "foo.cpp";
+
+  DS.addDraft(File, "int main() {}\n");
+
+  TextDocumentContentChangeEvent Change;
+  Change.range.emplace();
+  Change.range->start.line = 0;
+  Change.range->start.character = 0;
+  Change.range->end.line = 100;
+  Change.range->end.character = 0;
+  Change.text = "foo";
+
+  llvm::Expected<std::string> Result = DS.updateDraft(File, {Change});
+
+  EXPECT_TRUE(!Result);
+  EXPECT_EQ(llvm::toString(Result.takeError()),
+            "Line value is out of range (100)");
+}
+
+/// Check that if a valid change is followed by an invalid change, the original
+/// version of the document (prior to all changes) is kept.
+TEST(DraftStoreIncrementalUpdateTest, InvalidRangeInASequence) {
+  DraftStore DS;
+  Path File = "foo.cpp";
+
+  StringRef OriginalContents = "int main() {}\n";
+  DS.addDraft(File, OriginalContents);
+
+  // The valid change
+  TextDocumentContentChangeEvent Change1;
+  Change1.range.emplace();
+  Change1.range->start.line = 0;
+  Change1.range->start.character = 0;
+  Change1.range->end.line = 0;
+  Change1.range->end.character = 0;
+  Change1.text = "Hello ";
+
+  // The invalid change
+  TextDocumentContentChangeEvent Change2;
+  Change2.range.emplace();
+  Change2.range->start.line = 0;
+  Change2.range->start.character = 5;
+  Change2.range->end.line = 0;
+  Change2.range->end.character = 100;
+  Change2.text = "something";
+
+  llvm::Expected<std::string> Result = DS.updateDraft(File, {Change1, Change2});
+
+  EXPECT_TRUE(!Result);
+  EXPECT_EQ(llvm::toString(Result.takeError()),
+            "Character value is out of range (100)");
+
+  llvm::Optional<std::string> Contents = DS.getDraft(File);
+  EXPECT_TRUE(Contents);
+  EXPECT_EQ(*Contents, OriginalContents);
+}
+
+} // namespace
+} // namespace clangd
+} // namespace clang
diff --git a/unittests/clangd/HeadersTests.cpp b/unittests/clangd/HeadersTests.cpp
index 29452ef..9a5ca48 100644
--- a/unittests/clangd/HeadersTests.cpp
+++ b/unittests/clangd/HeadersTests.cpp
@@ -29,7 +29,7 @@
                         bool ExpectError = false) {
     if (Preferred.empty())
       Preferred = Original;
-    auto VFS = FS.getTaggedFileSystem(MainFile).Value;
+    auto VFS = FS.getFileSystem();
     auto Cmd = CDB.getCompileCommand(MainFile);
     assert(static_cast<bool>(Cmd));
     VFS->setCurrentWorkingDirectory(Cmd->Directory);
diff --git a/unittests/clangd/IndexTests.cpp b/unittests/clangd/IndexTests.cpp
index 20eb452..4d7c430 100644
--- a/unittests/clangd/IndexTests.cpp
+++ b/unittests/clangd/IndexTests.cpp
@@ -29,7 +29,7 @@
     Sym.Scope = "";
   } else {
     Sym.Name = QName.substr(Pos + 2);
-    Sym.Scope = QName.substr(0, Pos);
+    Sym.Scope = QName.substr(0, Pos + 2);
   }
   return Sym;
 }
@@ -89,13 +89,16 @@
   return generateSymbols(Names, WeakSymbols);
 }
 
+std::string getQualifiedName(const Symbol &Sym) {
+  return (Sym.Scope + Sym.Name).str();
+}
+
 std::vector<std::string> match(const SymbolIndex &I,
                                const FuzzyFindRequest &Req,
                                bool *Incomplete = nullptr) {
   std::vector<std::string> Matches;
   bool IsIncomplete = I.fuzzyFind(Req, [&](const Symbol &Sym) {
-    Matches.push_back(
-        (Sym.Scope + (Sym.Scope.empty() ? "" : "::") + Sym.Name).str());
+    Matches.push_back(getQualifiedName(Sym));
   });
   if (Incomplete)
     *Incomplete = IsIncomplete;
@@ -178,7 +181,7 @@
   I.build(generateSymbols({"a::y1", "a::y2", "a::x", "b::y2", "y3"}));
   FuzzyFindRequest Req;
   Req.Query = "y";
-  Req.Scopes = {"a"};
+  Req.Scopes = {"a::"};
   EXPECT_THAT(match(I, Req), UnorderedElementsAre("a::y1", "a::y2"));
 }
 
@@ -187,7 +190,7 @@
   I.build(generateSymbols({"a::y1", "a::y2", "a::x", "b::y3", "y3"}));
   FuzzyFindRequest Req;
   Req.Query = "y";
-  Req.Scopes = {"a", "b"};
+  Req.Scopes = {"a::", "b::"};
   EXPECT_THAT(match(I, Req), UnorderedElementsAre("a::y1", "a::y2", "b::y3"));
 }
 
@@ -196,7 +199,7 @@
   I.build(generateSymbols({"a::y1", "a::b::y2"}));
   FuzzyFindRequest Req;
   Req.Query = "y";
-  Req.Scopes = {"a"};
+  Req.Scopes = {"a::"};
   EXPECT_THAT(match(I, Req), UnorderedElementsAre("a::y1"));
 }
 
@@ -205,16 +208,60 @@
   I.build(generateSymbols({"ns::ABC", "ns::abc"}));
   FuzzyFindRequest Req;
   Req.Query = "AB";
-  Req.Scopes = {"ns"};
+  Req.Scopes = {"ns::"};
   EXPECT_THAT(match(I, Req), UnorderedElementsAre("ns::ABC", "ns::abc"));
 }
 
-TEST(MergeTest, MergeIndex) {
+// Returns qualified names of symbols with any of IDs in the index.
+std::vector<std::string> lookup(const SymbolIndex &I,
+                                llvm::ArrayRef<SymbolID> IDs) {
+  LookupRequest Req;
+  Req.IDs.insert(IDs.begin(), IDs.end());
+  std::vector<std::string> Results;
+  I.lookup(Req, [&](const Symbol &Sym) {
+    Results.push_back(getQualifiedName(Sym));
+  });
+  return Results;
+}
+
+TEST(MemIndexTest, Lookup) {
+  MemIndex I;
+  I.build(generateSymbols({"ns::abc", "ns::xyz"}));
+  EXPECT_THAT(lookup(I, SymbolID("ns::abc")), UnorderedElementsAre("ns::abc"));
+  EXPECT_THAT(lookup(I, {SymbolID("ns::abc"), SymbolID("ns::xyz")}),
+              UnorderedElementsAre("ns::abc", "ns::xyz"));
+  EXPECT_THAT(lookup(I, {SymbolID("ns::nonono"), SymbolID("ns::xyz")}),
+              UnorderedElementsAre("ns::xyz"));
+  EXPECT_THAT(lookup(I, SymbolID("ns::nonono")), UnorderedElementsAre());
+}
+
+TEST(MergeIndexTest, Lookup) {
+  MemIndex I, J;
+  I.build(generateSymbols({"ns::A", "ns::B"}));
+  J.build(generateSymbols({"ns::B", "ns::C"}));
+  EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::A")),
+              UnorderedElementsAre("ns::A"));
+  EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::B")),
+              UnorderedElementsAre("ns::B"));
+  EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::C")),
+              UnorderedElementsAre("ns::C"));
+  EXPECT_THAT(
+      lookup(*mergeIndex(&I, &J), {SymbolID("ns::A"), SymbolID("ns::B")}),
+      UnorderedElementsAre("ns::A", "ns::B"));
+  EXPECT_THAT(
+      lookup(*mergeIndex(&I, &J), {SymbolID("ns::A"), SymbolID("ns::C")}),
+      UnorderedElementsAre("ns::A", "ns::C"));
+  EXPECT_THAT(lookup(*mergeIndex(&I, &J), SymbolID("ns::D")),
+              UnorderedElementsAre());
+  EXPECT_THAT(lookup(*mergeIndex(&I, &J), {}), UnorderedElementsAre());
+}
+
+TEST(MergeIndexTest, FuzzyFind) {
   MemIndex I, J;
   I.build(generateSymbols({"ns::A", "ns::B"}));
   J.build(generateSymbols({"ns::B", "ns::C"}));
   FuzzyFindRequest Req;
-  Req.Scopes = {"ns"};
+  Req.Scopes = {"ns::"};
   EXPECT_THAT(match(*mergeIndex(&I, &J), Req),
               UnorderedElementsAre("ns::A", "ns::B", "ns::C"));
 }
@@ -225,6 +272,8 @@
   L.Name = R.Name = "Foo";                    // same in both
   L.CanonicalDeclaration.FileURI = "file:///left.h"; // differs
   R.CanonicalDeclaration.FileURI = "file:///right.h";
+  L.References = 1;
+  R.References = 2;
   L.CompletionPlainInsertText = "f00";        // present in left only
   R.CompletionSnippetInsertText = "f0{$1:0}"; // present in right only
   Symbol::Details DetL, DetR;
@@ -238,6 +287,7 @@
   Symbol M = mergeSymbol(L, R, &Scratch);
   EXPECT_EQ(M.Name, "Foo");
   EXPECT_EQ(M.CanonicalDeclaration.FileURI, "file:///left.h");
+  EXPECT_EQ(M.References, 3u);
   EXPECT_EQ(M.CompletionPlainInsertText, "f00");
   EXPECT_EQ(M.CompletionSnippetInsertText, "f0{$1:0}");
   ASSERT_TRUE(M.Detail);
diff --git a/unittests/clangd/SourceCodeTests.cpp b/unittests/clangd/SourceCodeTests.cpp
index 86c8a09..d787641 100644
--- a/unittests/clangd/SourceCodeTests.cpp
+++ b/unittests/clangd/SourceCodeTests.cpp
@@ -7,7 +7,9 @@
 //
 //===----------------------------------------------------------------------===//
 #include "SourceCode.h"
+#include "llvm/Support/Error.h"
 #include "llvm/Support/raw_os_ostream.h"
+#include "llvm/Testing/Support/Error.h"
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
 
@@ -15,6 +17,9 @@
 namespace clangd {
 namespace {
 
+using llvm::Failed;
+using llvm::HasValue;
+
 MATCHER_P2(Pos, Line, Col, "") {
   return arg.line == Line && arg.character == Col;
 }
@@ -33,30 +38,57 @@
 
 TEST(SourceCodeTests, PositionToOffset) {
   // line out of bounds
-  EXPECT_EQ(0u, positionToOffset(File, position(-1, 2)));
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(-1, 2)), Failed());
   // first line
-  EXPECT_EQ(0u, positionToOffset(File, position(0, -1))); // out of range
-  EXPECT_EQ(0u, positionToOffset(File, position(0, 0)));  // first character
-  EXPECT_EQ(3u, positionToOffset(File, position(0, 3)));  // middle character
-  EXPECT_EQ(6u, positionToOffset(File, position(0, 6)));  // last character
-  EXPECT_EQ(7u, positionToOffset(File, position(0, 7)));  // the newline itself
-  EXPECT_EQ(8u, positionToOffset(File, position(0, 8)));  // out of range
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, -1)),
+                       Failed()); // out of range
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 0)),
+                       HasValue(0)); // first character
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 3)),
+                       HasValue(3)); // middle character
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 6)),
+                       HasValue(6)); // last character
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7)),
+                       HasValue(7)); // the newline itself
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 7), false),
+                       HasValue(7));
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8)),
+                       HasValue(7)); // out of range
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(0, 8), false),
+                       Failed()); // out of range
   // middle line
-  EXPECT_EQ(8u, positionToOffset(File, position(1, -1))); // out of range
-  EXPECT_EQ(8u, positionToOffset(File, position(1, 0)));  // first character
-  EXPECT_EQ(11u, positionToOffset(File, position(1, 3))); // middle character
-  EXPECT_EQ(14u, positionToOffset(File, position(1, 6))); // last character
-  EXPECT_EQ(15u, positionToOffset(File, position(1, 7))); // the newline itself
-  EXPECT_EQ(16u, positionToOffset(File, position(1, 8))); // out of range
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, -1)),
+                       Failed()); // out of range
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 0)),
+                       HasValue(8)); // first character
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3)),
+                       HasValue(11)); // middle character
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 3), false),
+                       HasValue(11));
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 6)),
+                       HasValue(14)); // last character
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 7)),
+                       HasValue(15)); // the newline itself
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8)),
+                       HasValue(15)); // out of range
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(1, 8), false),
+                       Failed()); // out of range
   // last line
-  EXPECT_EQ(16u, positionToOffset(File, position(2, -1))); // out of range
-  EXPECT_EQ(16u, positionToOffset(File, position(2, 0)));  // first character
-  EXPECT_EQ(19u, positionToOffset(File, position(2, 3)));  // middle character
-  EXPECT_EQ(23u, positionToOffset(File, position(2, 7)));  // last character
-  EXPECT_EQ(24u, positionToOffset(File, position(2, 8)));  // EOF
-  EXPECT_EQ(24u, positionToOffset(File, position(2, 9)));  // out of range
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, -1)),
+                       Failed()); // out of range
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 0)),
+                       HasValue(16)); // first character
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 3)),
+                       HasValue(19)); // middle character
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 7)),
+                       HasValue(23)); // last character
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 8)),
+                       HasValue(24)); // EOF
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(2, 9), false),
+                       Failed()); // out of range
   // line out of bounds
-  EXPECT_EQ(24u, positionToOffset(File, position(3, 1)));
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 0)), Failed());
+  EXPECT_THAT_EXPECTED(positionToOffset(File, position(3, 1)), Failed());
 }
 
 TEST(SourceCodeTests, OffsetToPosition) {
diff --git a/unittests/clangd/SymbolCollectorTests.cpp b/unittests/clangd/SymbolCollectorTests.cpp
index 363fd00..76eace5 100644
--- a/unittests/clangd/SymbolCollectorTests.cpp
+++ b/unittests/clangd/SymbolCollectorTests.cpp
@@ -59,6 +59,7 @@
   return arg.Definition.StartOffset == Offsets.first &&
          arg.Definition.EndOffset == Offsets.second;
 }
+MATCHER_P(Refs, R, "") { return int(arg.References) == R; }
 
 namespace clang {
 namespace clangd {
@@ -198,6 +199,19 @@
                    QName("foo::bar::v2"), QName("foo::baz")}));
 }
 
+TEST_F(SymbolCollectorTest, Template) {
+  Annotations Header(R"(
+    // Template is indexed, specialization and instantiation is not.
+    template <class T> struct [[Tmpl]] {T x = 0;};
+    template <> struct Tmpl<int> {};
+    extern template struct Tmpl<float>;
+    template struct Tmpl<double>;
+  )");
+  runSymbolCollector(Header.code(), /*Main=*/"");
+  EXPECT_THAT(Symbols, UnorderedElementsAreArray({AllOf(
+                           QName("Tmpl"), DeclRange(Header.offsetRange()))}));
+}
+
 TEST_F(SymbolCollectorTest, Locations) {
   Annotations Header(R"cpp(
     // Declared in header, defined in main.
@@ -229,6 +243,31 @@
           AllOf(QName("Z"), DeclRange(Header.offsetRange("zdecl")))));
 }
 
+TEST_F(SymbolCollectorTest, References) {
+  const std::string Header = R"(
+    class W;
+    class X {};
+    class Y;
+    class Z {}; // not used anywhere
+    Y* y = nullptr;  // used in header doesn't count
+  )";
+  const std::string Main = R"(
+    W* w = nullptr;
+    W* w2 = nullptr; // only one usage counts
+    X x();
+    class V;
+    V* v = nullptr; // Used, but not eligible for indexing.
+    class Y{}; // definition doesn't count as a reference
+  )";
+  CollectorOpts.CountReferences = true;
+  runSymbolCollector(Header, Main);
+  EXPECT_THAT(Symbols,
+              UnorderedElementsAre(AllOf(QName("W"), Refs(1)),
+                                   AllOf(QName("X"), Refs(1)),
+                                   AllOf(QName("Y"), Refs(0)),
+                                   AllOf(QName("Z"), Refs(0)), QName("y")));
+}
+
 TEST_F(SymbolCollectorTest, SymbolRelativeNoFallback) {
   runSymbolCollector("class Foo {};", /*Main=*/"");
   EXPECT_THAT(Symbols, UnorderedElementsAre(
diff --git a/unittests/clangd/SyncAPI.cpp b/unittests/clangd/SyncAPI.cpp
index 62b68ca..28393ee 100644
--- a/unittests/clangd/SyncAPI.cpp
+++ b/unittests/clangd/SyncAPI.cpp
@@ -11,8 +11,9 @@
 namespace clang {
 namespace clangd {
 
-void runAddDocument(ClangdServer &Server, PathRef File, StringRef Contents) {
-  Server.addDocument(File, Contents);
+void runAddDocument(ClangdServer &Server, PathRef File, StringRef Contents,
+                    WantDiagnostics WantDiags, bool SkipCache) {
+  Server.addDocument(File, Contents, WantDiags, SkipCache);
   if (!Server.blockUntilIdleForTest())
     llvm_unreachable("not idle after addDocument");
 }
@@ -67,31 +68,31 @@
 }
 } // namespace
 
-Tagged<CompletionList> runCodeComplete(ClangdServer &Server, PathRef File,
-                                       Position Pos,
-                                       clangd::CodeCompleteOptions Opts) {
-  llvm::Optional<Tagged<CompletionList>> Result;
+llvm::Expected<CompletionList>
+runCodeComplete(ClangdServer &Server, PathRef File, Position Pos,
+                clangd::CodeCompleteOptions Opts) {
+  llvm::Optional<llvm::Expected<CompletionList>> Result;
   Server.codeComplete(File, Pos, Opts, capture(Result));
   return std::move(*Result);
 }
 
-llvm::Expected<Tagged<SignatureHelp>>
-runSignatureHelp(ClangdServer &Server, PathRef File, Position Pos) {
-  llvm::Optional<llvm::Expected<Tagged<SignatureHelp>>> Result;
+llvm::Expected<SignatureHelp> runSignatureHelp(ClangdServer &Server,
+                                               PathRef File, Position Pos) {
+  llvm::Optional<llvm::Expected<SignatureHelp>> Result;
   Server.signatureHelp(File, Pos, capture(Result));
   return std::move(*Result);
 }
 
-llvm::Expected<Tagged<std::vector<Location>>>
+llvm::Expected<std::vector<Location>>
 runFindDefinitions(ClangdServer &Server, PathRef File, Position Pos) {
-  llvm::Optional<llvm::Expected<Tagged<std::vector<Location>>>> Result;
+  llvm::Optional<llvm::Expected<std::vector<Location>>> Result;
   Server.findDefinitions(File, Pos, capture(Result));
   return std::move(*Result);
 }
 
-llvm::Expected<Tagged<std::vector<DocumentHighlight>>>
+llvm::Expected<std::vector<DocumentHighlight>>
 runFindDocumentHighlights(ClangdServer &Server, PathRef File, Position Pos) {
-  llvm::Optional<llvm::Expected<Tagged<std::vector<DocumentHighlight>>>> Result;
+  llvm::Optional<llvm::Expected<std::vector<DocumentHighlight>>> Result;
   Server.findDocumentHighlights(File, Pos, capture(Result));
   return std::move(*Result);
 }
diff --git a/unittests/clangd/SyncAPI.h b/unittests/clangd/SyncAPI.h
index 9bfe155..c0fcb93 100644
--- a/unittests/clangd/SyncAPI.h
+++ b/unittests/clangd/SyncAPI.h
@@ -19,19 +19,21 @@
 namespace clangd {
 
 // Calls addDocument and then blockUntilIdleForTest.
-void runAddDocument(ClangdServer &Server, PathRef File, StringRef Contents);
+void runAddDocument(ClangdServer &Server, PathRef File, StringRef Contents,
+                    WantDiagnostics WantDiags = WantDiagnostics::Auto,
+                    bool SkipCache = false);
 
-Tagged<CompletionList> runCodeComplete(ClangdServer &Server, PathRef File,
-                                       Position Pos,
-                                       clangd::CodeCompleteOptions Opts);
+llvm::Expected<CompletionList>
+runCodeComplete(ClangdServer &Server, PathRef File, Position Pos,
+                clangd::CodeCompleteOptions Opts);
 
-llvm::Expected<Tagged<SignatureHelp>>
-runSignatureHelp(ClangdServer &Server, PathRef File, Position Pos);
+llvm::Expected<SignatureHelp> runSignatureHelp(ClangdServer &Server,
+                                               PathRef File, Position Pos);
 
-llvm::Expected<Tagged<std::vector<Location>>>
+llvm::Expected<std::vector<Location>>
 runFindDefinitions(ClangdServer &Server, PathRef File, Position Pos);
 
-llvm::Expected<Tagged<std::vector<DocumentHighlight>>>
+llvm::Expected<std::vector<DocumentHighlight>>
 runFindDocumentHighlights(ClangdServer &Server, PathRef File, Position Pos);
 
 llvm::Expected<std::vector<tooling::Replacement>>
diff --git a/unittests/clangd/TUSchedulerTests.cpp b/unittests/clangd/TUSchedulerTests.cpp
index 14588d6..2235e87 100644
--- a/unittests/clangd/TUSchedulerTests.cpp
+++ b/unittests/clangd/TUSchedulerTests.cpp
@@ -21,7 +21,7 @@
 using ::testing::Pair;
 using ::testing::Pointee;
 
-void ignoreUpdate(llvm::Optional<std::vector<DiagWithFixIts>>) {}
+void ignoreUpdate(llvm::Optional<std::vector<Diag>>) {}
 void ignoreError(llvm::Error Err) {
   handleAllErrors(std::move(Err), [](const llvm::ErrorInfoBase &) {});
 }
@@ -102,20 +102,20 @@
         /*UpdateDebounce=*/std::chrono::steady_clock::duration::zero());
     auto Path = testPath("foo.cpp");
     S.update(Path, getInputs(Path, ""), WantDiagnostics::Yes,
-             [&](std::vector<DiagWithFixIts>) { Ready.wait(); });
+             [&](std::vector<Diag>) { Ready.wait(); });
 
     S.update(Path, getInputs(Path, "request diags"), WantDiagnostics::Yes,
-             [&](std::vector<DiagWithFixIts> Diags) { ++CallbackCount; });
+             [&](std::vector<Diag> Diags) { ++CallbackCount; });
     S.update(Path, getInputs(Path, "auto (clobbered)"), WantDiagnostics::Auto,
-             [&](std::vector<DiagWithFixIts> Diags) {
+             [&](std::vector<Diag> Diags) {
                ADD_FAILURE() << "auto should have been cancelled by auto";
              });
     S.update(Path, getInputs(Path, "request no diags"), WantDiagnostics::No,
-             [&](std::vector<DiagWithFixIts> Diags) {
+             [&](std::vector<Diag> Diags) {
                ADD_FAILURE() << "no diags should not be called back";
              });
     S.update(Path, getInputs(Path, "auto (produces)"), WantDiagnostics::Auto,
-             [&](std::vector<DiagWithFixIts> Diags) { ++CallbackCount; });
+             [&](std::vector<Diag> Diags) { ++CallbackCount; });
     Ready.notify();
   }
   EXPECT_EQ(2, CallbackCount);
@@ -131,15 +131,15 @@
     // FIXME: we could probably use timeouts lower than 1 second here.
     auto Path = testPath("foo.cpp");
     S.update(Path, getInputs(Path, "auto (debounced)"), WantDiagnostics::Auto,
-             [&](std::vector<DiagWithFixIts> Diags) {
+             [&](std::vector<Diag> Diags) {
                ADD_FAILURE() << "auto should have been debounced and canceled";
              });
     std::this_thread::sleep_for(std::chrono::milliseconds(200));
     S.update(Path, getInputs(Path, "auto (timed out)"), WantDiagnostics::Auto,
-             [&](std::vector<DiagWithFixIts> Diags) { ++CallbackCount; });
+             [&](std::vector<Diag> Diags) { ++CallbackCount; });
     std::this_thread::sleep_for(std::chrono::seconds(2));
     S.update(Path, getInputs(Path, "auto (shut down)"), WantDiagnostics::Auto,
-             [&](std::vector<DiagWithFixIts> Diags) { ++CallbackCount; });
+             [&](std::vector<Diag> Diags) { ++CallbackCount; });
   }
   EXPECT_EQ(2, CallbackCount);
 }
@@ -190,8 +190,8 @@
         {
           WithContextValue WithNonce(NonceKey, ++Nonce);
           S.update(File, Inputs, WantDiagnostics::Auto,
-                   [Nonce, &Mut, &TotalUpdates](
-                       llvm::Optional<std::vector<DiagWithFixIts>> Diags) {
+                   [Nonce, &Mut,
+                    &TotalUpdates](llvm::Optional<std::vector<Diag>> Diags) {
                      EXPECT_THAT(Context::current().get(NonceKey),
                                  Pointee(Nonce));
 
@@ -226,8 +226,7 @@
                 EXPECT_THAT(Context::current().get(NonceKey), Pointee(Nonce));
 
                 ASSERT_TRUE((bool)Preamble);
-                EXPECT_EQ(Preamble->Inputs.FS, Inputs.FS);
-                EXPECT_EQ(Preamble->Inputs.Contents, Inputs.Contents);
+                EXPECT_EQ(Preamble->Contents, Inputs.Contents);
 
                 std::lock_guard<std::mutex> Lock(Mut);
                 ++TotalPreambleReads;
diff --git a/unittests/clangd/TestFS.cpp b/unittests/clangd/TestFS.cpp
index 197c93f..1b9bb04 100644
--- a/unittests/clangd/TestFS.cpp
+++ b/unittests/clangd/TestFS.cpp
@@ -26,16 +26,6 @@
   return MemFS;
 }
 
-Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
-MockFSProvider::getTaggedFileSystem(PathRef File) {
-  if (ExpectedFile) {
-    EXPECT_EQ(*ExpectedFile, File);
-  }
-
-  auto FS = buildTestFS(Files);
-  return make_tagged(FS, Tag);
-}
-
 MockCompilationDatabase::MockCompilationDatabase(bool UseRelPaths)
     : ExtraClangFlags({"-ffreestanding"}), UseRelPaths(UseRelPaths) {
   // -ffreestanding avoids implicit stdc-predef.h.
diff --git a/unittests/clangd/TestFS.h b/unittests/clangd/TestFS.h
index b86adbe..bec8817 100644
--- a/unittests/clangd/TestFS.h
+++ b/unittests/clangd/TestFS.h
@@ -26,13 +26,12 @@
 // A VFS provider that returns TestFSes containing a provided set of files.
 class MockFSProvider : public FileSystemProvider {
 public:
-  Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
-  getTaggedFileSystem(PathRef File) override;
+  IntrusiveRefCntPtr<vfs::FileSystem> getFileSystem() override {
+    return buildTestFS(Files);
+  }
 
-  llvm::Optional<std::string> ExpectedFile;
   // If relative paths are used, they are resolved with testPath().
   llvm::StringMap<std::string> Files;
-  VFSTag Tag = VFSTag();
 };
 
 // A Compilation database that returns a fixed set of compile flags.
diff --git a/unittests/clangd/TraceTests.cpp b/unittests/clangd/TraceTests.cpp
index 553997a..02fe7da 100644
--- a/unittests/clangd/TraceTests.cpp
+++ b/unittests/clangd/TraceTests.cpp
@@ -41,7 +41,7 @@
   }
   bool Match = true;
   SmallString<32> Tmp;
-  for (auto Prop : *M) {
+  for (auto &Prop : *M) {
     auto *K = dyn_cast_or_null<yaml::ScalarNode>(Prop.getKey());
     if (!K)
       continue;
diff --git a/unittests/clangd/XRefsTests.cpp b/unittests/clangd/XRefsTests.cpp
index c2dd053..e112043 100644
--- a/unittests/clangd/XRefsTests.cpp
+++ b/unittests/clangd/XRefsTests.cpp
@@ -41,8 +41,8 @@
 using testing::UnorderedElementsAreArray;
 
 class IgnoreDiagnostics : public DiagnosticsConsumer {
-  void onDiagnosticsReady(
-      PathRef File, Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {}
+  void onDiagnosticsReady(PathRef File,
+                          std::vector<Diag> Diagnostics) override {}
 };
 
 // FIXME: this is duplicated with FileIndexTests. Share it.
@@ -119,7 +119,7 @@
   const char *Tests[] = {
       R"cpp(// Local variable
         int main() {
-          [[int bonjour]];
+          int [[bonjour]];
           ^bonjour = 2;
           int test1 = bonjour;
         }
@@ -127,7 +127,7 @@
 
       R"cpp(// Struct
         namespace ns1 {
-        [[struct MyClass {}]];
+        struct [[MyClass]] {};
         } // namespace ns1
         int main() {
           ns1::My^Class* Params;
@@ -135,21 +135,21 @@
       )cpp",
 
       R"cpp(// Function definition via pointer
-        [[int foo(int) {}]]
+        int [[foo]](int) {}
         int main() {
           auto *X = &^foo;
         }
       )cpp",
 
       R"cpp(// Function declaration via call
-        [[int foo(int)]];
+        int [[foo]](int);
         int main() {
           return ^foo(42);
         }
       )cpp",
 
       R"cpp(// Field
-        struct Foo { [[int x]]; };
+        struct Foo { int [[x]]; };
         int main() {
           Foo bar;
           bar.^x;
@@ -158,27 +158,27 @@
 
       R"cpp(// Field, member initializer
         struct Foo {
-          [[int x]];
+          int [[x]];
           Foo() : ^x(0) {}
         };
       )cpp",
 
       R"cpp(// Field, GNU old-style field designator
-        struct Foo { [[int x]]; };
+        struct Foo { int [[x]]; };
         int main() {
           Foo bar = { ^x : 1 };
         }
       )cpp",
 
       R"cpp(// Field, field designator
-        struct Foo { [[int x]]; };
+        struct Foo { int [[x]]; };
         int main() {
           Foo bar = { .^x = 2 };
         }
       )cpp",
 
       R"cpp(// Method call
-        struct Foo { [[int x()]]; };
+        struct Foo { int [[x]](); };
         int main() {
           Foo bar;
           bar.^x();
@@ -186,7 +186,7 @@
       )cpp",
 
       R"cpp(// Typedef
-        [[typedef int Foo]];
+        typedef int [[Foo]];
         int main() {
           ^Foo bar;
         }
@@ -199,30 +199,51 @@
       )cpp", */
 
       R"cpp(// Namespace
-        [[namespace ns {
+        namespace [[ns]] {
         struct Foo { static void bar(); }
-        }]] // namespace ns
+        } // namespace ns
         int main() { ^ns::Foo::bar(); }
       )cpp",
 
       R"cpp(// Macro
         #define MACRO 0
-        #define [[MACRO 1]]
+        #define [[MACRO]] 1
         int main() { return ^MACRO; }
         #define MACRO 2
         #undef macro
       )cpp",
 
+      R"cpp(// Macro
+       class TTT { public: int a; };
+       #define [[FF]](S) if (int b = S.a) {}
+       void f() {
+         TTT t;
+         F^F(t);
+       }
+      )cpp",
+
       R"cpp(// Forward class declaration
         class Foo;
-        [[class Foo {}]];
+        class [[Foo]] {};
         F^oo* foo();
       )cpp",
 
       R"cpp(// Function declaration
         void foo();
         void g() { f^oo(); }
-        [[void foo() {}]]
+        void [[foo]]() {}
+      )cpp",
+
+      R"cpp(
+        #define FF(name) class name##_Test {};
+        [[FF]](my);
+        void f() { my^_Test a; }
+      )cpp",
+
+      R"cpp(
+         #define FF() class [[Test]] {};
+         FF();
+         void f() { T^est a; }
       )cpp",
   };
   for (const char *Test : Tests) {
@@ -236,7 +257,7 @@
 
 TEST(GoToDefinition, RelPathsInCompileCommand) {
   Annotations SourceAnnotations(R"cpp(
-[[int foo]];
+int [[foo]];
 int baz = f^oo;
 )cpp");
 
@@ -254,9 +275,8 @@
       runFindDefinitions(Server, FooCpp, SourceAnnotations.point());
   EXPECT_TRUE(bool(Locations)) << "findDefinitions returned an error";
 
-  EXPECT_THAT(
-      Locations->Value,
-      ElementsAre(Location{URIForFile{FooCpp}, SourceAnnotations.range()}));
+  EXPECT_THAT(*Locations, ElementsAre(Location{URIForFile{FooCpp},
+                                               SourceAnnotations.range()}));
 }
 
 TEST(Hover, All) {
@@ -584,7 +604,9 @@
   auto FooH = testPath("foo.h");
   auto FooHUri = URIForFile{FooH};
 
-  const char *HeaderContents = R"cpp([[]]int a;)cpp";
+  const char *HeaderContents = R"cpp([[]]#pragma once
+                                     int a;
+                                     )cpp";
   Annotations HeaderAnnotations(HeaderContents);
   FS.Files[FooH] = HeaderAnnotations.code();
 
@@ -595,38 +617,38 @@
   auto Locations =
       runFindDefinitions(Server, FooCpp, SourceAnnotations.point());
   ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
-  EXPECT_THAT(Locations->Value,
+  EXPECT_THAT(*Locations,
               ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
 
   // Test include in preamble, last char.
   Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("2"));
   ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
-  EXPECT_THAT(Locations->Value,
+  EXPECT_THAT(*Locations,
               ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
 
   Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("3"));
   ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
-  EXPECT_THAT(Locations->Value,
+  EXPECT_THAT(*Locations,
               ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
 
   // Test include outside of preamble.
   Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("6"));
   ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
-  EXPECT_THAT(Locations->Value,
+  EXPECT_THAT(*Locations,
               ElementsAre(Location{FooHUri, HeaderAnnotations.range()}));
 
   // Test a few positions that do not result in Locations.
   Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("4"));
   ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
-  EXPECT_THAT(Locations->Value, IsEmpty());
+  EXPECT_THAT(*Locations, IsEmpty());
 
   Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("5"));
   ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
-  EXPECT_THAT(Locations->Value, IsEmpty());
+  EXPECT_THAT(*Locations, IsEmpty());
 
   Locations = runFindDefinitions(Server, FooCpp, SourceAnnotations.point("7"));
   ASSERT_TRUE(bool(Locations)) << "findDefinitions returned an error";
-  EXPECT_THAT(Locations->Value, IsEmpty());
+  EXPECT_THAT(*Locations, IsEmpty());
 }
 
 } // namespace