diff --git a/include/mrdocs/Metadata/Template.hpp b/include/mrdocs/Metadata/Template.hpp index ec802884d..4126ba558 100644 --- a/include/mrdocs/Metadata/Template.hpp +++ b/include/mrdocs/Metadata/Template.hpp @@ -175,7 +175,7 @@ enum class TParamKind : int Type = 1, // for bitstream // template non-type parameter, e.g. "int N" or "auto N" NonType, - // template template parameter, e.g. "template typename T" + // Template-template parameter, e.g. "template typename T" Template }; @@ -235,7 +235,7 @@ tag_invoke( template -struct IsTParam : TParam +struct TParamCommonBase : TParam { static constexpr TParamKind kind_id = K; @@ -245,7 +245,7 @@ struct IsTParam : TParam protected: constexpr - IsTParam() noexcept + TParamCommonBase() noexcept : TParam(K) { } @@ -271,7 +271,7 @@ tag_invoke( } struct TypeTParam - : IsTParam + : TParamCommonBase { /** Keyword (class/typename) the parameter uses */ TParamKeyKind KeyKind = TParamKeyKind::Class; @@ -281,14 +281,14 @@ struct TypeTParam }; struct NonTypeTParam - : IsTParam + : TParamCommonBase { /** Type of the non-type template parameter */ std::unique_ptr Type; }; struct TemplateTParam - : IsTParam + : TParamCommonBase { /** Template parameters for the template template parameter */ std::vector> Params; diff --git a/src/lib/AST/ASTVisitor.cpp b/src/lib/AST/ASTVisitor.cpp index 8aecf5e4a..5eb54512b 100644 --- a/src/lib/AST/ASTVisitor.cpp +++ b/src/lib/AST/ASTVisitor.cpp @@ -950,6 +950,8 @@ populate( FunctionInfo& I, DeclTy* D) { + MRDOCS_SYMBOL_TRACE(D, context_); + // D is the templated declaration if FTD is non-null if (D->isFunctionTemplateSpecialization()) { @@ -987,11 +989,12 @@ populate( } } - // KRYSTIAN TODO: move other extraction that requires - // a valid function type here - if (auto FT = getDeclaratorType(D); ! FT.isNull()) + // Get the function type and extract information that comes from the type + if (auto FT = getDeclaratorType(D); !FT.isNull()) { + MRDOCS_SYMBOL_TRACE(FT, context_); const auto* FPT = FT->template getAs(); + MRDOCS_SYMBOL_TRACE(FPT, context_); populate(I.Noexcept, FPT); I.HasTrailingReturn |= FPT->hasTrailingReturn(); } @@ -999,79 +1002,78 @@ populate( // // FunctionDecl // - I.OverloadedOperator = toOperatorKind( - D->getOverloadedOperator()); - I.IsVariadic |= D->isVariadic(); - I.IsDefaulted |= D->isDefaulted(); - I.IsExplicitlyDefaulted |= D->isExplicitlyDefaulted(); - I.IsDeleted |= D->isDeleted(); - I.IsDeletedAsWritten |= D->isDeletedAsWritten(); - I.IsNoReturn |= D->isNoReturn(); - // subsumes D->hasAttr() - // subsumes D->hasAttr() - // subsumes D->hasAttr() - // subsumes D->getType()->getAs()->getNoReturnAttr() - I.HasOverrideAttr |= D->template hasAttr(); - - if (ConstexprSpecKind const CSK = D->getConstexprKind(); + FunctionDecl const* FD = D; + I.OverloadedOperator = toOperatorKind(FD->getOverloadedOperator()); + I.IsVariadic |= FD->isVariadic(); + I.IsDefaulted |= FD->isDefaulted(); + I.IsExplicitlyDefaulted |= FD->isExplicitlyDefaulted(); + I.IsDeleted |= FD->isDeleted(); + I.IsDeletedAsWritten |= FD->isDeletedAsWritten(); + I.IsNoReturn |= FD->isNoReturn(); + I.HasOverrideAttr |= FD->template hasAttr(); + + if (ConstexprSpecKind const CSK = FD->getConstexprKind(); CSK != ConstexprSpecKind::Unspecified) { I.Constexpr = toConstexprKind(CSK); } - if (StorageClass const SC = D->getStorageClass()) + if (StorageClass const SC = FD->getStorageClass()) { I.StorageClass = toStorageClassKind(SC); } - I.IsNodiscard |= D->template hasAttr(); - I.IsExplicitObjectMemberFunction |= D->hasCXXExplicitFunctionObjectParameter(); + I.IsNodiscard |= FD->template hasAttr(); + I.IsExplicitObjectMemberFunction |= FD->hasCXXExplicitFunctionObjectParameter(); + // // CXXMethodDecl // if constexpr(std::derived_from) { - I.IsVirtual |= D->isVirtual(); - I.IsVirtualAsWritten |= D->isVirtualAsWritten(); - I.IsPure |= D->isPureVirtual(); - I.IsConst |= D->isConst(); - I.IsVolatile |= D->isVolatile(); - I.RefQualifier = toReferenceKind(D->getRefQualifier()); - I.IsFinal |= D->template hasAttr(); - //D->isCopyAssignmentOperator() - //D->isMoveAssignmentOperator() - //D->isOverloadedOperator(); - //D->isStaticOverloadedOperator(); - } + CXXMethodDecl const* MD = D; + I.IsVirtual |= MD->isVirtual(); + I.IsVirtualAsWritten |= MD->isVirtualAsWritten(); + I.IsPure |= MD->isPureVirtual(); + I.IsConst |= MD->isConst(); + I.IsVolatile |= MD->isVolatile(); + I.RefQualifier = toReferenceKind(MD->getRefQualifier()); + I.IsFinal |= MD->template hasAttr(); + //MD->isCopyAssignmentOperator() + //MD->isMoveAssignmentOperator() + //MD->isOverloadedOperator(); + //MD->isStaticOverloadedOperator(); - // - // CXXDestructorDecl - // - // if constexpr(std::derived_from) - // { - // } + // + // CXXDestructorDecl + // + // if constexpr(std::derived_from) + // { + // } - // - // CXXConstructorDecl - // - if constexpr(std::derived_from) - { - populate(I.Explicit, D->getExplicitSpecifier()); - } + // + // CXXConstructorDecl + // + if constexpr(std::derived_from) + { + populate(I.Explicit, D->getExplicitSpecifier()); + } - // - // CXXConversionDecl - // - if constexpr(std::derived_from) - { - populate(I.Explicit, D->getExplicitSpecifier()); + // + // CXXConversionDecl + // + if constexpr(std::derived_from) + { + populate(I.Explicit, D->getExplicitSpecifier()); + } } - ArrayRef const params = D->parameters(); + ArrayRef const params = FD->parameters(); I.Params.resize(params.size()); for (std::size_t i = 0; i < params.size(); ++i) { ParmVarDecl const* P = params[i]; + MRDOCS_SYMBOL_TRACE(P, context_); Param& param = I.Params[i]; if (param.Name.empty()) @@ -1099,16 +1101,16 @@ populate( } } - I.Class = toFunctionClass(D->getDeclKind()); + I.Class = toFunctionClass(FD->getDeclKind()); // extract the return type in direct dependency mode // if it contains a placeholder type which is // deduceded as a local class type - QualType const RT = D->getReturnType(); + QualType const RT = FD->getReturnType(); MRDOCS_SYMBOL_TRACE(RT, context_); I.ReturnType = toTypeInfo(RT); - if (auto* TRC = D->getTrailingRequiresClause()) + if (auto* TRC = FD->getTrailingRequiresClause()) { populate(I.Requires, TRC); } @@ -1120,8 +1122,9 @@ void ASTVisitor:: populate(FunctionInfo& I, FunctionTemplateDecl* D) { - populate(I.Template, D->getTemplatedDecl(), D); - populate(I, D->getTemplatedDecl()); + FunctionDecl* TD = D->getTemplatedDecl(); + populate(I.Template, TD, D); + populate(I, TD); } void @@ -1375,7 +1378,8 @@ ASTVisitor:: populate(TemplateInfo& Template, DeclTy*, TemplateDeclTy* TD) { MRDOCS_ASSERT(TD); - populate(Template, TD->getTemplateParameters()); + TemplateParameterList const* TPL = TD->getTemplateParameters(); + populate(Template, TPL); } template CXXRecordDeclTy> @@ -1592,18 +1596,25 @@ populate( { I = std::make_unique(); } - auto* R = dynamic_cast(I.get()); - if(R->Params.empty()) + TemplateTemplateParmDecl const* TTPD = cast(P); + MRDOCS_CHECK_OR(TTPD); + TemplateParameterList const* TPL = TTPD->getTemplateParameters(); + MRDOCS_CHECK_OR(TPL); + auto* Result = dynamic_cast(I.get()); + if (Result->Params.size() < TPL->size()) { - for (NamedDecl const* NP: *P->getTemplateParameters()) - { - populate(R->Params.emplace_back(), NP); - } + Result->Params.resize(TPL->size()); } - if (P->hasDefaultArgument() && !R->Default) + for (std::size_t i = 0; i < TPL->size(); ++i) { - R->Default = toTArg( - P->getDefaultArgument().getArgument()); + NamedDecl const* TP = TPL->getParam(i); + populate(Result->Params[i], TP); + } + if (TTPD->hasDefaultArgument() && !Result->Default) + { + TemplateArgumentLoc const& TAL = TTPD->getDefaultArgument(); + TemplateArgument const& TA = TAL.getArgument(); + Result->Default = toTArg(TA); } return; } @@ -1634,9 +1645,10 @@ populate( { TI.Params.resize(TPL->size()); } - for (std::size_t I = 0; I < TPL->size(); ++I) + for (std::size_t i = 0; i < TPL->size(); ++i) { - populate(TI.Params[I], TPL->getParam(I)); + NamedDecl const* P = TPL->getParam(i); + populate(TI.Params[i], P); } if (auto* RC = TPL->getRequiresClause()) { diff --git a/src/lib/AST/ASTVisitor.hpp b/src/lib/AST/ASTVisitor.hpp index 18810c99c..18da626a6 100644 --- a/src/lib/AST/ASTVisitor.hpp +++ b/src/lib/AST/ASTVisitor.hpp @@ -482,7 +482,8 @@ class ASTVisitor { Template.emplace(); } - populate(*Template, D, VTD); + TemplateInfo &TI = *Template; + populate(TI, D, VTD); } void diff --git a/src/lib/AST/ClangHelpers.hpp b/src/lib/AST/ClangHelpers.hpp index a18054594..835245c43 100644 --- a/src/lib/AST/ClangHelpers.hpp +++ b/src/lib/AST/ClangHelpers.hpp @@ -914,6 +914,20 @@ namespace detail { { printTraceName(&D, C, symbol_name); } + + template + void + printTraceName(std::optional const& D, ASTContext const& C, SmallString<256>& symbol_name) + { + if (D) + { + printTraceName(*D, C, symbol_name); + } + else + { + symbol_name += ""; + } + } } // namespace detail # define MRDOCS_SYMBOL_TRACE_MERGE_(a, b) a##b diff --git a/src/lib/AST/TerminalTypeVisitor.hpp b/src/lib/AST/TerminalTypeVisitor.hpp index d131ef05d..9e52ea576 100644 --- a/src/lib/AST/TerminalTypeVisitor.hpp +++ b/src/lib/AST/TerminalTypeVisitor.hpp @@ -615,22 +615,27 @@ class TerminalTypeVisitor // Template names can also refer to function templates, // C++0x template aliases, etc... TemplateName const TN = T->getTemplateName(); + MRDOCS_SYMBOL_TRACE(TN, Visitor_.context_); MRDOCS_ASSERT(! TN.isNull()); // The list of template parameters and a reference to // the templated scoped declaration NamedDecl* D = TN.getAsTemplateDecl(); + MRDOCS_SYMBOL_TRACE(TN, Visitor_.context_); if (!T->isTypeAlias()) { auto* CT = T->getCanonicalTypeInternal().getTypePtrOrNull(); + MRDOCS_SYMBOL_TRACE(CT, Visitor_.context_); if (auto* ICT = dyn_cast_or_null(CT)) { D = ICT->getDecl(); + MRDOCS_SYMBOL_TRACE(D, Visitor_.context_); } else if (auto* RT = dyn_cast_or_null(CT)) { D = RT->getDecl(); + MRDOCS_SYMBOL_TRACE(D, Visitor_.context_); } } diff --git a/src/lib/AST/TypeInfoBuilder.cpp b/src/lib/AST/TypeInfoBuilder.cpp index 6341c5342..73832be14 100644 --- a/src/lib/AST/TypeInfoBuilder.cpp +++ b/src/lib/AST/TypeInfoBuilder.cpp @@ -200,8 +200,9 @@ buildTerminal( unsigned quals, bool pack) { - MRDOCS_SYMBOL_TRACE(D, getASTVisitor().context_); MRDOCS_SYMBOL_TRACE(NNS, getASTVisitor().context_); + MRDOCS_SYMBOL_TRACE(D, getASTVisitor().context_); + MRDOCS_SYMBOL_TRACE(TArgs, getASTVisitor().context_); // Look for the Info type. If this is a template specialization, // we look for the Info of the specialized record. @@ -209,10 +210,6 @@ buildTerminal( MRDOCS_SYMBOL_TRACE(ID, getASTVisitor().context_); Info const* I = getASTVisitor().findOrTraverse(const_cast(ID)); - if (!I) - { - return; - } auto TI = std::make_unique(); TI->CVQualifiers = toQualifierKind(quals); @@ -223,7 +220,10 @@ buildTerminal( { Name->Name = II->getName(); } - Name->id = I->id; + if (I) + { + Name->id = I->id; + } if(NNS) { Name->Prefix = getASTVisitor().toNameInfo(NNS); diff --git a/test-files/golden-tests/metadata/function-template-template.adoc b/test-files/golden-tests/metadata/function-template-template.adoc new file mode 100644 index 000000000..5c2e4fb85 --- /dev/null +++ b/test-files/golden-tests/metadata/function-template-template.adoc @@ -0,0 +1,36 @@ += Reference +:mrdocs: + +[#index] +== Global namespace + + +=== Functions + +[cols=1] +|=== +| Name + +| <> +|=== + +[#f] +== f + + +=== Synopsis + + +Declared in `<function‐template‐template.cpp>` + +[source,cpp,subs="verbatim,replacements,macros,-callouts"] +---- +template<template<class...> typename ListType> +constexpr +void +f(ListType<int> param); +---- + + + +[.small]#Created with https://www.mrdocs.com[MrDocs]# diff --git a/test-files/golden-tests/metadata/function-template-template.cpp b/test-files/golden-tests/metadata/function-template-template.cpp new file mode 100644 index 000000000..8411ea759 --- /dev/null +++ b/test-files/golden-tests/metadata/function-template-template.cpp @@ -0,0 +1,4 @@ +template