brettw updated this revision to Diff 479772.

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

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"
 
@@ -23,6 +24,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>)
@@ -142,6 +144,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) {
@@ -174,6 +177,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>());
   }
@@ -267,6 +271,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
@@ -239,7 +239,7 @@
 TypeInfo getTypeInfoForType(const QualType &T) {
   const TagDecl *TD = getTagDeclForType(T);
   if (!TD)
-    return TypeInfo(Reference(SymbolID(), T.getAsString()));
+    return TypeInfo(Reference(SymbolID(), T.getAsString(), T.getAsString()));
 
   InfoType IT;
   if (dyn_cast<EnumDecl>(TD)) {
@@ -249,7 +249,7 @@
   } else {
     IT = InfoType::IT_default;
   }
-  return TypeInfo(Reference(getUSRForDecl(TD), TD->getNameAsString(), IT,
+  return TypeInfo(Reference(getUSRForDecl(TD), TD->getNameAsString(), T.getAsString(), IT,
                             getInfoRelativePath(TD)));
 }
 
@@ -280,12 +280,12 @@
 //
 // See MakeAndInsertIntoParent().
 static void InsertChild(ScopeChildren &Scope, const NamespaceInfo &Info) {
-  Scope.Namespaces.emplace_back(Info.USR, Info.Name, InfoType::IT_namespace,
+  Scope.Namespaces.emplace_back(Info.USR, Info.Name, 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,
+  Scope.Records.emplace_back(Info.USR, Info.Name, Info.Name, InfoType::IT_record,
                              getInfoRelativePath(Info.Namespace));
 }
 
@@ -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,9 +421,10 @@
     if (const auto *Ty = B.getType()->getAs<TemplateSpecializationType>()) {
       const TemplateDecl *D = Ty->getTemplateName().getAsTemplateDecl();
       I.Parents.emplace_back(getUSRForDecl(D), B.getType().getAsString(),
+                              B.getType().getAsString(),
                              InfoType::IT_record);
     } else if (const RecordDecl *P = getRecordDeclForType(B.getType()))
-      I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
+      I.Parents.emplace_back(getUSRForDecl(P), P->getNameAsString(), P->getQualifiedNameAsString(),
                              InfoType::IT_record, getInfoRelativePath(P));
     else
       I.Parents.emplace_back(SymbolID(), B.getType().getAsString());
@@ -434,6 +432,7 @@
   for (const CXXBaseSpecifier &B : D->vbases()) {
     if (const RecordDecl *P = getRecordDeclForType(B.getType()))
       I.VirtualParents.emplace_back(getUSRForDecl(P), P->getNameAsString(),
+                                P->getQualifiedNameAsString(),
                                     InfoType::IT_record,
                                     getInfoRelativePath(P));
     else
@@ -454,16 +453,16 @@
         IsInAnonymousNamespace = true;
       } else
         Namespace = N->getNameAsString();
-      Namespaces.emplace_back(getUSRForDecl(N), Namespace,
+      Namespaces.emplace_back(getUSRForDecl(N), Namespace, N->getQualifiedNameAsString(),
                               InfoType::IT_namespace);
     } else if (const auto *N = dyn_cast<RecordDecl>(DC))
-      Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
+      Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), N->getQualifiedNameAsString(),
                               InfoType::IT_record);
     else if (const auto *N = dyn_cast<FunctionDecl>(DC))
-      Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
+      Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), N->getQualifiedNameAsString(),
                               InfoType::IT_function);
     else if (const auto *N = dyn_cast<EnumDecl>(DC))
-      Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(),
+      Namespaces.emplace_back(getUSRForDecl(N), N->getNameAsString(), N->getQualifiedNameAsString(),
                               InfoType::IT_enum);
   } while ((DC = DC->getParent()));
   // The global namespace should be added to the list of namespaces if the decl
@@ -472,10 +471,34 @@
   // record because that record matches the previous condition mentioned.
   if ((Namespaces.empty() && isa<RecordDecl>(D)) ||
       (!Namespaces.empty() && Namespaces.back().RefType == InfoType::IT_record))
-    Namespaces.emplace_back(SymbolID(), "GlobalNamespace",
+    Namespaces.emplace_back(SymbolID(), "GlobalNamespace", "",
                             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 +531,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 +670,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 +752,7 @@
 
   SymbolID ParentUSR = getUSRForDecl(Parent);
   Func.Parent =
-      Reference{ParentUSR, Parent->getNameAsString(), InfoType::IT_record};
+      Reference{ParentUSR, Parent->getNameAsString(), Parent->getQualifiedNameAsString(), InfoType::IT_record};
   Func.Access = D->getAccess();
 
   // Info is wrapped in its parent scope so is returned in the second position.
@@ -731,8 +814,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,12 +117,13 @@
 
 struct Reference {
   Reference(SymbolID USR = SymbolID(), StringRef Name = StringRef(),
+            StringRef QualName = StringRef(),
             InfoType IT = InfoType::IT_default, StringRef Path = StringRef())
-      : USR(USR), Name(Name), RefType(IT), Path(Path) {}
+      : 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);
@@ -135,7 +136,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).
@@ -163,18 +174,58 @@
 // A base struct for TypeInfos
 struct TypeInfo {
   TypeInfo() = default;
-  TypeInfo(const Reference &R) : Type(R) {}
+  TypeInfo(const Reference &R)
+      : Type(R) {}
 
   // 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, Name, InfoType::IT_default, 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. Representing the full range of template parameter kinds
+// is quite involved. Currently the documentation uses of this data just involve
+// echoing it back to reconstruct the declaration of the class or function, so
+// the full contents is sufficient.
+//
+// It is separated into this separate class so that other attributes can be
+// added here as needed.
+struct TemplateParamInfo {
+  TemplateParamInfo() = default;
+  explicit TemplateParamInfo(StringRef Contents) : Contents(Contents) {}
+
+  // The literal contents of the code for everything that specifies this
+  // template parameter. This will include all components, so for a template
+  // declaration it could be "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;
+};
+
+// This struct will be a member of the record/function that is the template or
+// 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;
@@ -316,6 +367,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,
@@ -331,6 +389,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;
@@ -430,9 +495,9 @@
   Index() = default;
   Index(StringRef Name) : Reference(SymbolID(), Name) {}
   Index(StringRef Name, StringRef JumpToSection)
-      : Reference(SymbolID(), Name), JumpToSection(JumpToSection) {}
+      : Reference(SymbolID(), Name, Name), JumpToSection(JumpToSection) {}
   Index(SymbolID USR, StringRef Name, InfoType IT, StringRef Path)
-      : Reference(USR, Name, IT, Path) {}
+      : Reference(USR, Name, Name, IT, 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
@@ -350,6 +350,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:
@@ -362,6 +364,35 @@
   }
 }
 
+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) {
+  switch (ID) {
+  case TEMPLATE_SPECIALIZATION_OF:
+    return decodeRecord(R, I->SpecializationOf, Blob);
+  default:
+    return llvm::createStringError(llvm::inconvertibleErrorCode(),
+                                   "invalid field for TemplateParamInfo");
+  }
+}
+
+llvm::Error parseRecord(const Record &R, unsigned ID, llvm::StringRef Blob,
+                        TemplateParamInfo *I) {
+  switch (ID) {
+  case TEMPLATE_PARAM_CONTENTS:
+    return decodeRecord(R, I->Contents, Blob);
+  default:
+    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");
@@ -594,6 +625,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) {
@@ -718,6 +788,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