brettw updated this revision to Diff 467895.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D134371/new/

https://reviews.llvm.org/D134371

Files:
  clang-tools-extra/clang-doc/BitcodeReader.cpp
  clang-tools-extra/clang-doc/BitcodeWriter.cpp
  clang-tools-extra/clang-doc/BitcodeWriter.h
  clang-tools-extra/clang-doc/HTMLGenerator.cpp
  clang-tools-extra/clang-doc/MDGenerator.cpp
  clang-tools-extra/clang-doc/Mapper.cpp
  clang-tools-extra/clang-doc/Mapper.h
  clang-tools-extra/clang-doc/Representation.cpp
  clang-tools-extra/clang-doc/Representation.h
  clang-tools-extra/clang-doc/Serialize.cpp
  clang-tools-extra/clang-doc/Serialize.h
  clang-tools-extra/clang-doc/YAMLGenerator.cpp
  clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
  clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
  clang-tools-extra/unittests/clang-doc/ClangDocTest.h
  clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
  clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
  clang-tools-extra/unittests/clang-doc/MergeTest.cpp
  clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
  clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp

Index: clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
+++ clang-tools-extra/unittests/clang-doc/YAMLGeneratorTest.cpp
@@ -28,15 +28,16 @@
   I.Path = "path/to/A";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
-                                 InfoType::IT_namespace, "path/to/A/Namespace");
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
-                              "path/to/A/Namespace");
-  I.ChildFunctions.emplace_back();
-  I.ChildFunctions.back().Name = "OneFunction";
-  I.ChildFunctions.back().Access = AccessSpecifier::AS_none;
-  I.ChildEnums.emplace_back();
-  I.ChildEnums.back().Name = "OneEnum";
+  I.Children.Namespaces.emplace_back(EmptySID, "ChildNamespace",
+                                     InfoType::IT_namespace,
+                                     "path/to/A/Namespace");
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                                  "path/to/A/Namespace");
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Functions.back().Access = AccessSpecifier::AS_none;
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getYAMLGenerator();
   assert(G);
@@ -100,8 +101,8 @@
   I.TagType = TagTypeKind::TTK_Class;
   I.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
                        AccessSpecifier::AS_public, true);
-  I.Bases.back().ChildFunctions.emplace_back();
-  I.Bases.back().ChildFunctions.back().Name = "InheritedFunctionOne";
+  I.Bases.back().Children.Functions.emplace_back();
+  I.Bases.back().Children.Functions.back().Name = "InheritedFunctionOne";
   I.Bases.back().Members.emplace_back(TypeInfo("int", "path/to/int"), "N",
                                       AccessSpecifier::AS_private);
   // F is in the global namespace
@@ -109,12 +110,12 @@
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,
                                 "path/to/G");
 
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
-                              "path/to/A/r");
-  I.ChildFunctions.emplace_back();
-  I.ChildFunctions.back().Name = "OneFunction";
-  I.ChildEnums.emplace_back();
-  I.ChildEnums.back().Name = "OneEnum";
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                                  "path/to/A/r");
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getYAMLGenerator();
   assert(G);
@@ -330,6 +331,30 @@
   EXPECT_EQ(Expected, Actual.str());
 }
 
+TEST(YAMLGeneratorTest, enumTypedefYAML) {
+  TypedefInfo I;
+  I.Name = "MyUsing";
+  I.Underlying = TypeInfo("int");
+  I.IsUsing = true;
+
+  auto G = getYAMLGenerator();
+  assert(G);
+  std::string Buffer;
+  llvm::raw_string_ostream Actual(Buffer);
+  auto Err = G->generateDocForInfo(&I, Actual, ClangDocContext());
+  assert(!Err);
+  std::string Expected =
+      R"raw(---
+USR:             '0000000000000000000000000000000000000000'
+Name:            'MyUsing'
+Underlying:
+  Name:            'int'
+IsUsing:         true
+...
+)raw";
+  EXPECT_EQ(Expected, Actual.str());
+}
+
 TEST(YAMLGeneratorTest, emitCommentYAML) {
   FunctionInfo I;
   I.Name = "f";
Index: clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
+++ clang-tools-extra/unittests/clang-doc/SerializeTest.cpp
@@ -59,6 +59,10 @@
   bool VisitRecordDecl(const RecordDecl *D) { return mapDecl(D); }
 
   bool VisitEnumDecl(const EnumDecl *D) { return mapDecl(D); }
+
+  bool VisitTypedefDecl(const TypedefDecl *D) { return mapDecl(D); }
+
+  bool VisitTypeAliasDecl(const TypeAliasDecl *D) { return mapDecl(D); }
 };
 
 void ExtractInfosFromCode(StringRef Code, size_t NumExpectedInfos, bool Public,
@@ -124,7 +128,7 @@
   F.Namespace.emplace_back(EmptySID, "B", InfoType::IT_namespace);
   F.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
   F.Access = AccessSpecifier::AS_none;
-  ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F));
+  ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 }
 
@@ -183,7 +187,7 @@
                                       InfoType::IT_namespace);
   EConstructor.Access = AccessSpecifier::AS_public;
   EConstructor.IsMethod = true;
-  ExpectedRecordWithEConstructor.ChildFunctions.emplace_back(
+  ExpectedRecordWithEConstructor.Children.Functions.emplace_back(
       std::move(EConstructor));
   CheckRecordInfo(&ExpectedRecordWithEConstructor, RecordWithEConstructor);
 
@@ -199,7 +203,7 @@
                                 InfoType::IT_namespace);
   Method.Access = AccessSpecifier::AS_protected;
   Method.IsMethod = true;
-  ExpectedRecordWithMethod.ChildFunctions.emplace_back(std::move(Method));
+  ExpectedRecordWithMethod.Children.Functions.emplace_back(std::move(Method));
   CheckRecordInfo(&ExpectedRecordWithMethod, RecordWithMethod);
 
   RecordInfo *F = InfoAsRecord(Infos[4].get());
@@ -222,7 +226,7 @@
                                         InfoType::IT_namespace);
   TemplateMethod.Access = AccessSpecifier::AS_public;
   TemplateMethod.IsMethod = true;
-  ExpectedRecordWithTemplateMethod.ChildFunctions.emplace_back(
+  ExpectedRecordWithTemplateMethod.Children.Functions.emplace_back(
       std::move(TemplateMethod));
   CheckRecordInfo(&ExpectedRecordWithTemplateMethod, RecordWithTemplateMethod);
 
@@ -241,7 +245,7 @@
                                                    InfoType::IT_namespace);
   SpecializedTemplateMethod.Access = AccessSpecifier::AS_public;
   SpecializedTemplateMethod.IsMethod = true;
-  ExpectedTemplatedRecord.ChildFunctions.emplace_back(
+  ExpectedTemplatedRecord.Children.Functions.emplace_back(
       std::move(SpecializedTemplateMethod));
   CheckRecordInfo(&ExpectedTemplatedRecord, TemplatedRecord);
 
@@ -268,7 +272,7 @@
   E.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   E.Members.emplace_back("X", "0");
   E.Members.emplace_back("Y", "1");
-  ExpectedNamespaceWithEnum.ChildEnums.emplace_back(std::move(E));
+  ExpectedNamespaceWithEnum.Children.Enums.emplace_back(std::move(E));
   CheckNamespaceInfo(&ExpectedNamespaceWithEnum, NamespaceWithEnum);
 
   NamespaceInfo *NamespaceWithScopedEnum = InfoAsNamespace(Infos[1].get());
@@ -279,7 +283,7 @@
   G.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   G.Members.emplace_back("A", "0");
   G.Members.emplace_back("B", "1");
-  ExpectedNamespaceWithScopedEnum.ChildEnums.emplace_back(std::move(G));
+  ExpectedNamespaceWithScopedEnum.Children.Enums.emplace_back(std::move(G));
   CheckNamespaceInfo(&ExpectedNamespaceWithScopedEnum, NamespaceWithScopedEnum);
 }
 
@@ -352,7 +356,7 @@
   F.ReturnType = TypeInfo("int");
   F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   F.Access = AccessSpecifier::AS_none;
-  ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F));
+  ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 }
 
@@ -368,7 +372,7 @@
   F.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   F.Params.emplace_back(TypeInfo("int"), "I");
   F.Access = AccessSpecifier::AS_none;
-  ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F));
+  ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 }
 
@@ -422,7 +426,8 @@
                                      InfoType::IT_namespace);
   FunctionSet.Access = AccessSpecifier::AS_protected;
   FunctionSet.IsMethod = true;
-  ExpectedE.Bases.back().ChildFunctions.emplace_back(std::move(FunctionSet));
+  ExpectedE.Bases.back().Children.Functions.emplace_back(
+      std::move(FunctionSet));
   ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"G",
                                /*Path=*/"GlobalNamespace", true,
                                AccessSpecifier::AS_private, true);
@@ -435,7 +440,8 @@
                                      InfoType::IT_namespace);
   FunctionGet.Access = AccessSpecifier::AS_private;
   FunctionGet.IsMethod = true;
-  ExpectedE.Bases.back().ChildFunctions.emplace_back(std::move(FunctionGet));
+  ExpectedE.Bases.back().Children.Functions.emplace_back(
+      std::move(FunctionGet));
   ExpectedE.Bases.back().Members.emplace_back(TypeInfo("int"), "I",
                                               AccessSpecifier::AS_private);
   ExpectedE.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
@@ -468,7 +474,8 @@
                                         InfoType::IT_namespace);
   FunctionSetNew.Access = AccessSpecifier::AS_private;
   FunctionSetNew.IsMethod = true;
-  ExpectedH.Bases.back().ChildFunctions.emplace_back(std::move(FunctionSetNew));
+  ExpectedH.Bases.back().Children.Functions.emplace_back(
+      std::move(FunctionSetNew));
   ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"G",
                                /*Path=*/"GlobalNamespace", true,
                                AccessSpecifier::AS_private, false);
@@ -481,7 +488,8 @@
                                         InfoType::IT_namespace);
   FunctionGetNew.Access = AccessSpecifier::AS_private;
   FunctionGetNew.IsMethod = true;
-  ExpectedH.Bases.back().ChildFunctions.emplace_back(std::move(FunctionGetNew));
+  ExpectedH.Bases.back().Children.Functions.emplace_back(
+      std::move(FunctionGetNew));
   ExpectedH.Bases.back().Members.emplace_back(TypeInfo("int"), "I",
                                               AccessSpecifier::AS_private);
   CheckRecordInfo(&ExpectedH, H);
