This revision was automatically updated to reflect the committed changes.
Closed by commit rG0f6dbb5f1646: [clang-doc] Add template support. (authored by 
brettw).

Changed prior to commit:
  https://reviews.llvm.org/D139154?vs=480560&id=480960#toc

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D139154

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/Representation.cpp
  clang-tools-extra/clang-doc/Representation.h
  clang-tools-extra/clang-doc/Serialize.cpp
  clang-tools-extra/clang-doc/YAMLGenerator.cpp
  clang-tools-extra/test/clang-doc/single-file-public.cpp
  clang-tools-extra/test/clang-doc/single-file.cpp
  clang-tools-extra/test/clang-doc/templates.cpp
  clang-tools-extra/unittests/clang-doc/HTMLGeneratorTest.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,10 +28,11 @@
   I.Path = "path/to/A";
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
-  I.Children.Namespaces.emplace_back(EmptySID, "ChildNamespace",
-                                     InfoType::IT_namespace,
-                                     "path/to/A/Namespace");
+  I.Children.Namespaces.emplace_back(
+      EmptySID, "ChildNamespace", InfoType::IT_namespace,
+      "path::to::A::Namespace::ChildNamespace", "path/to/A/Namespace");
   I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
+                                  "path::to::A::Namespace::ChildStruct",
                                   "path/to/A/Namespace");
   I.Children.Functions.emplace_back();
   I.Children.Functions.back().Name = "OneFunction";
@@ -53,13 +54,16 @@
 Namespace:
   - Type:            Namespace
     Name:            'A'
+    QualName:        'A'
 ChildNamespaces:
   - Type:            Namespace
     Name:            'ChildNamespace'
+    QualName:        'path::to::A::Namespace::ChildNamespace'
     Path:            'path/to/A/Namespace'
 ChildRecords:
   - Type:            Record
     Name:            'ChildStruct'
+    QualName:        'path::to::A::Namespace::ChildStruct'
     Path:            'path/to/A/Namespace'
 ChildFunctions:
   - USR:             '0000000000000000000000000000000000000000'
@@ -83,8 +87,7 @@
   I.DefLoc = Location(10, llvm::SmallString<16>{"test.cpp"});
   I.Loc.emplace_back(12, llvm::SmallString<16>{"test.cpp"});
 
-  I.Members.emplace_back(TypeInfo("int", "path/to/int"), "X",
-                         AccessSpecifier::AS_private);
+  I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
 
   // Member documentation.
   CommentInfo TopComment;
@@ -103,15 +106,15 @@
                        AccessSpecifier::AS_public, true);
   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",
+  I.Bases.back().Members.emplace_back(TypeInfo("int"), "N",
                                       AccessSpecifier::AS_private);
   // F is in the global namespace
   I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "");
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record,
-                                "path/to/G");
+                                "path::to::G::G", "path/to/G");
 
   I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
-                                  "path/to/A/r");
+                                  "path::to::A::r::ChildStruct", "path/to/A/r");
   I.Children.Functions.emplace_back();
   I.Children.Functions.back().Name = "OneFunction";
   I.Children.Enums.emplace_back();
@@ -131,6 +134,7 @@
 Namespace:
   - Type:            Namespace
     Name:            'A'
+    QualName:        'A'
 DefLocation:
   LineNumber:      10
   Filename:        'test.cpp'
@@ -142,7 +146,7 @@
 Members:
   - Type:
       Name:            'int'
-      Path:            'path/to/int'
+      QualName:        'int'
     Name:            'X'
     Access:          Private
     Description:
@@ -161,7 +165,7 @@
     Members:
       - Type:
           Name:            'int'
-          Path:            'path/to/int'
+          QualName:        'int'
         Name:            'N'
         Access:          Private
     ChildFunctions:
@@ -178,10 +182,12 @@
 VirtualParents:
   - Type:            Record
     Name:            'G'
+    QualName:        'path::to::G::G'
     Path:            'path/to/G'
 ChildRecords:
   - Type:            Record
     Name:            'ChildStruct'
+    QualName:        'path::to::A::r::ChildStruct'
     Path:            'path/to/A/r'
 ChildFunctions:
   - USR:             '0000000000000000000000000000000000000000'
@@ -206,10 +212,9 @@
 
   I.Access = AccessSpecifier::AS_none;
 
-  I.ReturnType = TypeInfo(
-      Reference(EmptySID, "void", InfoType::IT_default, "path/to/void"));
-  I.Params.emplace_back(TypeInfo("int", "path/to/int"), "P");
-  I.Params.emplace_back(TypeInfo("double", "path/to/double"), "D");
+  I.ReturnType = TypeInfo(Reference(EmptySID, "void", InfoType::IT_default));
+  I.Params.emplace_back(TypeInfo("int"), "P");
+  I.Params.emplace_back(TypeInfo("double"), "D");
   I.Params.back().DefaultValue = "2.0 * M_PI";
   I.IsMethod = true;
   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
@@ -227,6 +232,7 @@
 Namespace:
   - Type:            Namespace
     Name:            'A'
+    QualName:        'A'
 DefLocation:
   LineNumber:      10
   Filename:        'test.cpp'
@@ -237,20 +243,21 @@
 Parent:
   Type:            Record
   Name:            'Parent'
+  QualName:        'Parent'
 Params:
   - Type:
       Name:            'int'
-      Path:            'path/to/int'
+      QualName:        'int'
     Name:            'P'
   - Type:
       Name:            'double'
-      Path:            'path/to/double'
+      QualName:        'double'
     Name:            'D'
     DefaultValue:    '2.0 * M_PI'
 ReturnType:
   Type:
     Name:            'void'
-    Path:            'path/to/void'
+    QualName:        'void'
 ...
 )raw";
   EXPECT_EQ(Expected, Actual.str());
@@ -284,6 +291,7 @@
 Namespace:
   - Type:            Namespace
     Name:            'A'
+    QualName:        'A'
 DefLocation:
   LineNumber:      10
   Filename:        'test.cpp'
@@ -322,6 +330,7 @@
 BaseType:
   Type:
     Name:            'short'
+    QualName:        'short'
 Members:
   - Name:            'X'
     Value:           '-9876'
@@ -349,6 +358,7 @@
 Name:            'MyUsing'
 Underlying:
   Name:            'int'
+  QualName:        'int'
 IsUsing:         true
 ...
 )raw";
@@ -548,13 +558,16 @@
 Params:
   - Type:
       Name:            'int'
+      QualName:        'int'
     Name:            'I'
   - Type:
       Name:            'int'
+      QualName:        'int'
     Name:            'J'
 ReturnType:
   Type:
     Name:            'void'
+    QualName:        'void'
 ...
 )raw";
 
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
@@ -390,7 +390,7 @@
   RecordInfo *F = InfoAsRecord(Infos[0].get());
   RecordInfo ExpectedF(EmptySID, /*Name=*/"F", /*Path=*/"GlobalNamespace");
   ExpectedF.Namespace.emplace_back(EmptySID, "GlobalNamespace",
-                                   InfoType::IT_namespace);
+                                   InfoType::IT_namespace, "");
   ExpectedF.TagType = TagTypeKind::TTK_Class;
   ExpectedF.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   CheckRecordInfo(&ExpectedF, F);
