Merge pull request #18483 from jketema/extractor-fixes

C++: Fix types of struct/union templates and fix assumptions on proxy classes
This commit is contained in:
Jeroen Ketema
2025-01-15 12:01:25 +01:00
committed by GitHub
22 changed files with 9724 additions and 37 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Improve user types and proxy classes
compatibility: full
usertypes.rel: run usertypes.qlo

View File

@@ -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)

View File

@@ -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.

View File

@@ -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.
@@ -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 {
@@ -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.

View File

@@ -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" }

View File

@@ -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" }

View File

@@ -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])
}
}

View File

@@ -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.

View File

@@ -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" }

View File

@@ -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

View File

@@ -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) {

View File

@@ -771,12 +771,13 @@ decltypes(
/*
case @usertype.kind of
1 = @struct
| 0 = @unknown_usertype
| 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
@@ -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
;
*/
@@ -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(

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Improve user types and proxy classes
compatibility: partial
usertypes.rel: run usertypes.qlo

View File

@@ -0,0 +1,17 @@
class UserType extends @usertype {
string toString() { none() }
}
bindingset[kind]
int getKind(int kind) {
if kind in [10, 11, 12]
then result = 0
else
if kind = 6
then result = 16
else result = kind
}
from UserType usertype, string name, int kind
where usertypes(usertype, name, kind)
select usertype, name, getKind(kind)

View File

@@ -21,7 +21,7 @@ string kindstr(Class c) {
or
kind = 2 and result = "Class"
or
kind = 6 and result = "Template class"
kind = [15, 16] and result = "Template class"
)
}

View File

@@ -1,4 +1,4 @@
| ODASA-5186.cpp:4:8:4:14 | MyClass<T> | Class | ODASA-5186.cpp:5:8:5:17 | operator== | |
| ODASA-5186.cpp:4:8:4:14 | MyClass<T> | Struct | ODASA-5186.cpp:5:8:5:17 | operator== | |
| ODASA-5186.cpp:4:8:4:14 | MyClass<int> | Struct | ODASA-5186.cpp:5:8:5:8 | operator== | |
| file://:0:0:0:0 | __va_list_tag | Struct | file://:0:0:0:0 | operator= | |
| file://:0:0:0:0 | __va_list_tag | Struct | file://:0:0:0:0 | operator= | |

View File

@@ -12445,11 +12445,11 @@ ir.cpp:
# 1088| [ConstMemberFunction] bool std::iterator<Category, value_type, difference_type, pointer_type, reference_type>::operator==(std::iterator<Category, value_type, difference_type, pointer_type, reference_type>) const
# 1088| <params>:
# 1088| getParameter(0): [Parameter] other
# 1088| Type = [TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
# 1088| Type = [Struct,TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
# 1089| [ConstMemberFunction] bool std::iterator<Category, value_type, difference_type, pointer_type, reference_type>::operator!=(std::iterator<Category, value_type, difference_type, pointer_type, reference_type>) const
# 1089| <params>:
# 1089| getParameter(0): [Parameter] other
# 1089| Type = [TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
# 1089| Type = [Struct,TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
# 1089| [ConstMemberFunction] bool std::iterator<std::random_access_iterator_tag, ClassWithDestructor, std::ptrdiff_t, ClassWithDestructor*, ClassWithDestructor&>::operator!=(std::iterator<std::random_access_iterator_tag, ClassWithDestructor, std::ptrdiff_t, ClassWithDestructor*, ClassWithDestructor&>) const
# 1089| <params>:
# 1089| getParameter(0): [Parameter] other
@@ -12497,7 +12497,7 @@ ir.cpp:
# 1096| [MemberFunction] int std::iterator<Category, value_type, difference_type, pointer_type, reference_type>::operator-(std::iterator<Category, value_type, difference_type, pointer_type, reference_type>)
# 1096| <params>:
# 1096| getParameter(0): [Parameter] (unnamed parameter 0)
# 1096| Type = [TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
# 1096| Type = [Struct,TemplateClass] iterator<Category, value_type, difference_type, pointer_type, reference_type>
# 1097| [MemberFunction] reference_type std::iterator<Category, value_type, difference_type, pointer_type, reference_type>::operator[](int)
# 1097| <params>:
# 1097| getParameter(0): [Parameter] (unnamed parameter 0)

View File

@@ -2,3 +2,4 @@
| proxy_class.cpp:3:20:3:20 | T | ProxyClass |
| proxy_class.cpp:3:20:3:20 | T | TypeTemplateParameter |
| proxy_class.cpp:4:8:4:14 | Derived<Base> | Struct |
| proxy_class.cpp:4:8:4:14 | Derived<T> | Struct |