Skip to content

Commit e4238e6

Browse files
committed
Unified: Use ParameterEx in type inference
1 parent ff7dd73 commit e4238e6

12 files changed

Lines changed: 325 additions & 309 deletions

File tree

‎unified/ql/lib/codeql/unified/internal/AstPlugin.qll‎

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
overlay[local]
1+
overlay[local?]
22
module;
33

44
private import unified
@@ -23,10 +23,26 @@ class AstPlugin extends Unit {
2323

2424
/**
2525
* Holds if the default constructor `cd` needs a parameter at index `i` with
26-
* the given name. `i = 0` is reserved for the implicit receiver parameter.
26+
* the given name. `hasDefault` indicates whether the parameter has a default
27+
* value.
28+
*
29+
* `i = 0` is reserved for the implicit receiver parameter.
2730
*/
2831
bindingset[cd]
29-
predicate defaultConstructorParameter(ConstructorDeclaration cd, int i, string name) { none() }
32+
predicate defaultConstructorParameter(
33+
ConstructorDeclaration cd, int i, string name, boolean hasDefault
34+
) {
35+
none()
36+
}
37+
38+
/**
39+
* Holds if the type of the `i`th parameter of the default constructor `cd`
40+
* is `type`.
41+
*/
42+
bindingset[cd]
43+
predicate defaultConstructorParameterType(ConstructorDeclaration cd, int i, AstNode type) {
44+
none()
45+
}
3046
}
3147

3248
bindingset[f]
@@ -50,6 +66,13 @@ string getVariableDeclarationKeyword(VariableDeclaration decl) {
5066
}
5167