@@ -410,9 +410,10 @@
   ExpectedE.Namespace.emplace_back(EmptySID, "GlobalNamespace",
                                    InfoType::IT_namespace);
   ExpectedE.Parents.emplace_back(EmptySID, /*Name=*/"F", InfoType::IT_record,
-                                 /*Path*=*/"GlobalNamespace");
-  ExpectedE.VirtualParents.emplace_back(
-      EmptySID, /*Name=*/"G", InfoType::IT_record, /*Path*=*/"GlobalNamespace");
+                                 /*QualName=*/"", /*Path*=*/"GlobalNamespace");
+  ExpectedE.VirtualParents.emplace_back(EmptySID, /*Name=*/"G",
+                                        InfoType::IT_record, /*QualName=*/"G",
+                                        /*Path*=*/"GlobalNamespace");
   ExpectedE.Bases.emplace_back(EmptySID, /*Name=*/"F",
                                /*Path=*/"GlobalNamespace", false,
                                AccessSpecifier::AS_public, true);
@@ -455,9 +456,10 @@
   ExpectedH.TagType = TagTypeKind::TTK_Class;
   ExpectedH.DefLoc = Location(0, llvm::SmallString<16>{"test.cpp"});
   ExpectedH.Parents.emplace_back(EmptySID, /*Name=*/"E", InfoType::IT_record,
-                                 /*Path=*/"GlobalNamespace");
-  ExpectedH.VirtualParents.emplace_back(
-      EmptySID, /*Name=*/"G", InfoType::IT_record, /*Path=*/"GlobalNamespace");
+                                 /*QualName=*/"E", /*Path=*/"GlobalNamespace");
+  ExpectedH.VirtualParents.emplace_back(EmptySID, /*Name=*/"G",
+                                        InfoType::IT_record, /*QualName=*/"G",
+                                        /*Path=*/"GlobalNamespace");
   ExpectedH.Bases.emplace_back(EmptySID, /*Name=*/"E",
                                /*Path=*/"GlobalNamespace", false,
                                AccessSpecifier::AS_private, true);
@@ -562,7 +564,7 @@
   NamespaceInfo *ParentA = InfoAsNamespace(Infos[1].get());
   NamespaceInfo ExpectedParentA(EmptySID);
   ExpectedParentA.Children.Records.emplace_back(
-      EmptySID, "A", InfoType::IT_record, "GlobalNamespace");
+      EmptySID, "A", InfoType::IT_record, "A", "GlobalNamespace");
   CheckNamespaceInfo(&ExpectedParentA, ParentA);
 
   RecordInfo *ParentB = InfoAsRecord(Infos[3].get());
@@ -570,13 +572,13 @@
   llvm::SmallString<128> ExpectedParentBPath("GlobalNamespace/A");
   llvm::sys::path::native(ExpectedParentBPath);
   ExpectedParentB.Children.Records.emplace_back(
-      EmptySID, "B", InfoType::IT_record, ExpectedParentBPath);
+      EmptySID, "B", InfoType::IT_record, "A::B", ExpectedParentBPath);
   CheckRecordInfo(&ExpectedParentB, ParentB);
 
   NamespaceInfo *ParentC = InfoAsNamespace(Infos[7].get());
   NamespaceInfo ExpectedParentC(EmptySID);
   ExpectedParentC.Children.Records.emplace_back(
-      EmptySID, "C", InfoType::IT_record, "@nonymous_namespace");
+      EmptySID, "C", InfoType::IT_record, "C", "@nonymous_namespace");
   CheckNamespaceInfo(&ExpectedParentC, ParentC);
 }
 
@@ -594,8 +596,8 @@
 
   NamespaceInfo *ParentB = InfoAsNamespace(Infos[3].get());
   NamespaceInfo ExpectedParentB(EmptySID);
-  ExpectedParentB.Children.Namespaces.emplace_back(EmptySID, "B",
-                                                   InfoType::IT_namespace, "A");
+  ExpectedParentB.Children.Namespaces.emplace_back(
+      EmptySID, "B", InfoType::IT_namespace, "A::B", "A");
   CheckNamespaceInfo(&ExpectedParentB, ParentB);
 }
 
@@ -626,5 +628,105 @@
   EXPECT_EQ("double", SecondTD.Underlying.Type.Name);
 }
 
+TEST(SerializeTests, emitFunctionTemplate) {
+  EmittedInfoList Infos;
+  // A template and a specialization.
+  ExtractInfosFromCode("template<typename T = int> void GetFoo(T);\n"
+                       "template<> void GetFoo<bool>(bool);",
+                       2,
+                       /*Public=*/false, Infos);
+
+  // First info will be the global namespace.
+  NamespaceInfo *GlobalNS1 = InfoAsNamespace(Infos[0].get());
+  ASSERT_EQ(1u, GlobalNS1->Children.Functions.size());
+
+  const FunctionInfo &Func1 = GlobalNS1->Children.Functions[0];
+  EXPECT_EQ("GetFoo", Func1.Name);
+  ASSERT_TRUE(Func1.Template);
+  EXPECT_FALSE(Func1.Template->Specialization); // Not a specialization.
+
+  // Template parameter.
+  ASSERT_EQ(1u, Func1.Template->Params.size());
+  EXPECT_EQ("typename T = int", Func1.Template->Params[0].Contents);
+
+  // The second will be another global namespace with the function 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.Functions.size());
+
+  // This one is a template specialization.
+  const FunctionInfo &Func2 = GlobalNS2->Children.Functions[0];
+  EXPECT_EQ("GetFoo", Func2.Name);
+  ASSERT_TRUE(Func2.Template);
+  EXPECT_TRUE(Func2.Template->Params.empty()); // No template params.
+  ASSERT_TRUE(Func2.Template->Specialization);
+
+  // Specialization values.
+  ASSERT_EQ(1u, Func2.Template->Specialization->Params.size());
+  EXPECT_EQ("bool", Func2.Template->Specialization->Params[0].Contents);
+  EXPECT_EQ(Func1.USR, Func2.Template->Specialization->SpecializationOf);
+}
+
+TEST(SerializeTests, emitClassTemplate) {
+  EmittedInfoList Infos;
+  // This will generate 2x the number of infos: each Record will be followed by
+  // a copy of the global namespace containing it (this test checks the data
+  // pre-merge).
+  ExtractInfosFromCode(
+      "template<int I> class MyTemplate { int i[I]; };\n"
+      "template<> class MyTemplate<0> {};\n"
+      "template<typename T, int U = 1> class OtherTemplate {};\n"
+      "template<int U> class OtherTemplate<MyTemplate<0>, U> {};",
+      8,
+      /*Public=*/false, Infos);
+
+  // First record.
+  const RecordInfo *Rec1 = InfoAsRecord(Infos[0].get());
+  EXPECT_EQ("MyTemplate", Rec1->Name);
+  ASSERT_TRUE(Rec1->Template);
+  EXPECT_FALSE(Rec1->Template->Specialization); // Not a specialization.
+
+  // First record template parameter.
+  ASSERT_EQ(1u, Rec1->Template->Params.size());
+  EXPECT_EQ("int I", Rec1->Template->Params[0].Contents);
+
+  // Second record.
+  const RecordInfo *Rec2 = InfoAsRecord(Infos[2].get());
+  EXPECT_EQ("MyTemplate", Rec2->Name);
+  ASSERT_TRUE(Rec2->Template);
+  EXPECT_TRUE(Rec2->Template->Params.empty()); // No template params.
+  ASSERT_TRUE(Rec2->Template->Specialization);
+
+  // Second record specialization values.
+  ASSERT_EQ(1u, Rec2->Template->Specialization->Params.size());
+  EXPECT_EQ("0", Rec2->Template->Specialization->Params[0].Contents);
+  EXPECT_EQ(Rec1->USR, Rec2->Template->Specialization->SpecializationOf);
+
+  // Third record.
+  const RecordInfo *Rec3 = InfoAsRecord(Infos[4].get());
+  EXPECT_EQ("OtherTemplate", Rec3->Name);
+  ASSERT_TRUE(Rec3->Template);
+
+  // Third record template parameters.
+  ASSERT_EQ(2u, Rec3->Template->Params.size());
+  EXPECT_EQ("typename T", Rec3->Template->Params[0].Contents);
+  EXPECT_EQ("int U = 1", Rec3->Template->Params[1].Contents);
+
+  // Fourth record.
+  const RecordInfo *Rec4 = InfoAsRecord(Infos[6].get());
+  EXPECT_EQ("OtherTemplate", Rec3->Name);
+  ASSERT_TRUE(Rec4->Template);
+  ASSERT_TRUE(Rec4->Template->Specialization);
+
+  // Fourth record template + specialization parameters.
+  ASSERT_EQ(1u, Rec4->Template->Params.size());
+  EXPECT_EQ("int U", Rec4->Template->Params[0].Contents);
+  ASSERT_EQ(2u, Rec4->Template->Specialization->Params.size());
+  EXPECT_EQ("MyTemplate<0>",
+            Rec4->Template->Specialization->Params[0].Contents);
+  EXPECT_EQ("U", Rec4->Template->Specialization->Params[1].Contents);
+}
+
 } // namespace doc
 } // end namespace clang
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
@@ -44,9 +44,10 @@
   I.Namespace.emplace_back(EmptySID, "A", InfoType::IT_namespace);
 
   I.Children.Namespaces.emplace_back(EmptySID, "ChildNamespace",
-                                     InfoType::IT_namespace, "Namespace");
+                                     InfoType::IT_namespace,
+                                     "Namespace::ChildNamespace", "Namespace");
   I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