@@ -528,7 +536,7 @@
   F.Params.emplace_back(TypeInfo("double"), "d");
   F.Params.back().DefaultValue = "3.2 - 1.0";
   F.Access = AccessSpecifier::AS_none;
-  ExpectedBWithFunction.ChildFunctions.emplace_back(std::move(F));
+  ExpectedBWithFunction.Children.Functions.emplace_back(std::move(F));
   CheckNamespaceInfo(&ExpectedBWithFunction, BWithFunction);
 
   NamespaceInfo *BWithExportedFunction = InfoAsNamespace(Infos[1].get());
@@ -540,7 +548,7 @@
   ExportedF.Loc.emplace_back(0, llvm::SmallString<16>{"test.cpp"});
   ExportedF.Params.emplace_back(TypeInfo("double"), "y");
   ExportedF.Access = AccessSpecifier::AS_none;
-  ExpectedBWithExportedFunction.ChildFunctions.emplace_back(
+  ExpectedBWithExportedFunction.Children.Functions.emplace_back(
       std::move(ExportedF));
   CheckNamespaceInfo(&ExpectedBWithExportedFunction, BWithExportedFunction);
 }
@@ -553,22 +561,22 @@
 
   NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
   NamespaceInfo ExpectedParentA(EmptySID);
-  ExpectedParentA.ChildRecords.emplace_back(EmptySID, "A", InfoType::IT_record,
-                                            "GlobalNamespace");
+  ExpectedParentA.Children.Records.emplace_back(
+      EmptySID, "A", InfoType::IT_record, "GlobalNamespace");
   CheckNamespaceInfo(&ExpectedParentA, ParentA);
 
   RecordInfo *ParentB = InfoAsRecord(Infos[3].get());
   RecordInfo ExpectedParentB(EmptySID);
   llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A");
   llvm::sys::path::native(ExpectedParentBPath);
-  ExpectedParentB.ChildRecords.emplace_back(EmptySID, "B", InfoType::IT_record,
-                                            ExpectedParentBPath);
+  ExpectedParentB.Children.Records.emplace_back(
+      EmptySID, "B", InfoType::IT_record, ExpectedParentBPath);
   CheckRecordInfo(&ExpectedParentB, ParentB);
 
   NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());
   NamespaceInfo ExpectedParentC(EmptySID);
-  ExpectedParentC.ChildRecords.emplace_back(EmptySID, "C", InfoType::IT_record,
-                                            "@nonymous_namespace");
+  ExpectedParentC.Children.Records.emplace_back(
+      EmptySID, "C", InfoType::IT_record, "@nonymous_namespace");
   CheckNamespaceInfo(&ExpectedParentC, ParentC);
 }
 
@@ -580,16 +588,43 @@
 
   NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
   NamespaceInfo ExpectedParentA(EmptySID);
-  ExpectedParentA.ChildNamespaces.emplace_back(EmptySID, "A",
-                                               InfoType::IT_namespace);
+  ExpectedParentA.Children.Namespaces.emplace_back(EmptySID, "A",
+                                                   InfoType::IT_namespace);
   CheckNamespaceInfo(&ExpectedParentA, ParentA);
 
   NamespaceInfo *ParentB = InfoAsNamespace(Infos[3].get());
   NamespaceInfo ExpectedParentB(EmptySID);
-  ExpectedParentB.ChildNamespaces.emplace_back(EmptySID, "B",
-                                               InfoType::IT_namespace, "A");
+  ExpectedParentB.Children.Namespaces.emplace_back(EmptySID, "B",
+                                                   InfoType::IT_namespace, "A");
   CheckNamespaceInfo(&ExpectedParentB, ParentB);
 }
 
+TEST(SerializeTests, emitTypedefs) {
+  EmittedInfoList Infos;
+  ExtractInfosFromCode("typedef int MyInt; using MyDouble = double;", 2,
+                       /*Public=*/false, Infos);
+
+  // First info will be the global namespace with the typedef in it.
+  NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());
+  ASSERT_EQ(1u, GlobalNS1->Children.Typedefs.size());
+
+  const TypedefInfo &FirstTD = GlobalNS1->Children.Typedefs[0];
+  EXPECT_EQ("MyInt", FirstTD.Name);
+  EXPECT_FALSE(FirstTD.IsUsing);
+  EXPECT_EQ("int", FirstTD.Underlying.Type.Name);
+
+  // The second will be another global namespace with the using in it (the
+  // global namespace is duplicated because the items haven't been merged at the
+  // serialization phase of processing).
+  NamespaceInfo *GlobalNS2 = InfoAsNamespace(Infos[1].get());
+  ASSERT_EQ(1u, GlobalNS2->Children.Typedefs.size());
+
+  // Second is the "using" typedef.
+  const TypedefInfo &SecondTD = GlobalNS2->Children.Typedefs[0];
+  EXPECT_EQ("MyDouble", SecondTD.Name);
+  EXPECT_TRUE(SecondTD.IsUsing);
+  EXPECT_EQ("double", SecondTD.Underlying.Type.Name);
+}
+
 } // namespace doc
 } // end namespace clang
Index: clang-tools-extra/unittests/clang-doc/MergeTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-doc/MergeTest.cpp
+++ clang-tools-extra/unittests/clang-doc/MergeTest.cpp
@@ -18,29 +18,29 @@
   One.Name = "Namespace";
   One.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  One.ChildNamespaces.emplace_back(NonEmptySID, "ChildNamespace",
-                                   InfoType::IT_namespace);
-  One.ChildRecords.emplace_back(NonEmptySID, "ChildStruct",
-                                InfoType::IT_record);
-  One.ChildFunctions.emplace_back();
-  One.ChildFunctions.back().Name = "OneFunction";
-  One.ChildFunctions.back().USR = NonEmptySID;
-  One.ChildEnums.emplace_back();
-  One.ChildEnums.back().Name = "OneEnum";
-  One.ChildEnums.back().USR = NonEmptySID;
+  One.Children.Namespaces.emplace_back(NonEmptySID, "ChildNamespace",
+                                       InfoType::IT_namespace);
+  One.Children.Records.emplace_back(NonEmptySID, "ChildStruct",
+                                    InfoType::IT_record);
+  One.Children.Functions.emplace_back();
+  One.Children.Functions.back().Name = "OneFunction";
+  One.Children.Functions.back().USR = NonEmptySID;
+  One.Children.Enums.emplace_back();
+  One.Children.Enums.back().Name = "OneEnum";
+  One.Children.Enums.back().USR = NonEmptySID;
 
   NamespaceInfo Two;
   Two.Name = "Namespace";
   Two.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  Two.ChildNamespaces.emplace_back(EmptySID, "OtherChildNamespace",
-                                   InfoType::IT_namespace);
-  Two.ChildRecords.emplace_back(EmptySID, "OtherChildStruct",
-                                InfoType::IT_record);
-  Two.ChildFunctions.emplace_back();
-  Two.ChildFunctions.back().Name = "TwoFunction";
-  Two.ChildEnums.emplace_back();
-  Two.ChildEnums.back().Name = "TwoEnum";
+  Two.Children.Namespaces.emplace_back(EmptySID, "OtherChildNamespace",
+                                       InfoType::IT_namespace);
+  Two.Children.Records.emplace_back(EmptySID, "OtherChildStruct",
+                                    InfoType::IT_record);
+  Two.Children.Functions.emplace_back();
+  Two.Children.Functions.back().Name = "TwoFunction";
+  Two.Children.Enums.emplace_back();
+  Two.Children.Enums.back().Name = "TwoEnum";
 
   std::vector<std::unique_ptr<Info>> Infos;
   Infos.emplace_back(std::make_unique<NamespaceInfo>(std::move(One)));
@@ -50,24 +50,24 @@
   Expected->Name = "Namespace";
   Expected->Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  Expected->ChildNamespaces.emplace_back(NonEmptySID, "ChildNamespace",
-                                         InfoType::IT_namespace);
-  Expected->ChildRecords.emplace_back(NonEmptySID, "ChildStruct",
-                                      InfoType::IT_record);
-  Expected->ChildNamespaces.emplace_back(EmptySID, "OtherChildNamespace",
-                                         InfoType::IT_namespace);
-  Expected->ChildRecords.emplace_back(EmptySID, "OtherChildStruct",
-                                      InfoType::IT_record);
-  Expected->ChildFunctions.emplace_back();
-  Expected->ChildFunctions.back().Name = "OneFunction";
-  Expected->ChildFunctions.back().USR = NonEmptySID;
-  Expected->ChildFunctions.emplace_back();
-  Expected->ChildFunctions.back().Name = "TwoFunction";
-  Expected->ChildEnums.emplace_back();
-  Expected->ChildEnums.back().Name = "OneEnum";
-  Expected->ChildEnums.back().USR = NonEmptySID;
-  Expected->ChildEnums.emplace_back();
-  Expected->ChildEnums.back().Name = "TwoEnum";
+  Expected->Children.Namespaces.emplace_back(NonEmptySID, "ChildNamespace",
+                                             InfoType::IT_namespace);
+  Expected->Children.Records.emplace_back(NonEmptySID, "ChildStruct",
+                                          InfoType::IT_record);
+  Expected->Children.Namespaces.emplace_back(EmptySID, "OtherChildNamespace",
+                                             InfoType::IT_namespace);
+  Expected->Children.Records.emplace_back(EmptySID, "OtherChildStruct",
+                                          InfoType::IT_record);
+  Expected->Children.Functions.emplace_back();
+  Expected->Children.Functions.back().Name = "OneFunction";
+  Expected->Children.Functions.back().USR = NonEmptySID;
+  Expected->Children.Functions.emplace_back();
+  Expected->Children.Functions.back().Name = "TwoFunction";
+  Expected->Children.Enums.emplace_back();
+  Expected->Children.Enums.back().Name = "OneEnum";
+  Expected->Children.Enums.back().USR = NonEmptySID;
+  Expected->Children.Enums.emplace_back();
+  Expected->Children.Enums.back().Name = "TwoEnum";
 
   auto Actual = mergeInfos(Infos);
   assert(Actual);
@@ -90,14 +90,14 @@
 
   One.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
                          AccessSpecifier::AS_protected, true);
