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 llvm::Expected 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 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 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 +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 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)) 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/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 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"). 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 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 Params; + + // Set when this is a specialization of another record/function. + llvm::Optional 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 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 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/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(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()) { 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(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(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(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(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, + 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 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(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()) { + Specialization.SpecializationOf = + getUSRForDecl(SpecOf.get()); + } else if (SpecOf.is()) { + Specialization.SpecializationOf = + getUSRForDecl(SpecOf.get()); + } + + // 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(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(*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/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) @@ -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 { + static void mapping(IO &IO, TemplateParamInfo &I) { + IO.mapOptional("Contents", I.Contents); + } +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, TemplateSpecializationInfo &I) { + IO.mapOptional("SpecializationOf", I.SpecializationOf); + IO.mapOptional("Params", I.Params); + } +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, TemplateInfo &I) { + IO.mapOptional("Params", I.Params); + IO.mapOptional("Specialization", I.Specialization, + Optional()); } };