-                                  "Namespace");
+                                  "Namespace::ChildStruct", "Namespace");
   I.Children.Functions.emplace_back();
   I.Children.Functions.back().Access = AccessSpecifier::AS_none;
   I.Children.Functions.back().Name = "OneFunction";
@@ -152,14 +153,13 @@
 
   SmallString<16> PathTo;
   llvm::sys::path::native("path/to", PathTo);
-  I.Members.emplace_back(TypeInfo("int", "X/Y"), "X",
-                         AccessSpecifier::AS_private);
+  I.Members.emplace_back(TypeInfo("int"), "X", AccessSpecifier::AS_private);
   I.TagType = TagTypeKind::TTK_Class;
-  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, PathTo);
+  I.Parents.emplace_back(EmptySID, "F", InfoType::IT_record, "F", PathTo);
   I.VirtualParents.emplace_back(EmptySID, "G", InfoType::IT_record);
 
   I.Children.Records.emplace_back(EmptySID, "ChildStruct", InfoType::IT_record,
-                                  "X/Y/Z/r");
+                                  "X::Y::Z::r::ChildStruct", "X/Y/Z/r");
   I.Children.Functions.emplace_back();
   I.Children.Functions.back().Name = "OneFunction";
   I.Children.Enums.emplace_back();
@@ -195,11 +195,7 @@
     </p>
     <h2 id="Members">Members</h2>
     <ul>
-      <li>
-        private 
-        <a href="../../../X/Y/int.html">int</a>
-         X
-      </li>
+      <li>private int X</li>
     </ul>
     <h2 id="Records">Records</h2>
     <ul>
@@ -277,8 +273,8 @@
 
   SmallString<16> PathTo;
   llvm::sys::path::native("path/to", PathTo);
-  I.ReturnType =
-      TypeInfo(Reference(EmptySID, "float", InfoType::IT_default, PathTo));
+  I.ReturnType = TypeInfo(
+      Reference(EmptySID, "float", InfoType::IT_default, "float", PathTo));
   I.Params.emplace_back(TypeInfo("int", PathTo), "P");
   I.IsMethod = true;
   I.Parent = Reference(EmptySID, "Parent", InfoType::IT_record);
Index: clang-tools-extra/test/clang-doc/templates.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-doc/templates.cpp
@@ -0,0 +1,76 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: echo "" > %t/compile_flags.txt
+// RUN: cp "%s" "%t/test.cpp"
+// RUN: clang-doc --doxygen --executor=standalone -p %t %t/test.cpp -output=%t/docs
+// RUN: cat %t/docs/index.yaml | FileCheck %s --check-prefix=CHECK
+// RUN: rm -rf %t
+
+template<typename T, int U = 1>
+void function<bool, 0>(T x) {}
+
+template<>
+void function<bool, 0>(bool x) {}
+
+template<class... T>
+void ParamPackFunction(T... args);
+
+// CHECK: ---
+// CHECK-NEXT: USR:             '{{([0-9A-F]{40})}}'
+// CHECK-NEXT: ChildFunctions:
+// CHECK-NEXT:   - USR:             '{{([0-9A-F]{40})}}'
+// CHECK-NEXT:     Name:            'function'
+// CHECK-NEXT:     DefLocation:
+// CHECK-NEXT:       LineNumber:      10
+// CHECK-NEXT:       Filename:        '{{.*}}'
+// CHECK-NEXT:     Params:
+// CHECK-NEXT:       - Type:
+// CHECK-NEXT:           Name:            'T'
+// CHECK-NEXT:           QualName:        'T'
+// CHECK-NEXT:         Name:            'x'
+// CHECK-NEXT:     ReturnType:
+// CHECK-NEXT:       Type:
+// CHECK-NEXT:         Name:            'void'
+// CHECK-NEXT:         QualName:        'void'
+// CHECK-NEXT:     Template:
+// CHECK-NEXT:       Params:
+// CHECK-NEXT:         - Contents:        'typename T'
+// CHECK-NEXT:         - Contents:        'int U = 1'
+// CHECK-NEXT:   - USR:             '{{([0-9A-F]{40})}}'
+// CHECK-NEXT:     Name:            'function'
+// CHECK-NEXT:     DefLocation:
+// CHECK-NEXT:       LineNumber:      12
+// CHECK-NEXT:       Filename:        '{{.*}}'
+// CHECK-NEXT:     Params:
+// CHECK-NEXT:       - Type:
+// CHECK-NEXT:           Name:            '_Bool'
+// CHECK-NEXT:           QualName:        '_Bool'
+// CHECK-NEXT:         Name:            'x'
+// CHECK-NEXT:     ReturnType:
+// CHECK-NEXT:       Type:
+// CHECK-NEXT:         Name:            'void'
+// CHECK-NEXT:         QualName:        'void'
+// CHECK-NEXT:     Template:
+// CHECK-NEXT:       Specialization:
+// CHECK-NEXT:         SpecializationOf: '{{([0-9A-F]{40})}}'
+// CHECK-NEXT:         Params:
+// CHECK-NEXT:           - Contents:        'bool'
+// CHECK-NEXT:           - Contents:        '0'
+// CHECK-NEXT:  - USR:             '{{([0-9A-F]{40})}}'
+// CHECK-NEXT:    Name:            'ParamPackFunction'
+// CHECK-NEXT:    Location:
+// CHECK-NEXT:      - LineNumber:      16
+// CHECK-NEXT:        Filename:        '{{.*}}'
+// CHECK-NEXT:    Params:
+// CHECK-NEXT:      - Type:
+// CHECK-NEXT:          Name:            'T...'
+// CHECK-NEXT:          QualName:        'T...'
+// CHECK-NEXT:        Name:            'args'
+// CHECK-NEXT:    ReturnType:
+// CHECK-NEXT:      Type:
+// CHECK-NEXT:        Name:            'void'
+// CHECK-NEXT:        QualName:        'void'
+// CHECK-NEXT:    Template:
+// CHECK-NEXT:      Params:
+// CHECK-NEXT:        - Contents:        'class... T'
+// CHECK-NEXT: ...
Index: clang-tools-extra/test/clang-doc/single-file.cpp
===================================================================
--- clang-tools-extra/test/clang-doc/single-file.cpp
+++ clang-tools-extra/test/clang-doc/single-file.cpp
@@ -11,21 +11,23 @@
 void function(int x) {}
 
 // CHECK: ---