-  One.ChildRecords.emplace_back(NonEmptySID, "SharedChildStruct",
-                                InfoType::IT_record);
-  One.ChildFunctions.emplace_back();
-  One.ChildFunctions.back().Name = "OneFunction";
-  One.ChildFunctions.back().USR = NonEmptySID;
-  One.ChildEnums.emplace_back();
-  One.ChildEnums.back().Name = "OneEnum";
-  One.ChildEnums.back().USR = NonEmptySID;
+  One.Children.Records.emplace_back(NonEmptySID, "SharedChildStruct",
+                                    InfoType::IT_record);
+  One.Children.Functions.emplace_back();
+  One.Children.Functions.back().Name = "OneFunction";
+  One.Children.Functions.back().USR = NonEmptySID;
+  One.Children.Enums.emplace_back();
+  One.Children.Enums.back().Name = "OneEnum";
+  One.Children.Enums.back().USR = NonEmptySID;
 
   RecordInfo Two;
   Two.Name = "r";
@@ -107,12 +107,12 @@
 
   Two.TagType = TagTypeKind::TTK_Class;
 
-  Two.ChildRecords.emplace_back(NonEmptySID, "SharedChildStruct",
-                                InfoType::IT_record, "path");
-  Two.ChildFunctions.emplace_back();
-  Two.ChildFunctions.back().Name = "TwoFunction";
-  Two.ChildEnums.emplace_back();
-  Two.ChildEnums.back().Name = "TwoEnum";
+  Two.Children.Records.emplace_back(NonEmptySID, "SharedChildStruct",
+                                    InfoType::IT_record, "path");
+  Two.Children.Functions.emplace_back();
+  Two.Children.Functions.back().Name = "TwoFunction";
+  Two.Children.Enums.emplace_back();
+  Two.Children.Enums.back().Name = "TwoEnum";
 
   std::vector<std::unique_ptr<Info>> Infos;
   Infos.emplace_back(std::make_unique<RecordInfo>(std::move(One)));
@@ -134,18 +134,18 @@
   Expected->Bases.emplace_back(EmptySID, "F", "path/to/F", true,
                                AccessSpecifier::AS_protected, true);
 
-  Expected->ChildRecords.emplace_back(NonEmptySID, "SharedChildStruct",
-                                      InfoType::IT_record, "path");
-  Expected->ChildFunctions.emplace_back();
-  Expected->ChildFunctions.back().Name = "OneFunction";
-  Expected->ChildFunctions.back().USR = NonEmptySID;
-  Expected->ChildFunctions.emplace_back();
-  Expected->ChildFunctions.back().Name = "TwoFunction";
-  Expected->ChildEnums.emplace_back();
-  Expected->ChildEnums.back().Name = "OneEnum";
-  Expected->ChildEnums.back().USR = NonEmptySID;
-  Expected->ChildEnums.emplace_back();
-  Expected->ChildEnums.back().Name = "TwoEnum";
+  Expected->Children.Records.emplace_back(NonEmptySID, "SharedChildStruct",
+                                          InfoType::IT_record, "path");
+  Expected->Children.Functions.emplace_back();
+  Expected->Children.Functions.back().Name = "OneFunction";
+  Expected->Children.Functions.back().USR = NonEmptySID;
+  Expected->Children.Functions.emplace_back();
+  Expected->Children.Functions.back().Name = "TwoFunction";
+  Expected->Children.Enums.emplace_back();
+  Expected->Children.Enums.back().Name = "OneEnum";
+  Expected->Children.Enums.back().USR = NonEmptySID;
+  Expected->Children.Enums.emplace_back();
+  Expected->Children.Enums.back().Name = "TwoEnum";
 
   auto Actual = mergeInfos(Infos);
   assert(Actual);
Index: clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
+++ clang-tools-extra/unittests/clang-doc/MDGeneratorTest.cpp
@@ -26,14 +26,14 @@
   I.Name = "Namespace";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
-                                 InfoType::IT_namespace);
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
-  I.ChildFunctions.emplace_back();
-  I.ChildFunctions.back().Name = "OneFunction";
-  I.ChildFunctions.back().Access = AccessSpecifier::AS_none;
-  I.ChildEnums.emplace_back();
-  I.ChildEnums.back().Name = "OneEnum";
+  I.Children.Namespaces.emplace_back(EmptySID, "ChildNamespace",
+                                     InfoType::IT_namespace);
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Functions.back().Access = AccessSpecifier::AS_none;
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getMDGenerator();
   assert(G);
@@ -90,11 +90,11 @@
   I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
 
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
-  I.ChildFunctions.emplace_back();
-  I.ChildFunctions.back().Name = "OneFunction";
-  I.ChildEnums.emplace_back();
-  I.ChildEnums.back().Name = "OneEnum";
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getMDGenerator();
   assert(G);
Index: clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
+++ clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.cpp
@@ -43,15 +43,15 @@
   I.Name = "Namespace";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
-                                 InfoType::IT_namespace, "Namespace");
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
-                              "Namespace");
-  I.ChildFunctions.emplace_back();
-  I.ChildFunctions.back().Access = AccessSpecifier::AS_none;
-  I.ChildFunctions.back().Name = "OneFunction";
-  I.ChildEnums.emplace_back();
-  I.ChildEnums.back().Name = "OneEnum";
+  I.Children.Namespaces.emplace_back(EmptySID, "ChildNamespace",
+                                     InfoType::IT_namespace, "Namespace");
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                                  "Namespace");
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Access = AccessSpecifier::AS_none;
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getHTMLGenerator();
   assert(G);
@@ -158,12 +158,12 @@
   I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, PathTo);
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
 
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
-                              "X/Y/Z/r");
-  I.ChildFunctions.emplace_back();
-  I.ChildFunctions.back().Name = "OneFunction";
-  I.ChildEnums.emplace_back();
-  I.ChildEnums.back().Name = "OneEnum";
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                                  "X/Y/Z/r");
+  I.Children.Functions.emplace_back();
+  I.Children.Functions.back().Name = "OneFunction";
+  I.Children.Enums.emplace_back();
+  I.Children.Enums.back().Name = "OneEnum";
 
   auto G = getHTMLGenerator();
   assert(G);
Index: clang-tools-extra/unittests/clang-doc/ClangDocTest.h
===================================================================
--- clang-tools-extra/unittests/clang-doc/ClangDocTest.h
+++ clang-tools-extra/unittests/clang-doc/ClangDocTest.h
@@ -27,6 +27,7 @@
 RecordInfo *InfoAsRecord(Info *I);
 FunctionInfo *InfoAsFunction(Info *I);
 EnumInfo *InfoAsEnum(Info *I);
+TypedefInfo *InfoAsTypedef(Info *I);
 
 // Unlike the operator==, these functions explicitly does not check USRs, as
 // that may change and it would be better to not rely on its implementation.
@@ -41,6 +42,7 @@
 void CheckSymbolInfo(SymbolInfo *Expected, SymbolInfo *Actual);
 void CheckFunctionInfo(FunctionInfo *Expected, FunctionInfo *Actual);
 void CheckEnumInfo(EnumInfo *Expected, EnumInfo *Actual);
+void CheckTypedefInfo(TypedefInfo *Expected, TypedefInfo *Actual);
 void CheckNamespaceInfo(NamespaceInfo *Expected, NamespaceInfo *Actual);
 void CheckRecordInfo(RecordInfo *Expected, RecordInfo *Actual);
 void CheckBaseRecordInfo(BaseRecordInfo *Expected, BaseRecordInfo *Actual);
Index: clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
+++ clang-tools-extra/unittests/clang-doc/ClangDocTest.cpp
@@ -34,6 +34,11 @@
   return static_cast<EnumInfo *>(I);
 }
 
+TypedefInfo *InfoAsTypedef(Info *I) {
+  assert(I->IT == InfoType::IT_typedef);
+  return static_cast<TypedefInfo *>(I);
+}
+
 void CheckCommentInfo(const std::vector<CommentInfo> &Expected,
                       const std::vector<CommentInfo> &Actual);
 void CheckCommentInfo(const std::vector<std::unique_ptr<CommentInfo>> &Expected,
@@ -144,26 +149,35 @@
     EXPECT_EQ(Expected->Members[Idx], Actual->Members[Idx]);
 }
 
