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++: Fix types of struct/union templates and fix assumptions on proxy classes #18483

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
2,415 changes: 2,415 additions & 0 deletions cpp/downgrades/a01d8f91b8d49259e509b574962dec90719f69a6/old.dbscheme

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
description: Improve user types and proxy classes
compatibility: full
usertypes.rel: run usertypes.qlo
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
class UserType extends @usertype {
string toString() { none() }
}

bindingset[kind]
int getKind(int kind) { if kind in [15, 16, 17] then result = 6 else result = kind }

from UserType usertype, string name, int kind
where usertypes(usertype, name, kind)
select usertype, name, getKind(kind)
6 changes: 6 additions & 0 deletions cpp/ql/lib/change-notes/2025-01-13-struct-proxy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: feature
---
* A new predicate `getDecltype`was added to the `ProxyClass` class, which yields the decltype for the proxy class.
* Template classes that are of `struct` type are now also instances of the `Struct` class.
* Template classes that are of `union` type are now also instances of the `Union` class.
19 changes: 14 additions & 5 deletions cpp/ql/lib/semmle/code/cpp/Class.qll
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ class AbstractClass extends Class {
* `FullClassTemplateSpecialization`.
*/
class TemplateClass extends Class {
TemplateClass() { usertypes(underlyingElement(this), _, 6) }
TemplateClass() { usertypes(underlyingElement(this), _, [15, 16, 17]) }

/**
* Gets a class instantiated from this template.
Expand Down Expand Up @@ -1076,13 +1076,19 @@ class VirtualBaseClass extends Class {
}

/**
* The proxy class (where needed) associated with a template parameter, as
* in the following code:
* ```
* The proxy class (where needed) associated with a template parameter or a
* decltype, as in the following code:
* ```cpp
* template <typename T>
* struct S : T { // the type of this T is a proxy class
* ...
* };
*
* template <typename T>
* concept C =
* decltype(std::span{std::declval<T&>()})::extent
* != std::dynamic_extent;
* // the type of decltype(std::span{std::declval<T&>()}) is a proxy class
* ```
*/
class ProxyClass extends UserType {
Expand All @@ -1093,10 +1099,13 @@ class ProxyClass extends UserType {
/** Gets the location of the proxy class. */
override Location getLocation() { result = this.getTemplateParameter().getDefinitionLocation() }

/** Gets the template parameter for which this is the proxy class. */
/** Gets the template parameter for which this is the proxy class, if any. */
TypeTemplateParameter getTemplateParameter() {
is_proxy_class_for(underlyingElement(this), unresolveElement(result))
}

/** Gets the decltype for which this is the proxy class, if any. */
Decltype getDecltype() { is_proxy_class_for(underlyingElement(this), unresolveElement(result)) }
}

// Unpacks "array of ... of array of t" into t.
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/lib/semmle/code/cpp/Struct.qll
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import semmle.code.cpp.Class
* ```
*/
class Struct extends Class {
Struct() { usertypes(underlyingElement(this), _, 1) or usertypes(underlyingElement(this), _, 3) }
Struct() { usertypes(underlyingElement(this), _, [1, 3, 15, 17]) }

override string getAPrimaryQlClass() { result = "Struct" }

Expand Down
4 changes: 1 addition & 3 deletions cpp/ql/lib/semmle/code/cpp/TemplateParameter.qll
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,7 @@ deprecated class TemplateParameter = TypeTemplateParameter;
* ```
*/
class TypeTemplateParameter extends UserType, TemplateParameterImpl {
TypeTemplateParameter() {
usertypes(underlyingElement(this), _, 7) or usertypes(underlyingElement(this), _, 8)
}
TypeTemplateParameter() { usertypes(underlyingElement(this), _, [7, 8]) }

override string getAPrimaryQlClass() { result = "TypeTemplateParameter" }

Expand Down
5 changes: 1 addition & 4 deletions cpp/ql/lib/semmle/code/cpp/Type.qll
Original file line number Diff line number Diff line change
Expand Up @@ -406,10 +406,7 @@ class IntegralOrEnumType extends Type {
isIntegralType(underlyingElement(this), _)
or
// Enum type
(
usertypes(underlyingElement(this), _, 4) or
usertypes(underlyingElement(this), _, 13)
)
usertypes(underlyingElement(this), _, [4, 13])
}
}

Expand Down
5 changes: 1 addition & 4 deletions cpp/ql/lib/semmle/code/cpp/TypedefType.qll
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ private import semmle.code.cpp.internal.ResolveClass
* ```
*/
class TypedefType extends UserType {
TypedefType() {
usertypes(underlyingElement(this), _, 5) or
usertypes(underlyingElement(this), _, 14)
}
TypedefType() { usertypes(underlyingElement(this), _, [5, 14]) }

/**
* Gets the base type of this typedef type.
Expand Down
2 changes: 1 addition & 1 deletion cpp/ql/lib/semmle/code/cpp/Union.qll
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import semmle.code.cpp.Struct
* ```
*/
class Union extends Struct {
Union() { usertypes(underlyingElement(this), _, 3) }
Union() { usertypes(underlyingElement(this), _, [3, 17]) }

override string getAPrimaryQlClass() { result = "Union" }

Expand Down
4 changes: 2 additions & 2 deletions cpp/ql/lib/semmle/code/cpp/internal/QualifiedName.qll
Original file line number Diff line number Diff line change
Expand Up @@ -227,11 +227,11 @@ class ProxyClass extends UserType {
}

class TypeTemplateParameter extends UserType {
TypeTemplateParameter() { usertypes(this, _, 7) or usertypes(this, _, 8) }
TypeTemplateParameter() { usertypes(this, _, [7, 8]) }
}

class TemplateClass extends UserType {
TemplateClass() { usertypes(this, _, 6) }
TemplateClass() { usertypes(this, _, [15, 16, 17]) }

UserType getAnInstantiation() {
class_instantiation(result, this) and
Expand Down
10 changes: 1 addition & 9 deletions cpp/ql/lib/semmle/code/cpp/internal/ResolveClass.qll
Original file line number Diff line number Diff line change
Expand Up @@ -114,15 +114,7 @@ private module Cached {
* Holds if `t` is a struct, class, union, or template.
*/
cached
predicate isClass(@usertype t) {
usertypes(t, _, 1) or
usertypes(t, _, 2) or
usertypes(t, _, 3) or
usertypes(t, _, 6) or
usertypes(t, _, 10) or
usertypes(t, _, 11) or
usertypes(t, _, 12)
}
predicate isClass(@usertype t) { usertypes(t, _, [1, 2, 3, 15, 16, 17]) }

cached
predicate isType(@type t) {
Expand Down
12 changes: 9 additions & 3 deletions cpp/ql/lib/semmlecode.cpp.dbscheme
Original file line number Diff line number Diff line change
Expand Up @@ -771,12 +771,13 @@ decltypes(

/*
case @usertype.kind of
1 = @struct
| 0 = @unknown_usertype
Copy link
Contributor Author

Choose a reason for hiding this comment

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

0 was used in practice already, so this just makes its use explicit.

| 1 = @struct
| 2 = @class
| 3 = @union
| 4 = @enum
| 5 = @typedef // classic C: typedef typedef type name
| 6 = @template
// ... 6 = @template deprecated
| 7 = @template_parameter
| 8 = @template_template_parameter
| 9 = @proxy_class // a proxy class associated with a template parameter
Expand All @@ -785,6 +786,9 @@ case @usertype.kind of
// ... 12 objc_category deprecated
| 13 = @scoped_enum
| 14 = @using_alias // a using name = type style typedef
| 15 = @template_struct
| 16 = @template_class
| 17 = @template_union
;
*/

Expand Down Expand Up @@ -843,9 +847,11 @@ class_template_argument_value(
int arg_value: @expr ref
);

@user_or_decltype = @usertype | @decltype;

is_proxy_class_for(
unique int id: @usertype ref,
unique int templ_param_id: @usertype ref
int templ_param_id: @user_or_decltype ref
);

type_mentions(
Expand Down
Loading