-// CHECK-NEXT: USR:             '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-NEXT: USR:             '{{([0-9A-F]{40})}}'
 // CHECK-NEXT: ChildFunctions:
-// CHECK-NEXT:   - USR:             '{{[0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]}}'
+// CHECK-NEXT:   - USR:             '{{([0-9A-F]{40})}}'
 // CHECK-NEXT:    Name:            'function'
 // CHECK-NEXT:    DefLocation:
-// CHECK-NEXT:      LineNumber:      [[@LINE-8]]
+// CHECK-NEXT:      LineNumber:      11
 // CHECK-NEXT:      Filename:        '{{.*}}
 // CHECK-NEXT:    Location:
-// CHECK-NEXT:      - LineNumber:      [[@LINE-13]]
+// CHECK-NEXT:      - LineNumber:      9
 // CHECK-NEXT:        Filename:        '{{.*}}'
 // CHECK-NEXT:    Params:
 // CHECK-NEXT:      - Type:
 // CHECK-NEXT:          Name:            'int'
+// CHECK-NEXT:          QualName:        'int'
 // CHECK-NEXT:        Name:            'x'
 // CHECK-NEXT:    ReturnType:
 // CHECK-NEXT:      Type:
 // CHECK-NEXT:        Name:            'void'
+// CHECK-NEXT:        QualName:        'void'
 // CHECK-NEXT:...
Index: clang-tools-extra/test/clang-doc/single-file-public.cpp
===================================================================
--- clang-tools-extra/test/clang-doc/single-file-public.cpp
+++ clang-tools-extra/test/clang-doc/single-file-public.cpp
@@ -28,8 +28,9 @@
 // CHECK-NEXT: Namespace:
 // CHECK-NEXT:   - Type:             Namespace
 // CHECK-NEXT:     Name:             'GlobalNamespace'
+// CHECK-NEXT:     QualName:         'GlobalNamespace'
 // CHECK-NEXT: DefLocation:
-// CHECK-NEXT:   LineNumber:      [[@LINE-20]]
+// CHECK-NEXT:   LineNumber:      12
 // CHECK-NEXT:   Filename:        '{{.*}}'
 // CHECK-NEXT: TagType:         Class
 // CHECK-NEXT: ChildFunctions:
@@ -38,22 +39,26 @@
 // CHECK-NEXT:     Namespace:
 // CHECK-NEXT:       - Type:            Record
 // CHECK-NEXT:         Name:            'Record'
+// CHECK-NEXT:         QualName:        'Record'
 // CHECK-NEXT:         USR:             '{{([0-9A-F]{40})}}'
 // CHECK-NEXT:       - Type:            Namespace
 // CHECK-NEXT:         Name:            'GlobalNamespace'
+// CHECK-NEXT:         QualName:        'GlobalNamespace'
 // CHECK-NEXT:     DefLocation:
-// CHECK-NEXT:         LineNumber:      [[@LINE-23]]
+// CHECK-NEXT:         LineNumber:      22
 // CHECK-NEXT:         Filename:        '{{.*}}'
 // CHECK-NEXT:     Location:
-// CHECK-NEXT:       - LineNumber:      [[@LINE-31]]
+// CHECK-NEXT:       - LineNumber:      17
 // CHECK-NEXT:         Filename:        '{{.*}}'
 // CHECK-NEXT:     IsMethod:        true
 // CHECK-NEXT:     Parent:
 // CHECK-NEXT:         Type:            Record
 // CHECK-NEXT:         Name:            'Record'
+// CHECK-NEXT:         QualName:        'Record'
 // CHECK-NEXT:         USR:             '{{([0-9A-F]{40})}}'
 // CHECK-NEXT:     ReturnType:
 // CHECK-NEXT:       Type:
 // CHECK-NEXT:         Name:            'void'
+// CHECK-NEXT:         QualName:        'void'
 // CHECK-NEXT:     Access:			Public
 // CHECK-NEXT: ...
Index: clang-tools-extra/clang-doc/YAMLGenerator.cpp
===================================================================
--- clang-tools-extra/clang-doc/YAMLGenerator.cpp
+++ clang-tools-extra/clang-doc/YAMLGenerator.cpp
@@ -9,6 +9,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "Generators.h"
+#include "Representation.h"
 #include "llvm/Support/YAMLTraits.h"
 #include "llvm/Support/raw_ostream.h"
 #include <optional>