+void CheckTypedefInfo(TypedefInfo *Expected, TypedefInfo *Actual) {
+  CheckSymbolInfo(Expected, Actual);
+  EXPECT_EQ(Expected->IsUsing, Actual->IsUsing);
+  CheckTypeInfo(&Expected->Underlying, &Actual->Underlying);
+}
+
 void CheckNamespaceInfo(NamespaceInfo *Expected, NamespaceInfo *Actual) {
   CheckBaseInfo(Expected, Actual);
 
-  ASSERT_EQ(Expected->ChildNamespaces.size(), Actual->ChildNamespaces.size());
-  for (size_t Idx = 0; Idx < Actual->ChildNamespaces.size(); ++Idx)
-    CheckReference(Expected->ChildNamespaces[Idx],
-                   Actual->ChildNamespaces[Idx]);
+  ASSERT_EQ(Expected->Children.Namespaces.size(),
+            Actual->Children.Namespaces.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Namespaces.size(); ++Idx)
+    CheckReference(Expected->Children.Namespaces[Idx],
+                   Actual->Children.Namespaces[Idx]);
 
-  ASSERT_EQ(Expected->ChildRecords.size(), Actual->ChildRecords.size());
-  for (size_t Idx = 0; Idx < Actual->ChildRecords.size(); ++Idx)
-    CheckReference(Expected->ChildRecords[Idx], Actual->ChildRecords[Idx]);
+  ASSERT_EQ(Expected->Children.Records.size(), Actual->Children.Records.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Records.size(); ++Idx)
+    CheckReference(Expected->Children.Records[Idx],
+                   Actual->Children.Records[Idx]);
 
-  ASSERT_EQ(Expected->ChildFunctions.size(), Actual->ChildFunctions.size());
-  for (size_t Idx = 0; Idx < Actual->ChildFunctions.size(); ++Idx)
-    CheckFunctionInfo(&Expected->ChildFunctions[Idx],
-                      &Actual->ChildFunctions[Idx]);
+  ASSERT_EQ(Expected->Children.Functions.size(),
+            Actual->Children.Functions.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Functions.size(); ++Idx)
+    CheckFunctionInfo(&Expected->Children.Functions[Idx],
+                      &Actual->Children.Functions[Idx]);
 
-  ASSERT_EQ(Expected->ChildEnums.size(), Actual->ChildEnums.size());
-  for (size_t Idx = 0; Idx < Actual->ChildEnums.size(); ++Idx)
-    CheckEnumInfo(&Expected->ChildEnums[Idx], &Actual->ChildEnums[Idx]);
+  ASSERT_EQ(Expected->Children.Enums.size(), Actual->Children.Enums.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Enums.size(); ++Idx)
+    CheckEnumInfo(&Expected->Children.Enums[Idx], &Actual->Children.Enums[Idx]);
 }
 
 void CheckRecordInfo(RecordInfo *Expected, RecordInfo *Actual) {
@@ -189,18 +203,20 @@
   for (size_t Idx = 0; Idx < Actual->Bases.size(); ++Idx)
     CheckBaseRecordInfo(&Expected->Bases[Idx], &Actual->Bases[Idx]);
 
-  ASSERT_EQ(Expected->ChildRecords.size(), Actual->ChildRecords.size());
-  for (size_t Idx = 0; Idx < Actual->ChildRecords.size(); ++Idx)
-    CheckReference(Expected->ChildRecords[Idx], Actual->ChildRecords[Idx]);
+  ASSERT_EQ(Expected->Children.Records.size(), Actual->Children.Records.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Records.size(); ++Idx)
+    CheckReference(Expected->Children.Records[Idx],
+                   Actual->Children.Records[Idx]);
 
-  ASSERT_EQ(Expected->ChildFunctions.size(), Actual->ChildFunctions.size());
-  for (size_t Idx = 0; Idx < Actual->ChildFunctions.size(); ++Idx)
-    CheckFunctionInfo(&Expected->ChildFunctions[Idx],
-                      &Actual->ChildFunctions[Idx]);
+  ASSERT_EQ(Expected->Children.Functions.size(),
+            Actual->Children.Functions.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Functions.size(); ++Idx)
+    CheckFunctionInfo(&Expected->Children.Functions[Idx],
+                      &Actual->Children.Functions[Idx]);
 
-  ASSERT_EQ(Expected->ChildEnums.size(), Actual->ChildEnums.size());
-  for (size_t Idx = 0; Idx < Actual->ChildEnums.size(); ++Idx)
-    CheckEnumInfo(&Expected->ChildEnums[Idx], &Actual->ChildEnums[Idx]);
+  ASSERT_EQ(Expected->Children.Enums.size(), Actual->Children.Enums.size());
+  for (size_t Idx = 0; Idx < Actual->Children.Enums.size(); ++Idx)
+    CheckEnumInfo(&Expected->Children.Enums[Idx], &Actual->Children.Enums[Idx]);
 }
 
 void CheckBaseRecordInfo(BaseRecordInfo *Expected, BaseRecordInfo *Actual) {
Index: clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
+++ clang-tools-extra/unittests/clang-doc/BitcodeTest.cpp
@@ -35,6 +35,8 @@
     return writeInfo(*static_cast<EnumInfo *>(I));
   case InfoType::IT_function:
     return writeInfo(*static_cast<FunctionInfo *>(I));
+  case InfoType::IT_typedef:
+    return writeInfo(*static_cast<TypedefInfo *>(I));
   default:
     return "";
   }
@@ -57,11 +59,11 @@
   I.Name = "r";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  I.ChildNamespaces.emplace_back(EmptySID, "ChildNamespace",
-                                 InfoType::IT_namespace);
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
-  I.ChildFunctions.emplace_back();
-  I.ChildEnums.emplace_back();
+  I.Children.Namespaces.emplace_back(EmptySID, "ChildNamespace",
+                                     InfoType::IT_namespace);
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+  I.Children.Functions.emplace_back();
+  I.Children.Enums.emplace_back();
 
   std::string WriteResult = writeInfo(&I);
   EXPECT_TRUE(WriteResult.size() > 0);
@@ -83,7 +85,7 @@
   I.IsTypeDef = true;
   I.Bases.emplace_back(EmptySID, "F", "path/to/F", true,
                        AccessSpecifier::AS_public, true);
-  I.Bases.back().ChildFunctions.emplace_back();
+  I.Bases.back().Children.Functions.emplace_back();
   I.Bases.back().Members.emplace_back(TypeInfo("int"), "X",
                                       AccessSpecifier::AS_private);
   I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record);
@@ -101,9 +103,9 @@
   Brief->Children.back()->Text = "Value of the thing.";
   I.Bases.back().Members.back().Description.emplace_back(std::move(TopComment));
 
-  I.ChildRecords.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
-  I.ChildFunctions.emplace_back();
-  I.ChildEnums.emplace_back();
+  I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record);
+  I.Children.Functions.emplace_back();
+  I.Children.Enums.emplace_back();
 
   std::string WriteResult = writeInfo(&I);
   EXPECT_TRUE(WriteResult.size() > 0);
@@ -172,6 +174,22 @@
   CheckEnumInfo(&I, InfoAsEnum(ReadResults[0].get()));
 }
 
+TEST(BitcodeTest, emitTypedefInfoBitcode) {
+  TypedefInfo I;
+  I.Name = "MyInt";
+  I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
+
+  I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
+  I.Underlying = TypeInfo("unsigned");
+  I.IsUsing = true;
+
+  std::string WriteResult = writeInfo(&I);
+  EXPECT_TRUE(WriteResult.size() > 0);
+  std::vector<std::unique_ptr<Info>> ReadResults = readInfo(WriteResult, 1);
+
+  CheckTypedefInfo(&I, InfoAsTypedef(ReadResults[0].get()));
+}
+
 TEST(SerializeTest, emitInfoWithCommentBitcode) {
   FunctionInfo F;
   F.Name = "F";
Index: clang-tools-extra/clang-doc/YAMLGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -23,6 +23,7 @@
 LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(EnumValueInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(TypedefInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::SmallString<16>)
@@ -137,9 +138,10 @@
   IO.mapOptional("Parents", I.Parents, llvm::SmallVector<Reference, 4>());
   IO.mapOptional("VirtualParents", I.VirtualParents,
                  llvm::SmallVector<Reference, 4>());
-  IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>());
-  IO.mapOptional("ChildFunctions", I.ChildFunctions);
-  IO.mapOptional("ChildEnums", I.ChildEnums);
+  IO.mapOptional("ChildRecords", I.Children.Records, std::vector<Reference>());
+  IO.mapOptional("ChildFunctions", I.Children.Functions);
+  IO.mapOptional("ChildEnums", I.Children.Enums);
+  IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
 }
 
 static void CommentInfoMapping(IO &IO, CommentInfo &I) {
@@ -203,11 +205,13 @@
 template <> struct MappingTraits<NamespaceInfo> {
   static void mapping(IO &IO, NamespaceInfo &I) {
     InfoMapping(IO, I);
-    IO.mapOptional("ChildNamespaces", I.ChildNamespaces,
+    IO.mapOptional("ChildNamespaces", I.Children.Namespaces,
                    std::vector<Reference>());
-    IO.mapOptional("ChildRecords", I.ChildRecords, std::vector<Reference>());
-    IO.mapOptional("ChildFunctions", I.ChildFunctions);
-    IO.mapOptional("ChildEnums", I.ChildEnums);
+    IO.mapOptional("ChildRecords", I.Children.Records,
+                   std::vector<Reference>());
+    IO.mapOptional("ChildFunctions", I.Children.Functions);
+    IO.mapOptional("ChildEnums", I.Children.Enums);
+    IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
   }
 };
 
@@ -244,6 +248,14 @@
   }
 };
 
+template <> struct MappingTraits<TypedefInfo> {
+  static void mapping(IO &IO, TypedefInfo &I) {
+    SymbolInfoMapping(IO, I);
+    IO.mapOptional("Underlying", I.Underlying.Type);
+    IO.mapOptional("IsUsing", I.IsUsing, false);
+  }
+};
+
 template <> struct MappingTraits<FunctionInfo> {
   static void mapping(IO &IO, FunctionInfo &I) {
     SymbolInfoMapping(IO, I);
@@ -302,6 +314,9 @@
   case InfoType::IT_function:
     InfoYAML << *static_cast<clang::doc::FunctionInfo *>(I);
     break;
+  case InfoType::IT_typedef:
+    InfoYAML << *static_cast<clang::doc::TypedefInfo *>(I);
+    break;
   case InfoType::IT_default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "unexpected InfoType");
Index: clang-tools-extra/clang-doc/Serialize.h
===================================================================
--- clang-tools-extra/clang-doc/Serialize.h
+++ clang-tools-extra/clang-doc/Serialize.h
@@ -39,19 +39,31 @@
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 emitInfo(const NamespaceDecl *D, const FullComment *FC, int LineNumber,
          StringRef File, bool IsFileInRootDir, bool PublicOnly);
+
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 emitInfo(const RecordDecl *D, const FullComment *FC, int LineNumber,
          StringRef File, bool IsFileInRootDir, bool PublicOnly);
+
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 emitInfo(const EnumDecl *D, const FullComment *FC, int LineNumber,
          StringRef File, bool IsFileInRootDir, bool PublicOnly);
+
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 emitInfo(const FunctionDecl *D, const FullComment *FC, int LineNumber,
          StringRef File, bool IsFileInRootDir, bool PublicOnly);
+
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
 emitInfo(const CXXMethodDecl *D, const FullComment *FC, int LineNumber,
          StringRef File, bool IsFileInRootDir, bool PublicOnly);
 
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber,
+         StringRef File, bool IsFileInRootDir, bool PublicOnly);
+
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber,
+         StringRef File, bool IsFileInRootDir, bool PublicOnly);
+
 // 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
Index: clang-tools-extra/clang-doc/Serialize.cpp
===================================================================
--- clang-tools-extra/clang-doc/Serialize.cpp
+++ clang-tools-extra/clang-doc/Serialize.cpp
@@ -273,6 +273,75 @@
           isPublic(D->getAccessUnsafe(), D->getLinkageInternal()));
 }
 
