Skip to content

Commit ec06876

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

7 files changed

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

0 commit comments

Comments
 (0)