Skip to content

Commit 00344d0

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

6 files changed

Lines changed: 498 additions & 0 deletions

File tree

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

0 commit comments

Comments
 (0)