+// The InsertChild functions insert the given info into the given scope using
+// the method appropriate for that type. Some types are moved into the
+// appropriate vector, while other types have Reference objects generated to
+// refer to them.
+//
+// See MakeAndInsertIntoParent().
+static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
+  Scope.Namespaces.emplace_back(Info.USR, Info.Name, InfoType::IT_namespace,
+                                getInfoRelativePath(Info.Namespace));
+}
+
+static void InsertChild(ScopeChildren &Scope, const RecordInfo &Info) {
+  Scope.Records.emplace_back(Info.USR, Info.Name, InfoType::IT_record,
+                             getInfoRelativePath(Info.Namespace));
+}
+
+static void InsertChild(ScopeChildren &Scope, EnumInfo Info) {
+  Scope.Enums.push_back(std::move(Info));
+}
+
+static void InsertChild(ScopeChildren &Scope, FunctionInfo Info) {
+  Scope.Functions.push_back(std::move(Info));
+}
+
+static void InsertChild(ScopeChildren &Scope, TypedefInfo Info) {
+  Scope.Typedefs.push_back(std::move(Info));
+}
+
+// Creates a parent of the correct type for the given child and inserts it into
+// that parent.
+//
+// This is complicated by the fact that namespaces and records are inserted by
+// reference (constructing a "Reference" object with that namespace/record's
+// info), while everything else is inserted by moving it directly into the child
+// vectors.
+//
+// For namespaces and records, explicitly specify a const& template parameter
+// when invoking this function:
+//   MakeAndInsertIntoParent<const Record&>(...);
+// Otherwise, specify an rvalue reference <EnumInfo&&> and move into the
+// parameter. Since each variant is used once, it's not worth having a more
+// elaborate system to automatically deduce this information.
+template <typename ChildType>
+std::unique_ptr<Info> MakeAndInsertIntoParent(ChildType Child) {
+  if (Child.Namespace.empty()) {
+    // Insert into unnamed parent namespace.
+    auto ParentNS = std::make_unique<NamespaceInfo>();
+    InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
+    return ParentNS;
+  }
+
+  switch (Child.Namespace[0].RefType) {
+  case InfoType::IT_namespace: {
+    auto ParentNS = std::make_unique<NamespaceInfo>();
+    ParentNS->USR = Child.Namespace[0].USR;
+    InsertChild(ParentNS->Children, std::forward<ChildType>(Child));
+    return ParentNS;
+  }
+  case InfoType::IT_record: {
+    auto ParentRec = std::make_unique<RecordInfo>();
+    ParentRec->USR = Child.Namespace[0].USR;
+    InsertChild(ParentRec->Children, std::forward<ChildType>(Child));
+    return ParentRec;
+  }
+  default:
+    llvm_unreachable("Invalid reference type for parent namespace");
+  }
+}
+
 // There are two uses for this function.
 // 1) Getting the resulting mode of inheritance of a record.
 //    Example: class A {}; class B : private A {}; class C : public B {};
@@ -376,8 +445,8 @@
 static void
 populateParentNamespaces(llvm::SmallVector<Reference, 4> &Namespaces,
                          const T *D, bool &IsInAnonymousNamespace) {
-  const auto *DC = cast<DeclContext>(D);
-  while ((DC = DC->getParent())) {
+  const DeclContext *DC = D->getDeclContext();
+  do {
     if (const auto *N = dyn_cast<NamespaceDecl>(DC)) {
       std::string Namespace;
       if (N->isAnonymousNamespace()) {
@@ -396,7 +465,7 @@
     else if (const auto *N = dyn_cast<EnumDecl>(DC))
       Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
                               InfoType::IT_enum);
-  }
+  } while ((DC = DC->getParent()));
   // The global namespace should be added to the list of namespaces if the decl
   // corresponds to a Record and if it doesn't have any namespace (because this
   // means it's in the global namespace). Also if its outermost namespace is a
@@ -501,7 +570,7 @@
                                  IsInAnonymousNamespace);
             FI.Access =
                 getFinalAccessSpecifier(BI.Access, MD->getAccessUnsafe());
-            BI.ChildFunctions.emplace_back(std::move(FI));
+            BI.Children.Functions.emplace_back(std::move(FI));
           }
         I.Bases.emplace_back(std::move(BI));
         // Call this function recursively to get the inherited classes of
@@ -530,14 +599,9 @@
   if (I->Namespace.empty() && I->USR == SymbolID())
     return {std::unique_ptr<Info>{std::move(I)}, nullptr};
 
-  auto ParentI = std::make_unique<NamespaceInfo>();
-  ParentI->USR = I->Namespace.empty() ? SymbolID() : I->Namespace[0].USR;
-  ParentI->ChildNamespaces.emplace_back(I->USR, I->Name, InfoType::IT_namespace,
-                                        getInfoRelativePath(I->Namespace));
-  if (I->Namespace.empty())
-    ParentI->Path = getInfoRelativePath(ParentI->Namespace);
-  return {std::unique_ptr<Info>{std::move(I)},
-          std::unique_ptr<Info>{std::move(ParentI)}};
+  // Namespaces are inserted into the parent by reference, so we need to return
+  // both the parent and the record itself.
+  return {std::move(I), MakeAndInsertIntoParent<const NamespaceInfo &>(*I)};
 }
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
@@ -563,26 +627,10 @@
   }
   I->Path = getInfoRelativePath(I->Namespace);
 
-  switch (I->Namespace[0].RefType) {
-  case InfoType::IT_namespace: {
-    auto ParentI = std::make_unique<NamespaceInfo>();
-    ParentI->USR = I->Namespace[0].USR;
-    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record,
-                                       getInfoRelativePath(I->Namespace));
-    return {std::unique_ptr<Info>{std::move(I)},
-            std::unique_ptr<Info>{std::move(ParentI)}};
-  }
-  case InfoType::IT_record: {
-    auto ParentI = std::make_unique<RecordInfo>();
-    ParentI->USR = I->Namespace[0].USR;
-    ParentI->ChildRecords.emplace_back(I->USR, I->Name, InfoType::IT_record,
-                                       getInfoRelativePath(I->Namespace));
-    return {std::unique_ptr<Info>{std::move(I)},
-            std::unique_ptr<Info>{std::move(ParentI)}};
-  }
-  default:
-    llvm_unreachable("Invalid reference type for parent namespace");
-  }
+  // Records are inserted into the parent by reference, so we need to return
+  // both the parent and the record itself.
+  auto Parent = MakeAndInsertIntoParent<const RecordInfo &>(*I);
+  return {std::move(I), std::move(Parent)};
 }
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
@@ -596,17 +644,8 @@
   if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
     return {};
 
-  // Wrap in enclosing scope
-  auto ParentI = std::make_unique<NamespaceInfo>();
-  if (!Func.Namespace.empty())
-    ParentI->USR = Func.Namespace[0].USR;
-  else
-    ParentI->USR = SymbolID();
-  if (Func.Namespace.empty())
-    ParentI->Path = getInfoRelativePath(ParentI->Namespace);
-  ParentI->ChildFunctions.emplace_back(std::move(Func));
-  // Info is wrapped in its parent scope so it's returned in the second position
-  return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
+  // Info is wrapped in its parent scope so is returned in the second position.
+  return {nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
 }
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
@@ -633,12 +672,52 @@
       Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record};
   Func.Access = D->getAccess();
 
-  // Wrap in enclosing scope
-  auto ParentI = std::make_unique<RecordInfo>();
-  ParentI->USR = ParentUSR;
-  ParentI->ChildFunctions.emplace_back(std::move(Func));
-  // Info is wrapped in its parent scope so it's returned in the second position
-  return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
+  // Info is wrapped in its parent scope so is returned in the second position.
+  return {nullptr, MakeAndInsertIntoParent<FunctionInfo &&>(std::move(Func))};
+}
+
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const TypedefDecl *D, const FullComment *FC, int LineNumber,
+         StringRef File, bool IsFileInRootDir, bool PublicOnly) {
+  TypedefInfo Info;
+
+  bool IsInAnonymousNamespace = false;
+  populateInfo(Info, D, FC, IsInAnonymousNamespace);
+  if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
+    return {};
+
+  Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
+  Info.Underlying = getTypeInfoForType(D->getUnderlyingType());
+  if (Info.Underlying.Type.Name.empty()) {
+    // Typedef for an unnamed type. This is like "typedef struct { } Foo;"
+    // The record serializer explicitly checks for this syntax and constructs
+    // a record with that name, so we don't want to emit a duplicate here.
+    return {};
+  }
+  Info.IsUsing = false;
+
+  // Info is wrapped in its parent scope so is returned in the second position.
+  return {nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))};
+}
+
+// A type alias is a C++ "using" declaration for a type. It gets mapped to a
+// TypedefInfo with the IsUsing flag set.
+std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
+emitInfo(const TypeAliasDecl *D, const FullComment *FC, int LineNumber,
+         StringRef File, bool IsFileInRootDir, bool PublicOnly) {
+  TypedefInfo Info;
+
+  bool IsInAnonymousNamespace = false;
+  populateInfo(Info, D, FC, IsInAnonymousNamespace);
+  if (!shouldSerializeInfo(PublicOnly, IsInAnonymousNamespace, D))
+    return {};
+
+  Info.DefLoc.emplace(LineNumber, File, IsFileInRootDir);
+  Info.Underlying = getTypeInfoForType(D->getUnderlyingType());
+  Info.IsUsing = true;
+
+  // Info is wrapped in its parent scope so is returned in the second position.
+  return {nullptr, MakeAndInsertIntoParent<TypedefInfo &&>(std::move(Info))};
 }
 
 std::pair<std::unique_ptr<Info>, std::unique_ptr<Info>>
@@ -656,38 +735,8 @@
     Enum.BaseType = TypeInfo(D->getIntegerType().getAsString());
   parseEnumerators(Enum, D);
 
-  // Put in global namespace
-  if (Enum.Namespace.empty()) {
-    auto ParentI = std::make_unique<NamespaceInfo>();
-    ParentI->USR = SymbolID();
-    ParentI->ChildEnums.emplace_back(std::move(Enum));
-    ParentI->Path = getInfoRelativePath(ParentI->Namespace);
-    // Info is wrapped in its parent scope so it's returned in the second
-    // position
-    return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
-  }
-
-  // Wrap in enclosing scope
-  switch (Enum.Namespace[0].RefType) {
-  case InfoType::IT_namespace: {
-    auto ParentI = std::make_unique<NamespaceInfo>();
-    ParentI->USR = Enum.Namespace[0].USR;
-    ParentI->ChildEnums.emplace_back(std::move(Enum));
-    // Info is wrapped in its parent scope so it's returned in the second
-    // position
-    return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
-  }
-  case InfoType::IT_record: {
-    auto ParentI = std::make_unique<RecordInfo>();
-    ParentI->USR = Enum.Namespace[0].USR;
-    ParentI->ChildEnums.emplace_back(std::move(Enum));
-    // Info is wrapped in its parent scope so it's returned in the second
-    // position
-    return {nullptr, std::unique_ptr<Info>{std::move(ParentI)}};
-  }
-  default:
-    llvm_unreachable("Invalid reference type for parent namespace");
-  }
+  // Info is wrapped in its parent scope so is returned in the second position.
+  return {nullptr, MakeAndInsertIntoParent<EnumInfo &&>(std::move(Enum))};
 }
 
 } // namespace serialize