@@ -24,6 +25,7 @@
 LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(EnumInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(EnumValueInfo)
+LLVM_YAML_IS_SEQUENCE_VECTOR(TemplateParamInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(TypedefInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(BaseRecordInfo)
 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<CommentInfo>)
@@ -143,6 +145,7 @@
   IO.mapOptional("ChildFunctions", I.Children.Functions);
   IO.mapOptional("ChildEnums", I.Children.Enums);
   IO.mapOptional("ChildTypedefs", I.Children.Typedefs);
+  IO.mapOptional("Template", I.Template);
 }
 
 static void CommentInfoMapping(IO &IO, CommentInfo &I) {
@@ -175,6 +178,7 @@
   static void mapping(IO &IO, Reference &Ref) {
     IO.mapOptional("Type", Ref.RefType, InfoType::IT_default);
     IO.mapOptional("Name", Ref.Name, SmallString<16>());
+    IO.mapOptional("QualName", Ref.QualName, SmallString<16>());
     IO.mapOptional("USR", Ref.USR, SymbolID());
     IO.mapOptional("Path", Ref.Path, SmallString<128>());
   }
@@ -268,6 +272,28 @@
     // the AS that shouldn't be part of the output. Even though AS_public is the
     // default in the struct, it should be displayed in the YAML output.
     IO.mapOptional("Access", I.Access, clang::AccessSpecifier::AS_none);
+    IO.mapOptional("Template", I.Template);
+  }
+};
+
+template <> struct MappingTraits<TemplateParamInfo> {
+  static void mapping(IO &IO, TemplateParamInfo &I) {
+    IO.mapOptional("Contents", I.Contents);
+  }
+};
+
+template <> struct MappingTraits<TemplateSpecializationInfo> {
+  static void mapping(IO &IO, TemplateSpecializationInfo &I) {
+    IO.mapOptional("SpecializationOf", I.SpecializationOf);
+    IO.mapOptional("Params", I.Params);
+  }
+};
+
+template <> struct MappingTraits<TemplateInfo> {
+  static void mapping(IO &IO, TemplateInfo &I) {
+    IO.mapOptional("Params", I.Params);
+    IO.mapOptional("Specialization", I.Specialization,
+                   Optional<TemplateSpecializationInfo>());
   }
 };
 
Index: clang-tools-extra/clang-doc/Serialize.cpp
===================================================================
--- clang-tools-extra/clang-doc/Serialize.cpp
+++ clang-tools-extra/clang-doc/Serialize.cpp
@@ -250,7 +250,7 @@
     IT = InfoType::IT_default;
   }
   return TypeInfo(Reference(getUSRForDecl(TD), TD->getNameAsString(), IT,
-                            getInfoRelativePath(TD)));
+                            T.getAsString(), getInfoRelativePath(TD)));
 }
 
 static bool isPublic(const clang::AccessSpecifier AS,
@@ -281,12 +281,12 @@
 // See MakeAndInsertIntoParent().
 static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
   Scope.Namespaces.emplace_back(Info.USR, Info.Name, InfoType::IT_namespace,
-                                getInfoRelativePath(Info.Namespace));
+                                Info.Name, 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));
+                             Info.Name, getInfoRelativePath(Info.Namespace));
 }
 
 static void InsertChild(ScopeChildren &Scope, EnumInfo Info) {
@@ -405,10 +405,7 @@
   for (const ParmVarDecl *P : D->parameters()) {
     FieldTypeInfo &FieldInfo = I.Params.emplace_back(
         getTypeInfoForType(P->getOriginalType()), P->getNameAsString());
-
-    if (const Expr *DefaultArg = P->getDefaultArg()) {
-      FieldInfo.DefaultValue = getSourceCode(D, DefaultArg->getSourceRange());
-    }
+    FieldInfo.DefaultValue = getSourceCode(D, P->getDefaultArgRange());
   }
 }
 
@@ -424,18 +421,19 @@
     if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
       const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
       I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
-                             InfoType::IT_record);
+                             InfoType::IT_record, B.getType().getAsString());
     } else if (const RecordDecl *P = getRecordDeclForType(B.getType()))
       I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
-                             InfoType::IT_record, getInfoRelativePath(P));
+                             InfoType::IT_record, P->getQualifiedNameAsString(),
+                             getInfoRelativePath(P));
     else
       I.Parents.emplace_back(SymbolID(), B.getType().getAsString());
   }
   for (const CXXBaseSpecifier &B : D->vbases()) {
     if (const RecordDecl *P = getRecordDeclForType(B.getType()))
-      I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
-                                    InfoType::IT_record,
-                                    getInfoRelativePath(P));
+      I.VirtualParents.emplace_back(
+          getUSRForDecl(P), P->getNameAsString(), InfoType::IT_record,
+          P->getQualifiedNameAsString(), getInfoRelativePath(P));
     else
       I.VirtualParents.emplace_back(SymbolID(), B.getType().getAsString());
   }
@@ -455,16 +453,19 @@
       } else
         Namespace = N->getNameAsString();
       Namespaces.emplace_back(getUSRForDecl(N), Namespace,
-                              InfoType::IT_namespace);
+                              InfoType::IT_namespace,
+                              N->getQualifiedNameAsString());
     } else if (const auto *N = dyn_cast<RecordDecl>(DC))
       Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
-                              InfoType::IT_record);
+                              InfoType::IT_record,
+                              N->getQualifiedNameAsString());
     else if (const auto *N = dyn_cast<FunctionDecl>(DC))
       Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
-                              InfoType::IT_function);
+                              InfoType::IT_function,
+                              N->getQualifiedNameAsString());
     else if (const auto *N = dyn_cast<EnumDecl>(DC))
       Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
-                              InfoType::IT_enum);
+                              InfoType::IT_enum, N->getQualifiedNameAsString());
   } 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
@@ -476,6 +477,30 @@
                             InfoType::IT_namespace);
 }
 
+void PopulateTemplateParameters(llvm::Optional<TemplateInfo> &TemplateInfo,
+                                const clang::Decl *D) {
+  if (const TemplateParameterList *ParamList =
+          D->getDescribedTemplateParams()) {
+    if (!TemplateInfo) {
+      TemplateInfo.emplace();
+    }
+    for (const NamedDecl *ND : *ParamList) {
+      TemplateInfo->Params.emplace_back(
+          getSourceCode(ND, ND->getSourceRange()));
+    }
+  }
+}
+
+TemplateParamInfo TemplateArgumentToInfo(const clang::Decl *D,
+                                         const TemplateArgument &Arg) {
+  // The TemplateArgument's pretty printing handles all the normal cases
+  // well enough for our requirements.
+  std::string Str;
+  llvm::raw_string_ostream Stream(Str);
+  Arg.print(PrintingPolicy(D->getLangOpts()), Stream, false);
+  return TemplateParamInfo(Str);
+}
+
 template <typename T>
 static void populateInfo(Info &I, const T *D, const FullComment *C,
                          bool &IsInAnonymousNamespace) {
@@ -508,6 +533,26 @@
                      IsInAnonymousNamespace);
   I.ReturnType = getTypeInfoForType(D->getReturnType());
   parseParameters(I, D);
+
+  PopulateTemplateParameters(I.Template, D);
+
+  // Handle function template specializations.
+  if (const FunctionTemplateSpecializationInfo *FTSI =
+          D->getTemplateSpecializationInfo()) {
+    if (!I.Template)
+      I.Template.emplace();
+    I.Template->Specialization.emplace();
+    auto &Specialization = *I.Template->Specialization;
+
+    Specialization.SpecializationOf = getUSRForDecl(FTSI->getTemplate());
+
+    // Template parameters to the specialization.
+    if (FTSI->TemplateArguments) {
+      for (const TemplateArgument &Arg : FTSI->TemplateArguments->asArray()) {
+        Specialization.Params.push_back(TemplateArgumentToInfo(D, Arg));
+      }
+    }
+  }
 }
 
 static void populateMemberTypeInfo(MemberTypeInfo &I, const FieldDecl *D) {
@@ -627,6 +672,46 @@
   }
   I->Path = getInfoRelativePath(I->Namespace);
 