5268
bindingset[cd]
53-
predicate defaultConstructorParameter(ConstructorDeclaration cd, int i, string name) {
54-
any(AstPlugin p).defaultConstructorParameter(cd, i, name)
69+
predicate defaultConstructorParameter(
70+
ConstructorDeclaration cd, int i, string name, boolean hasDefault
71+
) {
72+
any(AstPlugin p).defaultConstructorParameter(cd, i, name, hasDefault)
73+
}
74+
75+
bindingset[cd]
76+
predicate defaultConstructorParameterType(ConstructorDeclaration cd, int i, AstNode type) {
77+
any(AstPlugin p).defaultConstructorParameterType(cd, i, type)
5578
}
Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,34 @@
1-
overlay[local]
1+
overlay[local?]
22
module;
33

44
private import unified
55
private import AstPlugin
6+
private import codeql.unified.internal.typeinference.TypeMention
7+
private import codeql.unified.internal.typeinference.TypeInferencePluginSwift
8+
9+
private predicate structHasParameterForField(
10+
ConstructorDeclaration cd, VariableDeclaration decl, int i, string name, boolean hasDefault
11+
) {
12+
exists(ClassLikeDeclaration struct |
13+
struct.hasModifier("struct") and
14+
cd = struct.getAMember() and
15+
decl = struct.getMember(i) and
16+
not decl.hasModifier("static") and
17+
name = decl.getPattern().(Identifier).getValue()
18+
|
19+
// if `decl` has an initializer or `Optional` type then the parameter has a default value
20+
decl.hasModifier("var") and
21+
if
22+
exists(decl.getValue()) or
23+
decl.getType().(TypeMention).getType() instanceof OptionalType
24+
then hasDefault = true
25+
else hasDefault = false
26+
or
27+
decl.hasModifier("let") and
28+
not exists(decl.getValue()) and
29+
hasDefault = false
30+
)
31+
}
632

733
private class AstPluginSwift extends AstPlugin {
834
bindingset[f]
@@ -27,25 +53,19 @@ private class AstPluginSwift extends AstPlugin {
2753
}
2854

2955
bindingset[cd]
30-
override predicate defaultConstructorParameter(ConstructorDeclaration cd, int i, string name) {
31-
exists(ClassLikeDeclaration cls |
32-
cd = cls.getAMember() and
33-
cls.hasModifier("struct") and
34-
name =
35-
rank[i](VariableDeclaration decl, int j, string s |
36-
decl = cls.getMember(j) and
37-
not decl.hasModifier("static") and
38-
(
39-
// if `decl` has an initializer then this parameter has that initializer as a default value
40-
decl.hasModifier("var")
41-
or
42-
decl.hasModifier("let") and
43-
not exists(decl.getValue())
44-
) and
45-
s = decl.getPattern().(Identifier).getValue()
46-
|
47-
s order by j
48-
)
56+
override predicate defaultConstructorParameter(
57+
ConstructorDeclaration cd, int i, string name, boolean hasDefault
58+
) {
59+
name = rank[i](int j, string s | structHasParameterForField(cd, _, j, s, _) | s order by j) and
60+
structHasParameterForField(cd, _, _, name, hasDefault)
61+
}
62+
63+
bindingset[cd]
64+
override predicate defaultConstructorParameterType(ConstructorDeclaration cd, int i, AstNode type) {
65+
exists(VariableDeclaration decl, string name |
66+
this.defaultConstructorParameter(cd, i, name, _) and
67+
structHasParameterForField(cd, decl, _, name, _) and
68+
type = decl.getType()
4969
)
5070
}
5171
}

‎unified/ql/lib/codeql/unified/internal/ParameterEx.qll‎

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ private newtype TParameterEx =
1111
TImplicitReceiverParameter(Callable c) {
1212
exists(LocalVariable v | v.isImplicitReceiverParameter(c))
1313
} or
14-
TDefaultConstructorParameter(ConstructorDeclaration cd, int i, string name) {
14+
TDefaultConstructorParameter(ConstructorDeclaration cd, int i, string name, boolean hasDefault) {
1515
cd.hasModifier("generated") and
16-
defaultConstructorParameter(cd, i, name)
16+
defaultConstructorParameter(cd, i, name, hasDefault)
1717
}
1818

1919
final class ParameterEx = ParameterExImpl;
@@ -42,7 +42,7 @@ abstract private class ParameterExImpl extends TParameterEx {
4242
* constructor `cd` with name `name`.
4343
*/
4444
predicate isDefaultConstructorParameter(ConstructorDeclaration cd, int i, string name) {
45-
this = TDefaultConstructorParameter(cd, i, name)
45+
this = TDefaultConstructorParameter(cd, i, name, _)
4646
}
4747

4848
/** Gets the callable that this parameter belongs to. */
@@ -60,6 +60,12 @@ abstract private class ParameterExImpl extends TParameterEx {
6060
this.isDefaultConstructorParameter(result, _, _)
6161
}
6262

63+
/** Holds if this parameter has a default value. */
64+
abstract predicate hasDefault();
65+
66+
/** Gets the type declaration of this parameter, if any. */
67+
abstract AstNode getType();
68+
6369
/** Gets a textual representation of this parameter. */
6470
abstract string toString();
6571

@@ -72,6 +78,10 @@ private class AstParameterEx extends ParameterExImpl, TAstParameter {
7278

7379
AstParameterEx() { this = TAstParameter(p) }
7480

81+
override predicate hasDefault() { exists(p.getDefault()) }
82+
83+
override AstNode getType() { result = p.getType() }
84+
7585
override string toString() { result = p.toString() }
7686

7787
override Location getLocation() { result = p.getLocation() }
@@ -82,6 +92,10 @@ private class ImplicitReceiverParameterEx extends ParameterExImpl, TImplicitRece
8292

8393
ImplicitReceiverParameterEx() { this = TImplicitReceiverParameter(c) }
8494

95+
override predicate hasDefault() { none() }
96+
97+
override AstNode getType() { none() }
98+
8599
override string toString() {
86100
exists(LocalVariable v |
87101
v.isImplicitReceiverParameter(c) and
@@ -96,8 +110,13 @@ private class DefaultConstructorParameterEx extends ParameterExImpl, TDefaultCon
96110
ConstructorDeclaration cd;
97111
int i;
98112
string name;
113+
boolean hasDefault;
114+
115+
DefaultConstructorParameterEx() { this = TDefaultConstructorParameter(cd, i, name, hasDefault) }
116+
117+
override AstNode getType() { defaultConstructorParameterType(cd, i, result) }
99118

100-
DefaultConstructorParameterEx() { this = TDefaultConstructorParameter(cd, i, name) }
119+
override predicate hasDefault() { hasDefault = true }
101120

102121
override string toString() { result = name + " [" + cd.getName() + " default constructor]" }
103122

‎unified/ql/lib/codeql/unified/internal/typeinference/Type.qll‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/** Provides classes representing types without type arguments. */
2+
overlay[local?]
3+
module;
24

35
import unified // reexport in order to shadow e.g. the `TypeParameter` class
46
private import unified as Unified

0 commit comments

Comments
 (0)