Index: clang-tools-extra/clang-doc/Representation.h
===================================================================
--- clang-tools-extra/clang-doc/Representation.h
+++ clang-tools-extra/clang-doc/Representation.h
@@ -30,17 +30,19 @@
 // SHA1'd hash of a USR.
 using SymbolID = std::array<uint8_t, 20>;
 
-struct Info;
-struct FunctionInfo;
-struct EnumInfo;
 struct BaseRecordInfo;
+struct EnumInfo;
+struct FunctionInfo;
+struct Info;
+struct TypedefInfo;
 
 enum class InfoType {
   IT_default,
   IT_namespace,
   IT_record,
   IT_function,
-  IT_enum
+  IT_enum,
+  IT_typedef
 };
 
 // A representation of a parsed comment.
@@ -142,6 +144,22 @@
   llvm::SmallString<128> Path;
 };
 
+// Holds the children of a record or namespace.
+struct ScopeChildren {
+  // Namespaces and Records are references because they will be properly
+  // documented in their own info, while the entirety of Functions and Enums are
+  // included here because they should not have separate documentation from
+  // their scope.
+  //
+  // Namespaces are not syntactically valid as children of records, but making
+  // this general for all possible container types reduces code complexity.
+  std::vector<Reference> Namespaces;
+  std::vector<Reference> Records;
+  std::vector<FunctionInfo> Functions;
+  std::vector<EnumInfo> Enums;
+  std::vector<TypedefInfo> Typedefs;
+};
+
 // A base struct for TypeInfos
 struct TypeInfo {
   TypeInfo() = default;
@@ -266,14 +284,7 @@
 
   void merge(NamespaceInfo &&I);
 
-  // Namespaces and Records are references because they will be properly
-  // documented in their own info, while the entirety of Functions and Enums are
-  // included here because they should not have separate documentation from
-  // their scope.
-  std::vector<Reference> ChildNamespaces;
-  std::vector<Reference> ChildRecords;
-  std::vector<FunctionInfo> ChildFunctions;
-  std::vector<EnumInfo> ChildEnums;
+  ScopeChildren Children;
 };
 
 // Info for symbols.
@@ -338,12 +349,23 @@
       Bases; // List of base/parent records; this includes inherited methods and
              // attributes
 
-  // Records are references because they will be properly documented in their
-  // own info, while the entirety of Functions and Enums are included here
-  // because they should not have separate documentation from their scope.
-  std::vector<Reference> ChildRecords;
-  std::vector<FunctionInfo> ChildFunctions;
-  std::vector<EnumInfo> ChildEnums;
+  ScopeChildren Children;
+};
+
+// Info for typedef and using statements.
+struct TypedefInfo : public SymbolInfo {
+  TypedefInfo(SymbolID USR = SymbolID())
+      : SymbolInfo(InfoType::IT_typedef, USR) {}
+
+  void merge(TypedefInfo &&I);
+
+  TypeInfo Underlying;
+
+  // Inidicates if this is a new C++ "using"-style typedef:
+  //   using MyVector = std::vector<int>
+  // False means it's a C-style typedef:
+  //   typedef std::vector<int> MyVector;
+  bool IsUsing;
 };
 
 struct BaseRecordInfo : public RecordInfo {
Index: clang-tools-extra/clang-doc/Representation.cpp
===================================================================
--- clang-tools-extra/clang-doc/Representation.cpp
+++ clang-tools-extra/clang-doc/Representation.cpp
@@ -90,6 +90,18 @@
   }
 }
 
+void reduceChildren(std::vector<TypedefInfo> &Children,
+                    std::vector<TypedefInfo> &&ChildrenToMerge) {
+  for (auto &ChildToMerge : ChildrenToMerge) {
+    int mergeIdx = getChildIndexIfExists(Children, ChildToMerge);
+    if (mergeIdx == -1) {
+      Children.push_back(std::move(ChildToMerge));
+      continue;
+    }
+    Children[mergeIdx].merge(std::move(ChildToMerge));
+  }
+}
+
 } // namespace
 
 // Dispatch function.
@@ -108,6 +120,8 @@
     return reduce<EnumInfo>(Values);
   case InfoType::IT_function:
     return reduce<FunctionInfo>(Values);
+  case InfoType::IT_typedef:
+    return reduce<TypedefInfo>(Values);
   default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "unexpected info type");
@@ -209,10 +223,11 @@
 void NamespaceInfo::merge(NamespaceInfo &&Other) {
   assert(mergeable(Other));
   // Reduce children if necessary.
-  reduceChildren(ChildNamespaces, std::move(Other.ChildNamespaces));
-  reduceChildren(ChildRecords, std::move(Other.ChildRecords));
-  reduceChildren(ChildFunctions, std::move(Other.ChildFunctions));
-  reduceChildren(ChildEnums, std::move(Other.ChildEnums));
+  reduceChildren(Children.Namespaces, std::move(Other.Children.Namespaces));
+  reduceChildren(Children.Records, std::move(Other.Children.Records));
+  reduceChildren(Children.Functions, std::move(Other.Children.Functions));
+  reduceChildren(Children.Enums, std::move(Other.Children.Enums));
+  reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs));
   mergeBase(std::move(Other));
 }
 
@@ -230,9 +245,10 @@
   if (VirtualParents.empty())
     VirtualParents = std::move(Other.VirtualParents);
   // Reduce children if necessary.
-  reduceChildren(ChildRecords, std::move(Other.ChildRecords));
-  reduceChildren(ChildFunctions, std::move(Other.ChildFunctions));
-  reduceChildren(ChildEnums, std::move(Other.ChildEnums));
+  reduceChildren(Children.Records, std::move(Other.Children.Records));
+  reduceChildren(Children.Functions, std::move(Other.Children.Functions));
+  reduceChildren(Children.Enums, std::move(Other.Children.Enums));
+  reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs));
   SymbolInfo::merge(std::move(Other));
 }
 
@@ -260,6 +276,15 @@
   SymbolInfo::merge(std::move(Other));
 }
 
+void TypedefInfo::merge(TypedefInfo &&Other) {
+  assert(mergeable(Other));
+  if (!IsUsing)
+    IsUsing = Other.IsUsing;
+  if (Underlying.Type.Name == "")
+    Underlying = Other.Underlying;
+  SymbolInfo::merge(std::move(Other));
+}
+
 llvm::SmallString<16> Info::extractName() const {
   if (!Name.empty())
     return Name;
@@ -282,6 +307,9 @@
   case InfoType::IT_enum:
     return llvm::SmallString<16>("@nonymous_enum_" +
                                  toHex(llvm::toStringRef(USR)));
+  case InfoType::IT_typedef:
+    return llvm::SmallString<16>("@nonymous_typedef_" +
+                                 toHex(llvm::toStringRef(USR)));
   case InfoType::IT_function:
     return llvm::SmallString<16>("@nonymous_function_" +
                                  toHex(llvm::toStringRef(USR)));
Index: clang-tools-extra/clang-doc/Mapper.h
===================================================================
--- clang-tools-extra/clang-doc/Mapper.h
+++ clang-tools-extra/clang-doc/Mapper.h
@@ -39,6 +39,8 @@
   bool VisitEnumDecl(const EnumDecl *D);
   bool VisitCXXMethodDecl(const CXXMethodDecl *D);
   bool VisitFunctionDecl(const FunctionDecl *D);
+  bool VisitTypedefDecl(const TypedefDecl *D);
+  bool VisitTypeAliasDecl(const TypeAliasDecl *D);
 
 private:
   template <typename T> bool mapDecl(const T *D);
Index: clang-tools-extra/clang-doc/Mapper.cpp
===================================================================
--- clang-tools-extra/clang-doc/Mapper.cpp
+++ clang-tools-extra/clang-doc/Mapper.cpp
@@ -71,6 +71,14 @@
   return mapDecl(D);
 }
 