+  PopulateTemplateParameters(I->Template, D);
+
+  // Full and partial specializations.
+  if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
+    if (!I->Template)
+      I->Template.emplace();
+    I->Template->Specialization.emplace();
+    auto &Specialization = *I->Template->Specialization;
+
+    // What this is a specialization of.
+    auto SpecOf = CTSD->getSpecializedTemplateOrPartial();
+    if (SpecOf.is<ClassTemplateDecl *>()) {
+      Specialization.SpecializationOf =
+          getUSRForDecl(SpecOf.get<ClassTemplateDecl *>());
+    } else if (SpecOf.is<ClassTemplatePartialSpecializationDecl *>()) {
+      Specialization.SpecializationOf =
+          getUSRForDecl(SpecOf.get<ClassTemplatePartialSpecializationDecl *>());
+    }
+
+    // Parameters to the specilization. For partial specializations, get the
+    // parameters "as written" from the ClassTemplatePartialSpecializationDecl
+    // because the non-explicit template parameters will have generated internal
+    // placeholder names rather than the names the user typed that match the
+    // template parameters.
+    if (const ClassTemplatePartialSpecializationDecl *CTPSD =
+            dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) {
+      if (const ASTTemplateArgumentListInfo *AsWritten =
+              CTPSD->getTemplateArgsAsWritten()) {
+        for (unsigned i = 0; i < AsWritten->getNumTemplateArgs(); i++) {
+          Specialization.Params.emplace_back(
+              getSourceCode(D, (*AsWritten)[i].getSourceRange()));
+        }
+      }
+    } else {
+      for (const TemplateArgument &Arg : CTSD->getTemplateArgs().asArray()) {
+        Specialization.Params.push_back(TemplateArgumentToInfo(D, Arg));
+      }
+    }
+  }
+
   // 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);
@@ -669,7 +754,8 @@
 
   SymbolID ParentUSR = getUSRForDecl(Parent);
   Func.Parent =
-      Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record};
+      Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record,
+                Parent->getQualifiedNameAsString()};
   Func.Access = D->getAccess();
 
   // Info is wrapped in its parent scope so is returned in the second position.
@@ -731,8 +817,10 @@
     return {};
 
   Enum.Scoped = D->isScoped();
-  if (D->isFixed())
-    Enum.BaseType = TypeInfo(D->getIntegerType().getAsString());
+  if (D->isFixed()) {
+    auto Name = D->getIntegerType().getAsString();
+    Enum.BaseType = TypeInfo(Name, Name);
+  }
   parseEnumerators(Enum, D);
 
   // Info is wrapped in its parent scope so is returned in the second position.
Index: clang-tools-extra/clang-doc/Representation.h
===================================================================
--- clang-tools-extra/clang-doc/Representation.h
+++ clang-tools-extra/clang-doc/Representation.h
@@ -117,13 +117,21 @@
 };
 
 struct Reference {
+  // This variant (that takes no qualified name parameter) uses the Name as the
+  // QualName (very useful in unit tests to reduce verbosity). This can't use an
+  // empty string to indicate the default because we need to accept the empty
+  // string as a valid input for the global namespace (it will have
+  // "GlobalNamespace" as the name, but an empty QualName).
   Reference(SymbolID USR = SymbolID(), StringRef Name = StringRef(),
-            InfoType IT = InfoType::IT_default, StringRef Path = StringRef())
-      : USR(USR), Name(Name), RefType(IT), Path(Path) {}
+            InfoType IT = InfoType::IT_default)
+      : USR(USR), Name(Name), QualName(Name), RefType(IT) {}
+  Reference(SymbolID USR, StringRef Name, InfoType IT, StringRef QualName,
+            StringRef Path = StringRef())
+      : USR(USR), Name(Name), QualName(QualName), RefType(IT), Path(Path) {}
 
   bool operator==(const Reference &Other) const {
-    return std::tie(USR, Name, RefType) ==
-           std::tie(Other.USR, Other.Name, Other.RefType);
+    return std::tie(USR, Name, QualName, RefType) ==
+           std::tie(Other.USR, Other.Name, QualName, Other.RefType);
   }
 
   bool mergeable(const Reference &Other);
@@ -136,7 +144,17 @@
   llvm::SmallString<16> getFileBaseName() const;
 
   SymbolID USR = SymbolID(); // Unique identifier for referenced decl
-  SmallString<16> Name;      // Name of type (possibly unresolved).
+
+  // Name of type (possibly unresolved). Not including namespaces or template
+  // parameters (so for a std::vector<int> this would be "vector"). See also
+  // QualName.
+  SmallString<16> Name;
+
+  // Full qualified name of this type, including namespaces and template
+  // parameter (for example this could be "std::vector<int>"). Contrast to
+  // Name.
+  SmallString<16> QualName;
+
   InfoType RefType = InfoType::IT_default; // Indicates the type of this
                                            // Reference (namespace, record,
                                            // function, enum, default).
@@ -169,13 +187,46 @@
   // Convenience constructor for when there is no symbol ID or info type
   // (normally used for built-in types in tests).
   TypeInfo(StringRef Name, StringRef Path = StringRef())
-      : Type(SymbolID(), Name, InfoType::IT_default, Path) {}
+      : Type(SymbolID(), Name, InfoType::IT_default, Name, Path) {}
 
   bool operator==(const TypeInfo &Other) const { return Type == Other.Type; }
 
   Reference Type; // Referenced type in this info.
 };
 
+// Represents one template parameter.
+//
+// This is a very simple serialization of the text of the source code of the
+// template parameter. It is saved in a struct so there is a place to add the
+// name and default values in the future if needed.
+struct TemplateParamInfo {
+  TemplateParamInfo() = default;
+  explicit TemplateParamInfo(StringRef Contents) : Contents(Contents) {}
+
+  // The literal contents of the code for that specifies this template parameter
+  // for this declaration. Typical values will be "class T" and
+  // "typename T = int".
+  SmallString<16> Contents;
+};
+
+struct TemplateSpecializationInfo {
+  // Indicates the declaration that this specializes.
+  SymbolID SpecializationOf;
+
+  // Template parameters applying to the specialized record/function.
+  std::vector<TemplateParamInfo> Params;
+};
+
+// Records the template information for a struct or function that is a template
+// or an explicit template specialization.
+struct TemplateInfo {
+  // May be empty for non-partial specializations.
+  std::vector<TemplateParamInfo> Params;
+
+  // Set when this is a specialization of another record/function.
+  llvm::Optional<TemplateSpecializationInfo> Specialization;
+};
+
 // Info for field types.
 struct FieldTypeInfo : public TypeInfo {
   FieldTypeInfo() = default;
@@ -317,6 +368,13 @@
   // with value 0 to be used as the default.
   // (AS_public = 0, AS_protected = 1, AS_private = 2, AS_none = 3)
   AccessSpecifier Access = AccessSpecifier::AS_public;
+
+  // Full qualified name of this function, including namespaces and template
+  // specializations.
+  SmallString<16> FullName;
+
+  // When present, this function is a template or specialization.
+  llvm::Optional<TemplateInfo> Template;
 };
 
 // TODO: Expand to allow for documenting templating, inheritance access,
@@ -332,6 +390,13 @@
   // Type of this record (struct, class, union, interface).
   TagTypeKind TagType = TagTypeKind::TTK_Struct;
 
