Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C++: Introduce a new base class for template parameters #18308

Merged
merged 2 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically, this is currently a lie, as nothing represents non-type template parameters. I plan to fix this next.

4 changes: 4 additions & 0 deletions cpp/ql/lib/change-notes/2024-12-17-template-parameter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: deprecated
---
* The `TemplateParameter` class, representing C++ type template parameters has been deprecated. Use `TypeTemplateParameter` instead.
6 changes: 3 additions & 3 deletions cpp/ql/lib/semmle/code/cpp/Class.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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)))
}

Expand Down Expand Up @@ -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)))
}

Expand Down Expand Up @@ -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))
}
}
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/lib/semmle/code/cpp/Declaration.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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()
)
}
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/lib/semmle/code/cpp/Print.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""
}

/**
Expand Down
32 changes: 27 additions & 5 deletions cpp/ql/lib/semmle/code/cpp/Type.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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`, `TT`, and `I` are template parameters:
* ```
* template <class T, template<typename> TT, int I>
* 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.
*
Expand All @@ -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() }
}
Expand All @@ -1695,7 +1717,7 @@ class TemplateParameter extends UserType {
* void foo(const Container<Elem> &value) { }
* ```
*/
class TemplateTemplateParameter extends TemplateParameter {
class TemplateTemplateParameter extends TypeTemplateParameter {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the description in the change note I thought that type template parameters and template template parameters where to different groups and wouldn't have expected TemplateTemplateParameter to extend TypeTemplateParameter?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could pull that apart, but that will have quite some fallout in other places, and possibly for customers. So, I prefer to leave this as-is. Another observation is that template template parameters will still refer to (templated) types, so from that perspective it makes sense to have this layering, I think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, thanks. Let's keep it like this then :)

TemplateTemplateParameter() { usertypes(underlyingElement(this), _, 8) }

override string getAPrimaryQlClass() { result = "TemplateTemplateParameter" }
Expand All @@ -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" }
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/lib/semmle/code/cpp/commons/Dependency.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
6 changes: 3 additions & 3 deletions cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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()
)
}
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
}

Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/src/Likely Bugs/ReturnConstTypeCommon.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/test/examples/expressions/PrintAST.expected
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@ VacuousDestructorCall.cpp:
# 2| [TemplateFunction,TopLevelFunction] void CallDestructor<T>(T, T*)
# 2| <params>:
# 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] { ... }
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/test/library-tests/declaration/declaration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ union MyUnion0 {
// Typedef
typedef MyClass0 *MyClassPtr;

// TemplateClass, TemplateParameter (UserType)
// TemplateClass, TypeTemplateParameter (UserType)

template <typename T>
class myTemplateClass
Expand Down Expand Up @@ -113,7 +113,7 @@ class MyClass1 {
// Typedef
typedef MyClass1 *MyClassPtr;

// TemplateClass, TemplateParameter (UserType)
// TemplateClass, TypeTemplateParameter (UserType)

template <typename T>
class myTemplateClass
Expand Down
44 changes: 22 additions & 22 deletions cpp/ql/test/library-tests/ir/ir/PrintAST.expected
Original file line number Diff line number Diff line change
Expand Up @@ -9016,9 +9016,9 @@ ir.cpp:
# 704| [TemplateFunction,TopLevelFunction] T min<T>(T, T)
# 704| <params>:
# 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] ... ? ... : ...
Expand All @@ -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
Expand Down Expand Up @@ -9095,24 +9095,24 @@ ir.cpp:
# 715| [MemberFunction,TemplateFunction] T Outer<T>::Func<U, V>(U, V)
# 715| <params>:
# 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<long>::Func<U, V>(U, V)
# 715| <params>:
# 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<long>::Func<void*, char>(void*, char)
# 715| <params>:
# 715| getParameter(0): [Parameter] x
Expand Down Expand Up @@ -12559,7 +12559,7 @@ ir.cpp:
# 1109| [Constructor] void std::vector<T>::vector(T)
# 1109| <params>:
# 1109| getParameter(0): [Parameter] (unnamed parameter 0)
# 1109| Type = [TemplateParameter] T
# 1109| Type = [TypeTemplateParameter] T
# 1109| [Constructor] void std::vector<char>::vector(char)
# 1109| <params>:
# 1109| getParameter(0): [Parameter] (unnamed parameter 0)
Expand Down Expand Up @@ -12601,15 +12601,15 @@ ir.cpp:
# 1120| [Operator,TemplateFunction,TopLevelFunction] bool std::operator==<T>(iterator, iterator)
# 1120| <params>:
# 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!=<T>(iterator, iterator)
# 1122| <params>:
# 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<int> const&)
# 1126| <params>:
# 1126| getParameter(0): [Parameter] v
Expand Down Expand Up @@ -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<copy_constructor>()
# 1375| <params>:
Expand Down Expand Up @@ -14223,7 +14223,7 @@ ir.cpp:
# 1409| [TemplateFunction,TopLevelFunction] void acceptValue<T>(T)
# 1409| <params>:
# 1409| getParameter(0): [Parameter] v
# 1409| Type = [TemplateParameter] T
# 1409| Type = [TypeTemplateParameter] T
# 1409| [FunctionTemplateInstantiation,TopLevelFunction] void acceptValue<copy_constructor>(copy_constructor)
# 1409| <params>:
# 1409| getParameter(0): [Parameter] v
Expand Down Expand Up @@ -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>(int&)
# 2256| <params>:
Expand Down Expand Up @@ -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>(int&)
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/test/library-tests/proxy_class/locations.expected
Original file line number Diff line number Diff line change
@@ -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<Base> | Struct |
2 changes: 1 addition & 1 deletion cpp/ql/test/library-tests/proxy_class/locations.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
Loading