+bool MapASTVisitor::VisitTypedefDecl(const TypedefDecl *D) {
+  return mapDecl(D);
+}
+
+bool MapASTVisitor::VisitTypeAliasDecl(const TypeAliasDecl *D) {
+  return mapDecl(D);
+}
+
 comments::FullComment *
 MapASTVisitor::getComment(const NamedDecl *D, const ASTContext &Context) const {
   RawComment *Comment = Context.getRawCommentForDeclNoCache(D);
Index: clang-tools-extra/clang-doc/MDGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/MDGenerator.cpp
+++ clang-tools-extra/clang-doc/MDGenerator.cpp
@@ -189,9 +189,9 @@
 
   llvm::SmallString<64> BasePath = I.getRelativeFilePath("");
 
-  if (!I.ChildNamespaces.empty()) {
+  if (!I.Children.Namespaces.empty()) {
     writeHeader("Namespaces", 2, OS);
-    for (const auto &R : I.ChildNamespaces) {
+    for (const auto &R : I.Children.Namespaces) {
       OS << "* ";
       writeNameLink(BasePath, R, OS);
       OS << "\n";
@@ -199,9 +199,9 @@
     writeNewLine(OS);
   }
 
-  if (!I.ChildRecords.empty()) {
+  if (!I.Children.Records.empty()) {
     writeHeader("Records", 2, OS);
-    for (const auto &R : I.ChildRecords) {
+    for (const auto &R : I.Children.Records) {
       OS << "* ";
       writeNameLink(BasePath, R, OS);
       OS << "\n";
@@ -209,15 +209,15 @@
     writeNewLine(OS);
   }
 
-  if (!I.ChildFunctions.empty()) {
+  if (!I.Children.Functions.empty()) {
     writeHeader("Functions", 2, OS);
-    for (const auto &F : I.ChildFunctions)
+    for (const auto &F : I.Children.Functions)
       genMarkdown(CDCtx, F, OS);
     writeNewLine(OS);
   }
-  if (!I.ChildEnums.empty()) {
+  if (!I.Children.Enums.empty()) {
     writeHeader("Enums", 2, OS);
-    for (const auto &E : I.ChildEnums)
+    for (const auto &E : I.Children.Enums)
       genMarkdown(CDCtx, E, OS);
     writeNewLine(OS);
   }
@@ -259,26 +259,31 @@
     writeNewLine(OS);
   }
 
-  if (!I.ChildRecords.empty()) {
+  if (!I.Children.Records.empty()) {
     writeHeader("Records", 2, OS);
-    for (const auto &R : I.ChildRecords)
+    for (const auto &R : I.Children.Records)
       writeLine(R.Name, OS);
     writeNewLine(OS);
   }
-  if (!I.ChildFunctions.empty()) {
+  if (!I.Children.Functions.empty()) {
     writeHeader("Functions", 2, OS);
-    for (const auto &F : I.ChildFunctions)
+    for (const auto &F : I.Children.Functions)
       genMarkdown(CDCtx, F, OS);
     writeNewLine(OS);
   }
-  if (!I.ChildEnums.empty()) {
+  if (!I.Children.Enums.empty()) {
     writeHeader("Enums", 2, OS);
-    for (const auto &E : I.ChildEnums)
+    for (const auto &E : I.Children.Enums)
       genMarkdown(CDCtx, E, OS);
     writeNewLine(OS);
   }
 }
 
+static void genMarkdown(const ClangDocContext &CDCtx, const TypedefInfo &I,
+                        llvm::raw_ostream &OS) {
+  // TODO support typedefs in markdown.
+}
+
 static void serializeReference(llvm::raw_fd_ostream &OS, Index &I, int Level) {
   // Write out the heading level starting at ##
   OS << "##" << std::string(Level, '#') << " ";
@@ -337,6 +342,9 @@
       case InfoType::IT_function:
         Type = "Function";
         break;
+      case InfoType::IT_typedef:
+        Type = "Typedef";
+        break;
       case InfoType::IT_default:
         Type = "Other";
       }
@@ -375,6 +383,9 @@
   case InfoType::IT_function:
     genMarkdown(CDCtx, *static_cast<clang::doc::FunctionInfo *>(I), OS);
     break;
+  case InfoType::IT_typedef:
+    genMarkdown(CDCtx, *static_cast<clang::doc::TypedefInfo *>(I), OS);
+    break;
   case InfoType::IT_default:
     return createStringError(llvm::inconvertibleErrorCode(),
                              "unexpected InfoType");
Index: clang-tools-extra/clang-doc/HTMLGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/HTMLGenerator.cpp
+++ clang-tools-extra/clang-doc/HTMLGenerator.cpp
@@ -734,28 +734,29 @@
   llvm::SmallString<64> BasePath = I.getRelativeFilePath("");
 
   std::vector<std::unique_ptr<TagNode>> ChildNamespaces =
-      genReferencesBlock(I.ChildNamespaces, "Namespaces", BasePath);
+      genReferencesBlock(I.Children.Namespaces, "Namespaces", BasePath);
   AppendVector(std::move(ChildNamespaces), Out);
   std::vector<std::unique_ptr<TagNode>> ChildRecords =
-      genReferencesBlock(I.ChildRecords, "Records", BasePath);
+      genReferencesBlock(I.Children.Records, "Records", BasePath);
   AppendVector(std::move(ChildRecords), Out);
 
   std::vector<std::unique_ptr<TagNode>> ChildFunctions =
-      genFunctionsBlock(I.ChildFunctions, CDCtx, BasePath);
+      genFunctionsBlock(I.Children.Functions, CDCtx, BasePath);
   AppendVector(std::move(ChildFunctions), Out);
   std::vector<std::unique_ptr<TagNode>> ChildEnums =
-      genEnumsBlock(I.ChildEnums, CDCtx);
+      genEnumsBlock(I.Children.Enums, CDCtx);
   AppendVector(std::move(ChildEnums), Out);
 
-  if (!I.ChildNamespaces.empty())
+  if (!I.Children.Namespaces.empty())
     InfoIndex.Children.emplace_back("Namespaces", "Namespaces");
-  if (!I.ChildRecords.empty())
+  if (!I.Children.Records.empty())
     InfoIndex.Children.emplace_back("Records", "Records");
-  if (!I.ChildFunctions.empty())
+  if (!I.Children.Functions.empty())
     InfoIndex.Children.emplace_back(
-        genInfoIndexItem(I.ChildFunctions, "Functions"));
-  if (!I.ChildEnums.empty())
-    InfoIndex.Children.emplace_back(genInfoIndexItem(I.ChildEnums, "Enums"));
+        genInfoIndexItem(I.Children.Functions, "Functions"));
+  if (!I.Children.Enums.empty())
+    InfoIndex.Children.emplace_back(
+        genInfoIndexItem(I.Children.Enums, "Enums"));
 
   return Out;
 }
@@ -802,29 +803,37 @@
       genRecordMembersBlock(I.Members, I.Path);
   AppendVector(std::move(Members), Out);
   std::vector<std::unique_ptr<TagNode>> ChildRecords =
-      genReferencesBlock(I.ChildRecords, "Records", I.Path);
+      genReferencesBlock(I.Children.Records, "Records", I.Path);
   AppendVector(std::move(ChildRecords), Out);
 
   std::vector<std::unique_ptr<TagNode>> ChildFunctions =
-      genFunctionsBlock(I.ChildFunctions, CDCtx, I.Path);
+      genFunctionsBlock(I.Children.Functions, CDCtx, I.Path);
   AppendVector(std::move(ChildFunctions), Out);
   std::vector<std::unique_ptr<TagNode>> ChildEnums =
-      genEnumsBlock(I.ChildEnums, CDCtx);
+      genEnumsBlock(I.Children.Enums, CDCtx);
   AppendVector(std::move(ChildEnums), Out);
 
   if (!I.Members.empty())
     InfoIndex.Children.emplace_back("Members", "Members");
-  if (!I.ChildRecords.empty())
+  if (!I.Children.Records.empty())
     InfoIndex.Children.emplace_back("Records", "Records");
-  if (!I.ChildFunctions.empty())
+  if (!I.Children.Functions.empty())
+    InfoIndex.Children.emplace_back(
+        genInfoIndexItem(I.Children.Functions, "Functions"));
+  if (!I.Children.Enums.empty())
     InfoIndex.Children.emplace_back(
-        genInfoIndexItem(I.ChildFunctions, "Functions"));
-  if (!I.ChildEnums.empty())
-    InfoIndex.Children.emplace_back(genInfoIndexItem(I.ChildEnums, "Enums"));
+        genInfoIndexItem(I.Children.Enums, "Enums"));
 
   return Out;
 }
 
+static std::vector<std::unique_ptr<TagNode>>
+genHTML(const TypedefInfo &I, const ClangDocContext &CDCtx,
+        std::string &InfoTitle) {
+  // TODO support typedefs in HTML.
+  return {};
+}
+
 /// Generator for HTML documentation.
 class HTMLGenerator : public Generator {
 public:
@@ -858,6 +867,10 @@
     MainContentNodes =
         genHTML(*static_cast<clang::doc::FunctionInfo *>(I), CDCtx, "");
     break;
+  case InfoType::IT_typedef:
+    MainContentNodes =
+        genHTML(*static_cast<clang::doc::TypedefInfo *>(I), CDCtx, InfoTitle);
+    break;
   case InfoType::IT_default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "unexpected info type");
@@ -882,6 +895,8 @@
     return "function";
   case InfoType::IT_enum:
     return "enum";
+  case InfoType::IT_typedef:
+    return "typedef";
   }
   llvm_unreachable("Unknown InfoType");
 }
Index: clang-tools-extra/clang-doc/BitcodeWriter.h
===================================================================
--- clang-tools-extra/clang-doc/BitcodeWriter.h
+++ clang-tools-extra/clang-doc/BitcodeWriter.h
@@ -64,6 +64,7 @@
   BI_FUNCTION_BLOCK_ID,
   BI_COMMENT_BLOCK_ID,
   BI_REFERENCE_BLOCK_ID,
+  BI_TYPEDEF_BLOCK_ID,
   BI_LAST,
   BI_FIRST = BI_VERSION_BLOCK_ID
 };
@@ -123,6 +124,10 @@
   REFERENCE_TYPE,
   REFERENCE_PATH,
   REFERENCE_FIELD,
+  TYPEDEF_USR,
+  TYPEDEF_NAME,
+  TYPEDEF_DEFLOCATION,
+  TYPEDEF_IS_USING,
   RI_LAST,
   RI_FIRST = VERSION
 };
@@ -160,8 +165,9 @@
   void emitBlock(const EnumInfo &I);
   void emitBlock(const EnumValueInfo &I);
   void emitBlock(const TypeInfo &B);
+  void emitBlock(const TypedefInfo &B);
   void emitBlock(const FieldTypeInfo &B);
-  void emitBlock(const MemberTypeInfo &B);
+  void emitBlock(const MemberTypeInfo &T);
   void emitBlock(const CommentInfo &B);
   void emitBlock(const Reference &B, FieldId F);
 
Index: clang-tools-extra/clang-doc/BitcodeWriter.cpp
===================================================================
--- clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -113,6 +113,7 @@
           {BI_NAMESPACE_BLOCK_ID, "NamespaceBlock"},
           {BI_ENUM_BLOCK_ID, "EnumBlock"},
           {BI_ENUM_VALUE_BLOCK_ID, "EnumValueBlock"},
+          {BI_TYPEDEF_BLOCK_ID, "TypedefBlock"},
           {BI_TYPE_BLOCK_ID, "TypeBlock"},
           {BI_FIELD_TYPE_BLOCK_ID, "FieldTypeBlock"},
           {BI_MEMBER_TYPE_BLOCK_ID, "MemberTypeBlock"},
@@ -187,7 +188,11 @@
           {REFERENCE_NAME, {"Name", &StringAbbrev}},
           {REFERENCE_TYPE, {"RefType", &IntAbbrev}},
           {REFERENCE_PATH, {"Path", &StringAbbrev}},
-          {REFERENCE_FIELD, {"Field", &IntAbbrev}}};
+          {REFERENCE_FIELD, {"Field", &IntAbbrev}},
+          {TYPEDEF_USR, {"USR", &SymbolIDAbbrev}},
+          {TYPEDEF_NAME, {"Name", &StringAbbrev}},
+          {TYPEDEF_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
+          {TYPEDEF_IS_USING, {"IsUsing", &BoolAbbrev}}};
       assert(Inits.size() == RecordIdCount);
       for (const auto &Init : Inits) {
         RecordIdNameMap[Init.first] = Init.second;
@@ -218,6 +223,9 @@
         // Enum Value Block
         {BI_ENUM_VALUE_BLOCK_ID,
          {ENUM_VALUE_NAME, ENUM_VALUE_VALUE, ENUM_VALUE_EXPR}},
+        // Typedef Block
+        {BI_TYPEDEF_BLOCK_ID,
+         {TYPEDEF_USR, TYPEDEF_NAME, TYPEDEF_DEFLOCATION, TYPEDEF_IS_USING}},
         // Namespace Block
         {BI_NAMESPACE_BLOCK_ID,
          {NAMESPACE_USR, NAMESPACE_NAME, NAMESPACE_PATH}},
@@ -418,6 +426,18 @@
   emitBlock(T.Type, FieldId::F_type);
 }
 
+void ClangDocBitcodeWriter::emitBlock(const TypedefInfo &T) {
+  StreamSubBlockGuard Block(Stream, BI_TYPEDEF_BLOCK_ID);
+  emitRecord(T.USR, TYPEDEF_USR);
+  emitRecord(T.Name, TYPEDEF_NAME);
+  for (const auto &N : T.Namespace)
+    emitBlock(N, FieldId::F_namespace);
+  if (T.DefLoc)
+    emitRecord(*T.DefLoc, TYPEDEF_DEFLOCATION);
+  emitRecord(T.IsUsing, TYPEDEF_IS_USING);
+  emitBlock(T.Underlying);
+}
+
 void ClangDocBitcodeWriter::emitBlock(const FieldTypeInfo &T) {
   StreamSubBlockGuard Block(Stream, BI_FIELD_TYPE_BLOCK_ID);
   emitBlock(T.Type, FieldId::F_type);
@@ -465,13 +485,15 @@
     emitBlock(N, FieldId::F_namespace);
   for (const auto &CI : I.Description)
     emitBlock(CI);
-  for (const auto &C : I.ChildNamespaces)
+  for (const auto &C : I.Children.Namespaces)
     emitBlock(C, FieldId::F_child_namespace);
-  for (const auto &C : I.ChildRecords)
+  for (const auto &C : I.Children.Records)
     emitBlock(C, FieldId::F_child_record);
-  for (const auto &C : I.ChildFunctions)
+  for (const auto &C : I.Children.Functions)
     emitBlock(C);
-  for (const auto &C : I.ChildEnums)
+  for (const auto &C : I.Children.Enums)
+    emitBlock(C);
+  for (const auto &C : I.Children.Typedefs)
     emitBlock(C);
 }
 
@@ -524,11 +546,13 @@
     emitBlock(P, FieldId::F_vparent);
   for (const auto &PB : I.Bases)
     emitBlock(PB);
-  for (const auto &C : I.ChildRecords)
+  for (const auto &C : I.Children.Records)
     emitBlock(C, FieldId::F_child_record);
-  for (const auto &C : I.ChildFunctions)
+  for (const auto &C : I.Children.Functions)
+    emitBlock(C);
+  for (const auto &C : I.Children.Enums)
     emitBlock(C);
-  for (const auto &C : I.ChildEnums)
+  for (const auto &C : I.Children.Typedefs)
     emitBlock(C);
 }
 