+  // Full qualified name of this record, including namespaces and template
+  // specializations.
+  SmallString<16> FullName;
+
+  // When present, this record is a template or specialization.
+  llvm::Optional<TemplateInfo> Template;
+
   // Indicates if the record was declared using a typedef. Things like anonymous
   // structs in a typedef:
   //   typedef struct { ... } foo_t;
@@ -433,7 +498,7 @@
   Index(StringRef Name, StringRef JumpToSection)
       : Reference(SymbolID(), Name), JumpToSection(JumpToSection) {}
   Index(SymbolID USR, StringRef Name, InfoType IT, StringRef Path)
-      : Reference(USR, Name, IT, Path) {}
+      : Reference(USR, Name, IT, Name, Path) {}
   // This is used to look for a USR in a vector of Indexes using std::find
   bool operator==(const SymbolID &Other) const { return USR == Other; }
   bool operator<(const Index &Other) const;
Index: clang-tools-extra/clang-doc/Representation.cpp
===================================================================
--- clang-tools-extra/clang-doc/Representation.cpp
+++ clang-tools-extra/clang-doc/Representation.cpp
@@ -250,6 +250,8 @@
   reduceChildren(Children.Enums, std::move(Other.Children.Enums));
   reduceChildren(Children.Typedefs, std::move(Other.Children.Typedefs));
   SymbolInfo::merge(std::move(Other));
+  if (!Template)
+    Template = Other.Template;
 }
 
 void EnumInfo::merge(EnumInfo &&Other) {
@@ -274,6 +276,8 @@
   if (Params.empty())
     Params = std::move(Other.Params);
   SymbolInfo::merge(std::move(Other));
+  if (!Template)
+    Template = Other.Template;
 }
 
 void TypedefInfo::merge(TypedefInfo &&Other) {
Index: clang-tools-extra/clang-doc/BitcodeWriter.h
===================================================================
--- clang-tools-extra/clang-doc/BitcodeWriter.h
+++ clang-tools-extra/clang-doc/BitcodeWriter.h
@@ -17,7 +17,6 @@
 
 #include "Representation.h"
 #include "clang/AST/AST.h"
-#include "llvm/ADT/APSInt.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
@@ -64,6 +63,9 @@
   BI_FUNCTION_BLOCK_ID,
   BI_COMMENT_BLOCK_ID,
   BI_REFERENCE_BLOCK_ID,
+  BI_TEMPLATE_BLOCK_ID,
+  BI_TEMPLATE_SPECIALIZATION_BLOCK_ID,
+  BI_TEMPLATE_PARAM_BLOCK_ID,
   BI_TYPEDEF_BLOCK_ID,
   BI_LAST,
   BI_FIRST = BI_VERSION_BLOCK_ID
@@ -121,9 +123,12 @@
   BASE_RECORD_IS_PARENT,
   REFERENCE_USR,
   REFERENCE_NAME,
+  REFERENCE_QUAL_NAME,
   REFERENCE_TYPE,
   REFERENCE_PATH,
   REFERENCE_FIELD,
+  TEMPLATE_PARAM_CONTENTS,
+  TEMPLATE_SPECIALIZATION_OF,
   TYPEDEF_USR,
   TYPEDEF_NAME,
   TYPEDEF_DEFLOCATION,
@@ -169,6 +174,9 @@
   void emitBlock(const FieldTypeInfo &B);
   void emitBlock(const MemberTypeInfo &T);
   void emitBlock(const CommentInfo &B);
+  void emitBlock(const TemplateInfo &T);
+  void emitBlock(const TemplateSpecializationInfo &T);
+  void emitBlock(const TemplateParamInfo &T);
   void emitBlock(const Reference &B, FieldId F);
 
 private:
@@ -215,7 +223,7 @@
   void emitRecord(bool Value, RecordId ID);
   void emitRecord(int Value, RecordId ID);
   void emitRecord(unsigned Value, RecordId ID);
-  void emitRecord(llvm::APSInt Value, RecordId ID);
+  void emitRecord(const TemplateInfo &Templ);
   bool prepRecordData(RecordId ID, bool ShouldEmit = true);
 
   // Emission of appropriate abbreviation type.
Index: clang-tools-extra/clang-doc/BitcodeWriter.cpp
===================================================================
--- clang-tools-extra/clang-doc/BitcodeWriter.cpp
+++ clang-tools-extra/clang-doc/BitcodeWriter.cpp
@@ -121,7 +121,10 @@
           {BI_BASE_RECORD_BLOCK_ID, "BaseRecordBlock"},
           {BI_FUNCTION_BLOCK_ID, "FunctionBlock"},
           {BI_COMMENT_BLOCK_ID, "CommentBlock"},
-          {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"}};
+          {BI_REFERENCE_BLOCK_ID, "ReferenceBlock"},
+          {BI_TEMPLATE_BLOCK_ID, "TemplateBlock"},
+          {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, "TemplateSpecializationBlock"},
+          {BI_TEMPLATE_PARAM_BLOCK_ID, "TemplateParamBlock"}};
       assert(Inits.size() == BlockIdCount);
       for (const auto &Init : Inits)
         BlockIdNameMap[Init.first] = Init.second;
@@ -186,9 +189,12 @@
           {FUNCTION_IS_METHOD, {"IsMethod", &BoolAbbrev}},
           {REFERENCE_USR, {"USR", &SymbolIDAbbrev}},
           {REFERENCE_NAME, {"Name", &StringAbbrev}},
+          {REFERENCE_QUAL_NAME, {"QualName", &StringAbbrev}},
           {REFERENCE_TYPE, {"RefType", &IntAbbrev}},
           {REFERENCE_PATH, {"Path", &StringAbbrev}},
           {REFERENCE_FIELD, {"Field", &IntAbbrev}},
+          {TEMPLATE_PARAM_CONTENTS, {"Contents", &StringAbbrev}},
+          {TEMPLATE_SPECIALIZATION_OF, {"SpecializationOf", &SymbolIDAbbrev}},
           {TYPEDEF_USR, {"USR", &SymbolIDAbbrev}},
           {TYPEDEF_NAME, {"Name", &StringAbbrev}},
           {TYPEDEF_DEFLOCATION, {"DefLocation", &LocationAbbrev}},
@@ -244,8 +250,12 @@
           FUNCTION_ACCESS, FUNCTION_IS_METHOD}},
         // Reference Block
         {BI_REFERENCE_BLOCK_ID,
-         {REFERENCE_USR, REFERENCE_NAME, REFERENCE_TYPE, REFERENCE_PATH,
-          REFERENCE_FIELD}}};
+         {REFERENCE_USR, REFERENCE_NAME, REFERENCE_QUAL_NAME, REFERENCE_TYPE,
+          REFERENCE_PATH, REFERENCE_FIELD}},
+        // Template Blocks.
+        {BI_TEMPLATE_BLOCK_ID, {}},
+        {BI_TEMPLATE_PARAM_BLOCK_ID, {TEMPLATE_PARAM_CONTENTS}},
+        {BI_TEMPLATE_SPECIALIZATION_BLOCK_ID, {TEMPLATE_SPECIALIZATION_OF}}};
 
 // AbbreviationMap
 
