Skip to content

Commit 3bc691f

Browse files
committed
Unified: Introduce CallableEx and ParameterEx
1 parent 605dc1c commit 3bc691f

7 files changed

Lines changed: 544 additions & 0 deletions

File tree

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ private class AstPluginSwift extends AstPlugin {
1010
exists(f) and result = "func"
1111
}
1212

13+
bindingset[c]
14+
override string getConstructorDeclarationKeyword(ConstructorDeclaration c) {
15+
c.hasModifier(result) and
16+
result = "convenience"
17+
}
18+
1319
override string getClassLikeDeclarationKeyword(ClassLikeDeclaration cls) {
1420
cls.hasModifier(result) and
1521
result in ["class", "struct", "enum", "actor", "extension", "protocol"]
Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
/**
2+
* Provides logic for synthesizing callables and parameters.
3+
*/
4+
5+
private import unified
6+
private import CallableExPlugin
7+
private import NameBinding
8+
9+
private predicate mayHaveImplicitConstructor(ClassLikeDeclaration cls, string name) {
10+
mayHaveConstructor(cls, name) and
11+
forall(ConstructorDeclaration c | c = cls.getAMember() | not constructorPreventsImplicit(c))
12+
}
13+
14+
bindingset[cls]
15+
private predicate mayInheritConstructorFrom(ClassLikeDeclaration cls, ClassLikeDeclaration base) {
16+
mayInheritConstructor(cls) and
17+
mayHaveImplicitConstructor(cls, _) and
18+
base.getNameNode() = getStaticBindingTargetFromRef(cls.getABaseType().getType()) and
19+
mayHaveConstructor(base, _)
20+
}
21+
22+
private newtype TCallableEx =
23+
TAstCallableEx(Callable c) or
24+
TDefaultConstructor(ClassLikeDeclaration cls, string name) {
25+
mayHaveImplicitConstructor(cls, name) and
26+
forall(ClassLikeDeclaration base | mayInheritConstructorFrom(cls, base) |
27+
not mayHaveConstructor(cls, _)
28+
)
29+
} or
30+
TInheritedConstructor(ClassLikeDeclaration cls, CallableEx baseCtor) {
31+
exists(ClassLikeDeclaration baseClass |
32+
mayInheritConstructorFrom(cls, baseClass) and
33+
baseCtor.isConstructor(baseClass)
34+
)
35+
}
36+
37+
private newtype TParameterEx =
38+
TAstParameter(Parameter p) or
39+
TImplicitReceiverParameter(Callable c) {
40+
exists(LocalVariable v | v.isImplicitReceiverParameter(c))
41+
} or
42+
TDefaultConstructorParameter(ClassLikeDeclaration cls, int i, string name) {
43+
defaultConstructorParameter(cls, i, name)
44+
} or
45+
TInheritedConstructorParameter(CallableEx ctor, CallableEx baseCtor, int i) {
46+
ctor.isInheritedConstructor(_, baseCtor) and
47+
exists(baseCtor.getParameter(i))
48+
}
49+
50+
final class CallableEx = CallableExImpl;
51+
52+
/**
53+
* A callable from source code or a synthesized callable.
54+
*/
55+
abstract private class CallableExImpl extends TCallableEx {
56+
/**
57+
* Gets the source code callable that this entity represents, if any.
58+
*/
59+
Callable asCallable() { this = TAstCallableEx(result) }
60+
61+
/**
62+
* Holds if this entity represents a default constructor for `cls`, for example a
63+
* parameterless Swift `class` constructor or a Swift `struct` constructor
64+
* with parameters for relevant fields.
65+
*/
66+
predicate isDefaultConstructor(ClassLikeDeclaration cls) { this = TDefaultConstructor(cls, _) }
67+
68+
/**
69+
* Holds if this entity represents an inherited constructor for `cls` from the
70+
* base constructor `baseCtor` (which may itself be inherited).
71+
*/
72+
predicate isInheritedConstructor(ClassLikeDeclaration cls, CallableEx baseCtor) {
73+
this = TInheritedConstructor(cls, baseCtor)
74+
}
75+
76+
/**
77+
* Holds if this entity represents a constructor for `cls`.
78+
*/
79+
predicate isConstructor(ClassLikeDeclaration cls) {
80+
this.asCallable().(ConstructorDeclaration) = cls.getAMember()
81+
or
82+
this.isDefaultConstructor(cls)
83+
or
84+
this.isInheritedConstructor(cls, _)
85+
}
86+
87+
/**
88+
* Holds if this entity is a direct member of `cls`.
89+
*/
90+
predicate isMemberOf(ClassLikeDeclaration cls) {
91+
this.asCallable() = cls.getAMember()
92+
or
93+
this.isConstructor(cls)
94+
}
95+
96+
/** Gets the `i`-th type parameter of this callable. */
97+
abstract TypeParameter getTypeParameter(int i);
98+
99+
/**
100+
* Gets the `i`-th parameter of this callable. Implicit receiver parameters are
101+
* at index `0`, and all other parameters start at index `1`.
102+
*/
103+
abstract ParameterEx getParameter(int i);
104+
105+
/** Gets a parameter of this callable. */
106+
final ParameterEx getAParameter() { result = this.getParameter(_) }
107+
108+
/** Gets the declared return type of this callable, if any. */
109+
abstract Expr getReturnType();
110+
111+
/** Gets the body of this callable, if any. */
112+
abstract AstNode getBody();
113+
114+
/** Gets the name node of this callable, if any. */
115+
abstract Identifier getNameNode();
116+
117+
/** Gets the name of this callable. */
118+
abstract string getName();
119+
120+
/** Gets a textual representation of this callable. */
121+
abstract string toString();
122+
123+
/** Gets the location of this callable. */
124+
abstract Location getLocation();
125+
}
126+
127+
private class AstCallableEx extends CallableExImpl, TAstCallableEx {
128+
Callable c;
129+
130+
AstCallableEx() { this = TAstCallableEx(c) }
131+
132+
override TypeParameter getTypeParameter(int i) {
133+
result = c.(FunctionDeclaration).getTypeParameter(i)
134+
}
135+
136+
override ParameterEx getParameter(int i) {
137+
result.isImplicitReceiverParameter(c) and
138+
i = 0
139+
or
140+
exists(int j, Parameter p |
141+
result.asParameter() = p and
142+
i = j + 1
143+
|
144+
p = c.(FunctionDeclaration).getParameter(j)
145+
or
146+
p = c.(ConstructorDeclaration).getParameter(j)
147+
or
148+
p = c.(FunctionExpr).getParameter(j)
149+
or
150+
p = c.(AccessorDeclaration).getParameter(j)
151+
)
152+
}
153+
154+
override Expr getReturnType() {
155+
result = c.(FunctionDeclaration).getReturnType()
156+
or
157+
result = c.(FunctionExpr).getReturnType()
158+
}
159+
160+
override AstNode getBody() { result = c.getBody() }
161+
162+
override Identifier getNameNode() {
163+
result = c.(AccessorDeclaration).getNameNode()
164+
or
165+
result = c.(ConstructorDeclaration).getNameNode()
166+
or
167+
result = c.(FunctionDeclaration).getNameNode()
168+
}
169+
170+
override string getName() {
171+
result = this.getNameNode().getValue()
172+
or
173+
c instanceof DestructorDeclaration and
174+
result = "<destructor>"
175+
or
176+
c instanceof InitializerDeclaration and
177+
result = "<initializer>"
178+
}
179+
180+
override string toString() { result = c.toString() }
181+
182+
override Location getLocation() { result = c.getLocation() }
183+
}
184+
185+
private class DefaultConstructor extends CallableExImpl, TDefaultConstructor {
186+
ClassLikeDeclaration c;
187+
string name;
188+
189+
DefaultConstructor() { this = TDefaultConstructor(c, name) }
190+
191+
override TypeParameter getTypeParameter(int i) { none() }
192+
193+
override ParameterEx getParameter(int i) { result = TDefaultConstructorParameter(c, i, _) }
194+
195+
override Expr getReturnType() { none() }
196+
197+
override AstNode getBody() { none() }
198+
199+
override Identifier getNameNode() { none() }
200+
201+
override string getName() { result = name }
202+
203+
override string toString() { result = c.getName() + " [default constructor]" }
204+
205+
override Location getLocation() { result = c.getLocation() }
206+
}
207+
208+
private class InheritedConstructor extends CallableExImpl, TInheritedConstructor {
209+
ClassLikeDeclaration cls;
210+
CallableEx baseCtor;
211+
212+
InheritedConstructor() { this = TInheritedConstructor(cls, baseCtor) }
213+
214+
override TypeParameter getTypeParameter(int i) { none() }
215+
216+
override ParameterEx getParameter(int i) {
217+
result.isInheritedConstructorParameter(this, baseCtor, i)
218+
}
219+
220+
override Expr getReturnType() { none() }
221+
222+
override AstNode getBody() { none() }
223+
224+
override Identifier getNameNode() { none() }
225+
226+
override string getName() { result = baseCtor.getName() }
227+
228+
override string toString() {
229+
exists(ClassLikeDeclaration baseCls |
230+
baseCtor.isMemberOf(baseCls) and
231+
result = cls.getName() + " [inherited from " + baseCls.getName() + "]"
232+
)
233+
}
234+
235+
override Location getLocation() { result = cls.getLocation() }
236+
}
237+
238+
final class ParameterEx = ParameterExImpl;
239+
240+
/**
241+
* A parameter from source code or a synthesized parameter.
242+
*/
243+
abstract private class ParameterExImpl extends TParameterEx {
244+
/**
245+
* Gets the source code parameter that this entity represents, if any.
246+
*/
247+
Parameter asParameter() { this = TAstParameter(result) }
248+
249+
/**
250+
* Holds if this entity represents a regular parameter from source code.
251+
*/
252+
predicate isParameter() { exists(this.asParameter()) }
253+
254+
/**
255+
* Holds if this entity represents an implicit receiver parameter of `c`.
256+
*/
257+
predicate isImplicitReceiverParameter(Callable c) { this = TImplicitReceiverParameter(c) }
258+
259+
/**
260+
* Holds if this entity represents the `i`th parameter of the default
261+
* constructor of `cls` with name `name`.
262+
*/
263+
predicate isDefaultConstructorParameter(ClassLikeDeclaration cls, int i, string name) {
264+
this = TDefaultConstructorParameter(cls, i, name)
265+
}
266+
267+
/**
268+
* Holds if this entity represents the `i`th parameter of the inherited constructor
269+
* `ctor` where `baseCtor` is the base constructor.
270+
*/
271+
predicate isInheritedConstructorParameter(CallableEx ctor, CallableEx baseCtor, int i) {
272+
this = TInheritedConstructorParameter(ctor, baseCtor, i)
273+
}
274+
275+
/** Gets a textual representation of this parameter. */
276+
abstract string toString();
277+
278+
/** Gets the location of this parameter. */
279+
abstract Location getLocation();
280+
}
281+
282+
private class AstParameterEx extends ParameterExImpl, TAstParameter {
283+
Parameter p;
284+
285+
AstParameterEx() { this = TAstParameter(p) }
286+
287+
override string toString() { result = p.toString() }
288+
289+
override Location getLocation() { result = p.getLocation() }
290+
}
291+
292+
private class ImplicitReceiverParameterEx extends ParameterExImpl, TImplicitReceiverParameter {
293+
Callable c;
294+
295+
ImplicitReceiverParameterEx() { this = TImplicitReceiverParameter(c) }
296+
297+
override string toString() {
298+
exists(LocalVariable v |
299+
v.isImplicitReceiverParameter(c) and
300+
result = v.getName()
301+
)
302+
}
303+
304+
override Location getLocation() { result = c.getLocation() }
305+
}
306+
307+
private class DefaultConstructorParameterEx extends ParameterExImpl, TDefaultConstructorParameter {
308+
ClassLikeDeclaration c;
309+
int i;
310+
string name;
311+
312+
DefaultConstructorParameterEx() { this = TDefaultConstructorParameter(c, i, name) }
313+
314+
override string toString() { result = name + " [" + c.getName() + " default constructor]" }
315+
316+
override Location getLocation() { result = c.getLocation() }
317+
}
318+
319+
private class InheritedConstructorParameterEx extends ParameterExImpl,
320+
TInheritedConstructorParameter
321+
{
322+
CallableEx ctor;
323+
CallableEx baseCtor;
324+
int i;
325+
326+
InheritedConstructorParameterEx() { this = TInheritedConstructorParameter(ctor, baseCtor, i) }
327+
328+
override string toString() {
329+
exists(ParameterEx baseParam, ClassLikeDeclaration baseCls |
330+
baseCtor.isMemberOf(baseCls) and
331+
baseParam = baseCtor.getParameter(i) and
332+
result =
333+
"parameter " + i + " of " + ctor.getName() + " [inherited from " + baseCls.getName() + "]"
334+
)
335+
}
336+
337+
override Location getLocation() { result = ctor.getLocation() }
338+
}

0 commit comments

Comments
 (0)