@@ -543,7 +567,7 @@
   emitRecord(I.IsParent, BASE_RECORD_IS_PARENT);
   for (const auto &M : I.Members)
     emitBlock(M);
-  for (const auto &C : I.ChildFunctions)
+  for (const auto &C : I.Children.Functions)
     emitBlock(C);
 }
 
@@ -581,6 +605,9 @@
   case InfoType::IT_function:
     emitBlock(*static_cast<clang::doc::FunctionInfo *>(I));
     break;
+  case InfoType::IT_typedef:
+    emitBlock(*static_cast<clang::doc::TypedefInfo *>(I));
+    break;
   default:
     llvm::errs() << "Unexpected info, unable to write.\n";
     return true;
Index: clang-tools-extra/clang-doc/BitcodeReader.cpp
===================================================================
--- clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -24,12 +24,6 @@
   return llvm::Error::success();
 }
 
-llvm::Error decodeRecord(const Record &R, std::string &Field,
-                         llvm::StringRef Blob) {
-  Field.assign(Blob.begin(), Blob.end());
-  return llvm::Error::success();
-}
-
 llvm::Error decodeRecord(const Record &R, SymbolID &Field,
                          llvm::StringRef Blob) {
   if (R[0] != BitCodeConstants::USRHashSize)
@@ -104,6 +98,7 @@
   case InfoType::IT_function:
   case InfoType::IT_default:
   case InfoType::IT_enum:
+  case InfoType::IT_typedef:
     Field = IT;
     return llvm::Error::success();
   }
@@ -233,6 +228,23 @@
   }
 }
 
+llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob,
+                        TypedefInfo *I) {
+  switch (ID) {
+  case TYPEDEF_USR:
+    return decodeRecord(R, I->USR, Blob);
+  case TYPEDEF_NAME:
+    return decodeRecord(R, I->Name, Blob);
+  case TYPEDEF_DEFLOCATION:
+    return decodeRecord(R, I->DefLoc, Blob);
+  case TYPEDEF_IS_USING:
+    return decodeRecord(R, I->IsUsing, Blob);
+  default:
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "invalid field for TypedefInfo");
+  }
+}
+
 llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob,
                         EnumValueInfo *I) {
   switch (ID) {
@@ -424,6 +436,11 @@
   return llvm::Error::success();
 }
 
+template <> llvm::Error addTypeInfo(TypedefInfo *I, TypeInfo &&T) {
+  I->Underlying = std::move(T);
+  return llvm::Error::success();
+}
+
 template <typename T> llvm::Error addReference(T I, Reference &&R, FieldId F) {
   return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                  "invalid type cannot contain Reference");
@@ -475,6 +492,17 @@
   }
 }
 
+template <> llvm::Error addReference(TypedefInfo *I, Reference &&R, FieldId F) {
+  switch (F) {
+  case FieldId::F_namespace:
+    I->Namespace.emplace_back(std::move(R));
+    return llvm::Error::success();
+  default:
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "invalid type cannot contain Reference");
+  }
+}
+
 template <>
 llvm::Error addReference(NamespaceInfo *I, Reference &&R, FieldId F) {
   switch (F) {
@@ -482,10 +510,10 @@
     I->Namespace.emplace_back(std::move(R));
     return llvm::Error::success();
   case FieldId::F_child_namespace:
-    I->ChildNamespaces.emplace_back(std::move(R));
+    I->Children.Namespaces.emplace_back(std::move(R));
     return llvm::Error::success();
   case FieldId::F_child_record:
-    I->ChildRecords.emplace_back(std::move(R));
+    I->Children.Records.emplace_back(std::move(R));
     return llvm::Error::success();
   default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -520,7 +548,7 @@
     I->VirtualParents.emplace_back(std::move(R));
     return llvm::Error::success();
   case FieldId::F_child_record:
-    I->ChildRecords.emplace_back(std::move(R));
+    I->Children.Records.emplace_back(std::move(R));
     return llvm::Error::success();
   default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
@@ -534,32 +562,37 @@
   exit(1);
 }
 
+// Namespace children:
 template <> void addChild(NamespaceInfo *I, FunctionInfo &&R) {
-  I->ChildFunctions.emplace_back(std::move(R));
+  I->Children.Functions.emplace_back(std::move(R));
 }
-
 template <> void addChild(NamespaceInfo *I, EnumInfo &&R) {
-  I->ChildEnums.emplace_back(std::move(R));
+  I->Children.Enums.emplace_back(std::move(R));
+}
+template <> void addChild(NamespaceInfo *I, TypedefInfo &&R) {
+  I->Children.Typedefs.emplace_back(std::move(R));
 }
 
+// Record children:
 template <> void addChild(RecordInfo *I, FunctionInfo &&R) {
-  I->ChildFunctions.emplace_back(std::move(R));
+  I->Children.Functions.emplace_back(std::move(R));
 }
-
 template <> void addChild(RecordInfo *I, EnumInfo &&R) {
-  I->ChildEnums.emplace_back(std::move(R));
+  I->Children.Enums.emplace_back(std::move(R));
+}
+template <> void addChild(RecordInfo *I, TypedefInfo &&R) {
+  I->Children.Typedefs.emplace_back(std::move(R));
 }
 
+// Other types of children:
 template <> void addChild(EnumInfo *I, EnumValueInfo &&R) {
   I->Members.emplace_back(std::move(R));
 }
-
 template <> void addChild(RecordInfo *I, BaseRecordInfo &&R) {
   I->Bases.emplace_back(std::move(R));
 }
-
 template <> void addChild(BaseRecordInfo *I, FunctionInfo &&R) {
-  I->ChildFunctions.emplace_back(std::move(R));
+  I->Children.Functions.emplace_back(std::move(R));
 }
 
 // Read records from bitcode into a given info.
@@ -686,6 +719,13 @@
     addChild(I, std::move(EV));
     return llvm::Error::success();
   }
+  case BI_TYPEDEF_BLOCK_ID: {
+    TypedefInfo TI;
+    if (auto Err = readBlock(ID, &TI))
+      return Err;
+    addChild(I, std::move(TI));
+    return llvm::Error::success();
+  }
   default:
     return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                    "invalid subblock type");
@@ -786,6 +826,8 @@
     return createInfo<RecordInfo>(ID);
   case BI_ENUM_BLOCK_ID:
     return createInfo<EnumInfo>(ID);
+  case BI_TYPEDEF_BLOCK_ID:
+    return createInfo<TypedefInfo>(ID);
   case BI_FUNCTION_BLOCK_ID:
     return createInfo<FunctionInfo>(ID);
   default:
@@ -825,6 +867,7 @@
     case BI_NAMESPACE_BLOCK_ID:
     case BI_RECORD_BLOCK_ID:
     case BI_ENUM_BLOCK_ID:
+    case BI_TYPEDEF_BLOCK_ID:
     case BI_FUNCTION_BLOCK_ID: {
       auto InfoOrErr = readBlockToInfo(ID);
       if (!InfoOrErr)
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to