From b7d1da8741e22567ed28826130e70805aa2e3e43 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 17 Dec 2024 16:49:56 +0100 Subject: [PATCH] C++: Introduce a new base class for template parameters This will enable us to support non-type template parameters, which we currently do not support, and error template parameters, which might become relevant in the `build-mode: none` context. --- .../2024-12-17-template-parameter-base.md | 4 ++ .../2024-12-17-template-parameter.md | 4 ++ cpp/ql/lib/semmle/code/cpp/Class.qll | 6 +-- cpp/ql/lib/semmle/code/cpp/Declaration.qll | 2 +- cpp/ql/lib/semmle/code/cpp/Print.qll | 2 +- cpp/ql/lib/semmle/code/cpp/Type.qll | 32 +++++++++++--- .../semmle/code/cpp/commons/Dependency.qll | 2 +- .../semmle/code/cpp/dataflow/ExternalFlow.qll | 4 +- .../code/cpp/internal/QualifiedName.qll | 6 +-- .../Unused Entities/UnusedLocals.ql | 2 +- .../Arithmetic/PointlessSelfComparison.qll | 2 +- .../src/Likely Bugs/ReturnConstTypeCommon.qll | 2 +- cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql | 2 +- .../examples/expressions/PrintAST.expected | 4 +- .../library-tests/declaration/declaration.cpp | 4 +- .../library-tests/ir/ir/PrintAST.expected | 44 +++++++++---------- .../proxy_class/locations.expected | 2 +- .../library-tests/proxy_class/locations.ql | 2 +- 18 files changed, 78 insertions(+), 48 deletions(-) create mode 100644 cpp/ql/lib/change-notes/2024-12-17-template-parameter-base.md create mode 100644 cpp/ql/lib/change-notes/2024-12-17-template-parameter.md diff --git a/cpp/ql/lib/change-notes/2024-12-17-template-parameter-base.md b/cpp/ql/lib/change-notes/2024-12-17-template-parameter-base.md new file mode 100644 index 000000000000..6fec6d5f4f55 --- /dev/null +++ b/cpp/ql/lib/change-notes/2024-12-17-template-parameter-base.md @@ -0,0 +1,4 @@ +--- +category: feature +--- +* A new class `TemplateParameterBase` was introduced, which represents C++ non-type template parameters, type template parameters, and template template parameters. \ No newline at end of file diff --git a/cpp/ql/lib/change-notes/2024-12-17-template-parameter.md b/cpp/ql/lib/change-notes/2024-12-17-template-parameter.md new file mode 100644 index 000000000000..0ac7085b371b --- /dev/null +++ b/cpp/ql/lib/change-notes/2024-12-17-template-parameter.md @@ -0,0 +1,4 @@ +--- +category: deprecated +--- +* The `TemplateParameter` class, representing C++ type template parameters has been deprecated. Use `TypeTemplateParameter` instead. diff --git a/cpp/ql/lib/semmle/code/cpp/Class.qll b/cpp/ql/lib/semmle/code/cpp/Class.qll index 44863a6645be..42c46e94fe66 100644 --- a/cpp/ql/lib/semmle/code/cpp/Class.qll +++ b/cpp/ql/lib/semmle/code/cpp/Class.qll @@ -952,7 +952,7 @@ class ClassTemplateSpecialization extends Class { result.getNamespace() = this.getNamespace() and // It is distinguished by the fact that each of its template arguments // is a distinct template parameter. - count(TemplateParameter tp | tp = result.getATemplateArgument()) = + count(TemplateParameterBase tp | tp = result.getATemplateArgument()) = count(int i | exists(result.getTemplateArgument(i))) } @@ -1006,7 +1006,7 @@ private predicate isPartialClassTemplateSpecialization(Class c) { */ exists(Type ta | ta = c.getATemplateArgument() and ta.involvesTemplateParameter()) and - count(TemplateParameter tp | tp = c.getATemplateArgument()) != + count(TemplateParameterBase tp | tp = c.getATemplateArgument()) != count(int i | exists(c.getTemplateArgument(i))) } @@ -1091,7 +1091,7 @@ class ProxyClass extends UserType { override Location getLocation() { result = this.getTemplateParameter().getDefinitionLocation() } /** Gets the template parameter for which this is the proxy class. */ - TemplateParameter getTemplateParameter() { + TypeTemplateParameter getTemplateParameter() { is_proxy_class_for(underlyingElement(this), unresolveElement(result)) } } diff --git a/cpp/ql/lib/semmle/code/cpp/Declaration.qll b/cpp/ql/lib/semmle/code/cpp/Declaration.qll index 61fe2018026a..60d391b65971 100644 --- a/cpp/ql/lib/semmle/code/cpp/Declaration.qll +++ b/cpp/ql/lib/semmle/code/cpp/Declaration.qll @@ -187,7 +187,7 @@ class Declaration extends Locatable, @declaration { this instanceof Parameter or this instanceof ProxyClass or this instanceof LocalVariable or - this instanceof TemplateParameter or + this instanceof TypeTemplateParameter or this.(UserType).isLocal() ) } diff --git a/cpp/ql/lib/semmle/code/cpp/Print.qll b/cpp/ql/lib/semmle/code/cpp/Print.qll index 28a18bb0ac41..5aafe1c2b65b 100644 --- a/cpp/ql/lib/semmle/code/cpp/Print.qll +++ b/cpp/ql/lib/semmle/code/cpp/Print.qll @@ -33,7 +33,7 @@ private string getScopePrefix(Declaration decl) { result = "(" + type.getEnclosingFunction().(DumpFunction).getIdentityString() + ")::" ) or - decl instanceof TemplateParameter and result = "" + decl instanceof TypeTemplateParameter and result = "" } /** diff --git a/cpp/ql/lib/semmle/code/cpp/Type.qll b/cpp/ql/lib/semmle/code/cpp/Type.qll index b67b6502afe2..0853f0d4db20 100644 --- a/cpp/ql/lib/semmle/code/cpp/Type.qll +++ b/cpp/ql/lib/semmle/code/cpp/Type.qll @@ -1666,6 +1666,28 @@ class RoutineType extends Type, @routinetype { } } +abstract private class TemplateParameterImpl extends Locatable { + override string getAPrimaryQlClass() { result = "TemplateParameterImpl" } +} + +/** + * A C++ template parameter. + * + * In the example below, `T` and `I` are template parameters: + * ``` + * template + * class C { }; + * ``` + */ +final class TemplateParameterBase = TemplateParameterImpl; + +/** + * A C++ `typename` (or `class`) template parameter. + * + * DEPRECATED: Use `TypeTemplateParameter` instead. + */ +deprecated class TemplateParameter = TypeTemplateParameter; + /** * A C++ `typename` (or `class`) template parameter. * @@ -1675,12 +1697,12 @@ class RoutineType extends Type, @routinetype { * class C { }; * ``` */ -class TemplateParameter extends UserType { - TemplateParameter() { +class TypeTemplateParameter extends UserType, TemplateParameterImpl { + TypeTemplateParameter() { usertypes(underlyingElement(this), _, 7) or usertypes(underlyingElement(this), _, 8) } - override string getAPrimaryQlClass() { result = "TemplateParameter" } + override string getAPrimaryQlClass() { result = "TypeTemplateParameter" } override predicate involvesTemplateParameter() { any() } } @@ -1695,7 +1717,7 @@ class TemplateParameter extends UserType { * void foo(const Container &value) { } * ``` */ -class TemplateTemplateParameter extends TemplateParameter { +class TemplateTemplateParameter extends TypeTemplateParameter { TemplateTemplateParameter() { usertypes(underlyingElement(this), _, 8) } override string getAPrimaryQlClass() { result = "TemplateTemplateParameter" } @@ -1707,7 +1729,7 @@ class TemplateTemplateParameter extends TemplateParameter { * auto val = some_typed_expr(); * ``` */ -class AutoType extends TemplateParameter { +class AutoType extends TypeTemplateParameter { AutoType() { usertypes(underlyingElement(this), "auto", 7) } override string getAPrimaryQlClass() { result = "AutoType" } diff --git a/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll b/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll index fefc1767c248..264b6142e76e 100644 --- a/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll +++ b/cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll @@ -66,7 +66,7 @@ class Symbol extends DependsSource { not this.(TypeDeclarationEntry).getType() instanceof LocalEnum and not this.(TypeDeclarationEntry).getType() instanceof LocalClass and not this.(TypeDeclarationEntry).getType() instanceof LocalTypedefType and - not this.(TypeDeclarationEntry).getType() instanceof TemplateParameter + not this.(TypeDeclarationEntry).getType() instanceof TypeTemplateParameter or this instanceof NamespaceDeclarationEntry ) diff --git a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll index d234dbc8e3ab..ad8e2fd2e33b 100644 --- a/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll +++ b/cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll @@ -504,7 +504,7 @@ private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remain result = getParameterTypeWithoutTemplateArguments(templateFunction, n) ) or - exists(string mid, TemplateParameter tp, Function templateFunction | + exists(string mid, TypeTemplateParameter tp, Function templateFunction | mid = getTypeNameWithoutFunctionTemplates(f, n, remaining + 1) and templateFunction = getFullyTemplatedFunction(f) and tp = templateFunction.getTemplateArgument(remaining) and @@ -529,7 +529,7 @@ private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining remaining = 0 and result = getTypeNameWithoutFunctionTemplates(f, n, 0) or - exists(string mid, TemplateParameter tp, Class template | + exists(string mid, TypeTemplateParameter tp, Class template | mid = getTypeNameWithoutClassTemplates(f, n, remaining + 1) and isClassConstructedFrom(f.getDeclaringType(), template) and tp = template.getTemplateArgument(remaining) and diff --git a/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll b/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll index 54de2c953634..195f96557450 100644 --- a/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll +++ b/cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll @@ -130,7 +130,7 @@ class Declaration extends @declaration { this instanceof Parameter or this instanceof ProxyClass or this instanceof LocalVariable or - this instanceof TemplateParameter or + this instanceof TypeTemplateParameter or this.(UserType).isLocal() ) } @@ -226,8 +226,8 @@ class ProxyClass extends UserType { ProxyClass() { usertypes(this, _, 9) } } -class TemplateParameter extends UserType { - TemplateParameter() { usertypes(this, _, 7) or usertypes(this, _, 8) } +class TypeTemplateParameter extends UserType { + TypeTemplateParameter() { usertypes(this, _, 7) or usertypes(this, _, 8) } } class TemplateClass extends UserType { diff --git a/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql b/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql index 5ae8468d0fc4..4ba1ad93f565 100644 --- a/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql +++ b/cpp/ql/src/Best Practices/Unused Entities/UnusedLocals.ql @@ -26,7 +26,7 @@ import cpp */ class TemplateDependentType extends Type { TemplateDependentType() { - this instanceof TemplateParameter + this instanceof TypeTemplateParameter or exists(TemplateDependentType t | this.refersToDirectly(t) and diff --git a/cpp/ql/src/Likely Bugs/Arithmetic/PointlessSelfComparison.qll b/cpp/ql/src/Likely Bugs/Arithmetic/PointlessSelfComparison.qll index df22d682e65f..d0ed90644d76 100644 --- a/cpp/ql/src/Likely Bugs/Arithmetic/PointlessSelfComparison.qll +++ b/cpp/ql/src/Likely Bugs/Arithmetic/PointlessSelfComparison.qll @@ -49,7 +49,7 @@ predicate nanTest(EqualityOperation cmp) { pointlessSelfComparison(cmp) and exists(Type t | t = cmp.getLeftOperand().getUnspecifiedType() | t instanceof FloatingPointType or - t instanceof TemplateParameter + t instanceof TypeTemplateParameter ) } diff --git a/cpp/ql/src/Likely Bugs/ReturnConstTypeCommon.qll b/cpp/ql/src/Likely Bugs/ReturnConstTypeCommon.qll index 6d81caed3910..fde1ebeec598 100644 --- a/cpp/ql/src/Likely Bugs/ReturnConstTypeCommon.qll +++ b/cpp/ql/src/Likely Bugs/ReturnConstTypeCommon.qll @@ -2,7 +2,7 @@ import cpp private predicate mightHaveConstMethods(Type t) { t instanceof Class or - t instanceof TemplateParameter + t instanceof TypeTemplateParameter } predicate hasSuperfluousConstReturn(Function f) { diff --git a/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql b/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql index 9027c064ac67..67828be1ae54 100644 --- a/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql +++ b/cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql @@ -26,7 +26,7 @@ predicate functionsMissingReturnStmt(Function f, ControlFlowNode blame) { exists(Type returnType | returnType = f.getUnspecifiedType() and not returnType instanceof VoidType and - not returnType instanceof TemplateParameter + not returnType instanceof TypeTemplateParameter ) and exists(ReturnStmt s | f.getAPredecessor() = s and diff --git a/cpp/ql/test/examples/expressions/PrintAST.expected b/cpp/ql/test/examples/expressions/PrintAST.expected index e8e753becb56..724b109db489 100644 --- a/cpp/ql/test/examples/expressions/PrintAST.expected +++ b/cpp/ql/test/examples/expressions/PrintAST.expected @@ -915,7 +915,7 @@ VacuousDestructorCall.cpp: # 2| [TemplateFunction,TopLevelFunction] void CallDestructor(T, T*) # 2| : # 2| getParameter(0): [Parameter] x -# 2| Type = [TemplateParameter] T +# 2| Type = [TypeTemplateParameter] T # 2| getParameter(1): [Parameter] y # 2| Type = [PointerType] T * # 2| getEntryPoint(): [BlockStmt] { ... } @@ -927,7 +927,7 @@ VacuousDestructorCall.cpp: # 3| Type = [UnknownType] unknown # 3| ValueCategory = prvalue # 3| getChild(-1): [VariableAccess] x -# 3| Type = [TemplateParameter] T +# 3| Type = [TypeTemplateParameter] T # 3| ValueCategory = lvalue # 4| getStmt(1): [ExprStmt] ExprStmt # 4| getExpr(): [ExprCall] call to expression diff --git a/cpp/ql/test/library-tests/declaration/declaration.cpp b/cpp/ql/test/library-tests/declaration/declaration.cpp index 0601f5c2d6ac..b9965252e85d 100644 --- a/cpp/ql/test/library-tests/declaration/declaration.cpp +++ b/cpp/ql/test/library-tests/declaration/declaration.cpp @@ -56,7 +56,7 @@ union MyUnion0 { // Typedef typedef MyClass0 *MyClassPtr; -// TemplateClass, TemplateParameter (UserType) +// TemplateClass, TypeTemplateParameter (UserType) template class myTemplateClass @@ -113,7 +113,7 @@ class MyClass1 { // Typedef typedef MyClass1 *MyClassPtr; -// TemplateClass, TemplateParameter (UserType) +// TemplateClass, TypeTemplateParameter (UserType) template class myTemplateClass diff --git a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected index ea242065ac17..1b0f0e685a5f 100644 --- a/cpp/ql/test/library-tests/ir/ir/PrintAST.expected +++ b/cpp/ql/test/library-tests/ir/ir/PrintAST.expected @@ -9016,9 +9016,9 @@ ir.cpp: # 704| [TemplateFunction,TopLevelFunction] T min(T, T) # 704| : # 704| getParameter(0): [Parameter] x -# 704| Type = [TemplateParameter] T +# 704| Type = [TypeTemplateParameter] T # 704| getParameter(1): [Parameter] y -# 704| Type = [TemplateParameter] T +# 704| Type = [TypeTemplateParameter] T # 704| getEntryPoint(): [BlockStmt] { ... } # 705| getStmt(0): [ReturnStmt] return ... # 705| getExpr(): [ConditionalExpr] ... ? ... : ... @@ -9028,16 +9028,16 @@ ir.cpp: # 705| Type = [UnknownType] unknown # 705| ValueCategory = prvalue # 705| getLesserOperand(): [VariableAccess] x -# 705| Type = [TemplateParameter] T +# 705| Type = [TypeTemplateParameter] T # 705| ValueCategory = lvalue # 705| getGreaterOperand(): [VariableAccess] y -# 705| Type = [TemplateParameter] T +# 705| Type = [TypeTemplateParameter] T # 705| ValueCategory = lvalue # 705| getThen(): [VariableAccess] x -# 705| Type = [TemplateParameter] T +# 705| Type = [TypeTemplateParameter] T # 705| ValueCategory = lvalue # 705| getElse(): [VariableAccess] y -# 705| Type = [TemplateParameter] T +# 705| Type = [TypeTemplateParameter] T # 705| ValueCategory = lvalue # 705| getCondition().getFullyConverted(): [CStyleCast] (bool)... # 705| Conversion = [BoolConversion] conversion to bool @@ -9095,24 +9095,24 @@ ir.cpp: # 715| [MemberFunction,TemplateFunction] T Outer::Func(U, V) # 715| : # 715| getParameter(0): [Parameter] x -# 715| Type = [TemplateParameter] U +# 715| Type = [TypeTemplateParameter] U # 715| getParameter(1): [Parameter] y -# 715| Type = [TemplateParameter] V +# 715| Type = [TypeTemplateParameter] V # 715| getEntryPoint(): [BlockStmt] { ... } # 716| getStmt(0): [ReturnStmt] return ... # 716| getExpr(): [Literal] 0 -# 716| Type = [TemplateParameter] T +# 716| Type = [TypeTemplateParameter] T # 716| Value = [Literal] 0 # 716| ValueCategory = prvalue # 716| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object -# 716| Type = [TemplateParameter] T +# 716| Type = [TypeTemplateParameter] T # 716| ValueCategory = prvalue(load) # 715| [MemberFunction,TemplateFunction] long Outer::Func(U, V) # 715| : # 715| getParameter(0): [Parameter] x -# 715| Type = [TemplateParameter] U +# 715| Type = [TypeTemplateParameter] U # 715| getParameter(1): [Parameter] y -# 715| Type = [TemplateParameter] V +# 715| Type = [TypeTemplateParameter] V # 715| [FunctionTemplateInstantiation,MemberFunction] long Outer::Func(void*, char) # 715| : # 715| getParameter(0): [Parameter] x @@ -12559,7 +12559,7 @@ ir.cpp: # 1109| [Constructor] void std::vector::vector(T) # 1109| : # 1109| getParameter(0): [Parameter] (unnamed parameter 0) -# 1109| Type = [TemplateParameter] T +# 1109| Type = [TypeTemplateParameter] T # 1109| [Constructor] void std::vector::vector(char) # 1109| : # 1109| getParameter(0): [Parameter] (unnamed parameter 0) @@ -12601,15 +12601,15 @@ ir.cpp: # 1120| [Operator,TemplateFunction,TopLevelFunction] bool std::operator==(iterator, iterator) # 1120| : # 1120| getParameter(0): [Parameter] left -# 1120| Type = [TemplateParameter] iterator +# 1120| Type = [TypeTemplateParameter] iterator # 1120| getParameter(1): [Parameter] right -# 1120| Type = [TemplateParameter] iterator +# 1120| Type = [TypeTemplateParameter] iterator # 1122| [Operator,TemplateFunction,TopLevelFunction] bool std::operator!=(iterator, iterator) # 1122| : # 1122| getParameter(0): [Parameter] left -# 1122| Type = [TemplateParameter] iterator +# 1122| Type = [TypeTemplateParameter] iterator # 1122| getParameter(1): [Parameter] right -# 1122| Type = [TemplateParameter] iterator +# 1122| Type = [TypeTemplateParameter] iterator # 1126| [TopLevelFunction] void RangeBasedFor(std::vector const&) # 1126| : # 1126| getParameter(0): [Parameter] v @@ -14129,11 +14129,11 @@ ir.cpp: # 1375| getEntryPoint(): [BlockStmt] { ... } # 1376| getStmt(0): [ReturnStmt] return ... # 1376| getExpr(): [Literal] 0 -# 1376| Type = [TemplateParameter] T +# 1376| Type = [TypeTemplateParameter] T # 1376| Value = [Literal] 0 # 1376| ValueCategory = prvalue # 1376| getExpr().getFullyConverted(): [TemporaryObjectExpr] temporary object -# 1376| Type = [TemplateParameter] T +# 1376| Type = [TypeTemplateParameter] T # 1376| ValueCategory = prvalue(load) # 1375| [FunctionTemplateInstantiation,TopLevelFunction] copy_constructor defaultConstruct() # 1375| : @@ -14223,7 +14223,7 @@ ir.cpp: # 1409| [TemplateFunction,TopLevelFunction] void acceptValue(T) # 1409| : # 1409| getParameter(0): [Parameter] v -# 1409| Type = [TemplateParameter] T +# 1409| Type = [TypeTemplateParameter] T # 1409| [FunctionTemplateInstantiation,TopLevelFunction] void acceptValue(copy_constructor) # 1409| : # 1409| getParameter(0): [Parameter] v @@ -20584,7 +20584,7 @@ ir.cpp: # 2256| Type = [LValueReferenceType] T & # 2256| ValueCategory = prvalue(load) # 2256| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference) -# 2256| Type = [TemplateParameter] T +# 2256| Type = [TypeTemplateParameter] T # 2256| ValueCategory = lvalue # 2256| [FunctionTemplateInstantiation,TopLevelFunction] int& vacuous_destructor_call::get(int&) # 2256| : @@ -20648,7 +20648,7 @@ ir.cpp: # 2260| Type = [LValueReferenceType] T & # 2260| ValueCategory = prvalue(load) # 2260| getArgument(0).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference) -# 2260| Type = [TemplateParameter] T +# 2260| Type = [TypeTemplateParameter] T # 2260| ValueCategory = lvalue # 2261| getStmt(1): [ReturnStmt] return ... # 2259| [FunctionTemplateInstantiation,TopLevelFunction] void vacuous_destructor_call::call_destructor(int&) diff --git a/cpp/ql/test/library-tests/proxy_class/locations.expected b/cpp/ql/test/library-tests/proxy_class/locations.expected index 6c0eb498cbbe..c1b9ba5f540e 100644 --- a/cpp/ql/test/library-tests/proxy_class/locations.expected +++ b/cpp/ql/test/library-tests/proxy_class/locations.expected @@ -1,4 +1,4 @@ | proxy_class.cpp:1:8:1:11 | Base | Struct | | proxy_class.cpp:3:20:3:20 | T | ProxyClass | -| proxy_class.cpp:3:20:3:20 | T | TemplateParameter | +| proxy_class.cpp:3:20:3:20 | T | TypeTemplateParameter | | proxy_class.cpp:4:8:4:14 | Derived | Struct | diff --git a/cpp/ql/test/library-tests/proxy_class/locations.ql b/cpp/ql/test/library-tests/proxy_class/locations.ql index 79ad71f0861b..956c338e8f6e 100644 --- a/cpp/ql/test/library-tests/proxy_class/locations.ql +++ b/cpp/ql/test/library-tests/proxy_class/locations.ql @@ -3,7 +3,7 @@ import cpp string clazz(Declaration d) { d instanceof ProxyClass and result = "ProxyClass" or - d instanceof TemplateParameter and result = "TemplateParameter" + d instanceof TypeTemplateParameter and result = "TypeTemplateParameter" or d instanceof Struct and result = "Struct" }