@@ -378,6 +388,8 @@
   Stream.EmitRecordWithAbbrev(Abbrevs.get(ID), Record);
 }
 
+void ClangDocBitcodeWriter::emitRecord(const TemplateInfo &Templ) {}
+
 bool ClangDocBitcodeWriter::prepRecordData(RecordId ID, bool ShouldEmit) {
   assert(RecordIdNameMap[ID] && "Unknown RecordId.");
   if (!ShouldEmit)
@@ -416,6 +428,7 @@
   StreamSubBlockGuard Block(Stream, BI_REFERENCE_BLOCK_ID);
   emitRecord(R.USR, REFERENCE_USR);
   emitRecord(R.Name, REFERENCE_NAME);
+  emitRecord(R.QualName, REFERENCE_QUAL_NAME);
   emitRecord((unsigned)R.RefType, REFERENCE_TYPE);
   emitRecord(R.Path, REFERENCE_PATH);
   emitRecord((unsigned)Field, REFERENCE_FIELD);
@@ -556,6 +569,8 @@
     emitBlock(C);
   for (const auto &C : I.Children.Typedefs)
     emitBlock(C);
+  if (I.Template)
+    emitBlock(*I.Template);
 }
 
 void ClangDocBitcodeWriter::emitBlock(const BaseRecordInfo &I) {
@@ -591,6 +606,28 @@
   emitBlock(I.ReturnType);
   for (const auto &N : I.Params)
     emitBlock(N);
+  if (I.Template)
+    emitBlock(*I.Template);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const TemplateInfo &T) {
+  StreamSubBlockGuard Block(Stream, BI_TEMPLATE_BLOCK_ID);
+  for (const auto &P : T.Params)
+    emitBlock(P);
+  if (T.Specialization)
+    emitBlock(*T.Specialization);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const TemplateSpecializationInfo &T) {
+  StreamSubBlockGuard Block(Stream, BI_TEMPLATE_SPECIALIZATION_BLOCK_ID);
+  emitRecord(T.SpecializationOf, TEMPLATE_SPECIALIZATION_OF);
+  for (const auto &P : T.Params)
+    emitBlock(P);
+}
+
+void ClangDocBitcodeWriter::emitBlock(const TemplateParamInfo &T) {
+  StreamSubBlockGuard Block(Stream, BI_TEMPLATE_PARAM_BLOCK_ID);
+  emitRecord(T.Contents, TEMPLATE_PARAM_CONTENTS);
 }
 
 bool ClangDocBitcodeWriter::dispatchInfoForWrite(Info *I) {
Index: clang-tools-extra/clang-doc/BitcodeReader.cpp
===================================================================
--- clang-tools-extra/clang-doc/BitcodeReader.cpp
+++ clang-tools-extra/clang-doc/BitcodeReader.cpp
@@ -351,6 +351,8 @@
     return decodeRecord(R, I->USR, Blob);
   case REFERENCE_NAME:
     return decodeRecord(R, I->Name, Blob);
+  case REFERENCE_QUAL_NAME:
+    return decodeRecord(R, I->QualName, Blob);
   case REFERENCE_TYPE:
     return decodeRecord(R, I->RefType, Blob);
   case REFERENCE_PATH:
@@ -363,6 +365,29 @@
   }
 }
 
+llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob,
+                        TemplateInfo *I) {
+  // Currently there are no child records of TemplateInfo (only child blocks).
+  return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                 "invalid field for TemplateParamInfo");
+}
+
+llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob,
+                        TemplateSpecializationInfo *I) {
+  if (ID == TEMPLATE_SPECIALIZATION_OF)
+    return decodeRecord(R, I->SpecializationOf, Blob);
+  return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                 "invalid field for TemplateParamInfo");
+}
+
+llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob,
+                        TemplateParamInfo *I) {
+  if (ID == TEMPLATE_PARAM_CONTENTS)
+    return decodeRecord(R, I->Contents, Blob);
+  return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                 "invalid field for TemplateParamInfo");
+}
+
 template <typename T> llvm::Expected<CommentInfo *> getCommentInfo(T I) {
   return llvm::createStringError(llvm::inconvertibleErrorCode(),
                                  "invalid type cannot contain CommentInfo");
@@ -595,6 +620,45 @@
   I->Children.Functions.emplace_back(std::move(R));
 }
 
+// TemplateParam children. These go into either a TemplateInfo (for template
+// parameters) or TemplateSpecializationInfo (for the specialization's
+// parameters).
+template <typename T> void addTemplateParam(T I, TemplateParamInfo &&P) {
+  llvm::errs() << "invalid container for template parameter";
+  exit(1);
+}
+template <> void addTemplateParam(TemplateInfo *I, TemplateParamInfo &&P) {
+  I->Params.emplace_back(std::move(P));
+}
+template <>
+void addTemplateParam(TemplateSpecializationInfo *I, TemplateParamInfo &&P) {
+  I->Params.emplace_back(std::move(P));
+}
+
+// Template info. These apply to either records or functions.
+template <typename T> void addTemplate(T I, TemplateInfo &&P) {
+  llvm::errs() << "invalid container for template info";
+  exit(1);
+}
+template <> void addTemplate(RecordInfo *I, TemplateInfo &&P) {
+  I->Template.emplace(std::move(P));
+}
+template <> void addTemplate(FunctionInfo *I, TemplateInfo &&P) {
+  I->Template.emplace(std::move(P));
+}
+
+// Template specializations go only into template records.
+template <typename T>
+void addTemplateSpecialization(T I, TemplateSpecializationInfo &&TSI) {
+  llvm::errs() << "invalid container for template specialization info";
+  exit(1);
+}
+template <>
+void addTemplateSpecialization(TemplateInfo *I,
+                               TemplateSpecializationInfo &&TSI) {
+  I->Specialization.emplace(std::move(TSI));
+}
+
 // Read records from bitcode into a given info.
 template <typename T>
 llvm::Error ClangDocBitcodeReader::readRecord(unsigned ID, T I) {
@@ -719,6 +783,27 @@
     addChild(I, std::move(EV));
     return llvm::Error::success();
   }
+  case BI_TEMPLATE_BLOCK_ID: {
+    TemplateInfo TI;
+    if (auto Err = readBlock(ID, &TI))
+      return Err;
+    addTemplate(I, std::move(TI));
+    return llvm::Error::success();
+  }
+  case BI_TEMPLATE_SPECIALIZATION_BLOCK_ID: {
+    TemplateSpecializationInfo TSI;
+    if (auto Err = readBlock(ID, &TSI))
+      return Err;
+    addTemplateSpecialization(I, std::move(TSI));
+    return llvm::Error::success();
+  }
+  case BI_TEMPLATE_PARAM_BLOCK_ID: {
+    TemplateParamInfo TPI;
+    if (auto Err = readBlock(ID, &TPI))
+      return Err;
+    addTemplateParam(I, std::move(TPI));
+    return llvm::Error::success();
+  }
   case BI_TYPEDEF_BLOCK_ID: {
     TypedefInfo TI;
     if (auto Err = readBlock(ID, &TI))
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to