* \brief Get a usable name from a template parameter pack. * * A template parameter pack, args, as in: * \code template auto forward(F f, Types &&...args) { f(args...); } forward(f,1, 2,3); * \endcode * * gets expanded by clang as * \code f(args, args, args); * \endcode * * which would obviously not compile. For clang AST dump it is the right thing. For
| 1101 | * The expected type for \c T currently is \c ValueDecl or \c VarDecl. |
| 1102 | */ |
| 1103 | static std::string GetTemplateParameterPackArgumentName(std::string_view name, const Decl* decl) |
| 1104 | { |
| 1105 | if(const auto* parmVarDecl = dyn_cast_or_null<ParmVarDecl>(decl)) { |
| 1106 | if(const auto& originalType = parmVarDecl->getOriginalType(); not originalType.isNull()) { |
| 1107 | if(const auto* substTemplateTypeParmType = GetSubstTemplateTypeParmType(originalType.getTypePtrOrNull()); |
| 1108 | substTemplateTypeParmType and substTemplateTypeParmType->getReplacedParameter()->isParameterPack()) { |
| 1109 | return StrCat(BuildInternalVarName(name), parmVarDecl->getFunctionScopeIndex()); |
| 1110 | |
| 1111 | } else if(const auto* fd = parmVarDecl->getParentFunctionOrMethod()) { |
| 1112 | // Get the primary template, if possible and check whether its parameters contain a parameter pack |
| 1113 | if(const auto* primTmpl = dyn_cast_or_null<FunctionDecl>(fd)->getPrimaryTemplate(); |
| 1114 | primTmpl and primTmpl->getTemplateParameters()->hasParameterPack()) { |
| 1115 | // if so, then search for the matching parameter name. |
| 1116 | for(const auto* pa : primTmpl->getTemplatedDecl()->parameters()) { |
| 1117 | // if one is found we suffix it with its function scope index |
| 1118 | if(pa->isParameterPack() and (parmVarDecl->getNameAsString() == pa->getNameAsString())) { |
| 1119 | return StrCat(BuildInternalVarName(name), parmVarDecl->getFunctionScopeIndex()); |
| 1120 | } |
| 1121 | } |
| 1122 | } |
| 1123 | } |
| 1124 | } |
| 1125 | } else if(const auto* varDecl = dyn_cast_or_null<VarDecl>(decl)) { |
| 1126 | // If it is an init-capture in C++2a p0780 brings "Allow pack expansion in lambda init-capture". We |
| 1127 | // need to figure out, whether the initializer for this \c VarDecl comes from a parameter pack. If |
| 1128 | // so, then we use this ParmVarDecl to get the index. |
| 1129 | if(varDecl->isInitCapture()) { |
| 1130 | if(const auto* drefExpr = FindVarDeclRef(varDecl->getInit())) { |
| 1131 | if(const auto* parmVarDecl = dyn_cast_or_null<ParmVarDecl>(drefExpr->getDecl())) { |
| 1132 | return GetTemplateParameterPackArgumentName(name, parmVarDecl); |
| 1133 | } |
| 1134 | } |
| 1135 | } |
| 1136 | } |
| 1137 | |
| 1138 | return std::string{name}; |
| 1139 | } |
| 1140 | //----------------------------------------------------------------------------- |
| 1141 | |
| 1142 | #if IS_CLANG_NEWER_THAN(20) |
no test coverage detected