Skip to content

Commit 338ce83

Browse files
authored
Merge pull request github#10788 from smowton/smowton/feature/kotlin-default-proxy-getter
Kotlin: Add Callable.getKotlinParameterDefaultsProxy
2 parents 2836c5e + 3b49594 commit 338ce83

File tree

5 files changed

+150
-0
lines changed

5 files changed

+150
-0
lines changed

java/ql/lib/semmle/code/java/Member.qll

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,48 @@ class Callable extends StmtParent, Member, @callable {
294294
constrs(this, _, result, _, _, _) or
295295
methods(this, _, result, _, _, _)
296296
}
297+
298+
/**
299+
* Gets this callable's Kotlin proxy that supplies default parameter values, if one exists.
300+
*
301+
* For example, for the Kotlin declaration `fun f(x: Int, y: Int = 0, z: String = "1")`,
302+
* this will get the synthetic proxy method that fills in the default values for `y` and `z`
303+
* if not supplied, and to which the Kotlin extractor dispatches calls to `f` that are missing
304+
* one or more parameter value. Similarly, constructors with one or more default parameter values
305+
* have a corresponding constructor that fills in default values.
306+
*/
307+
Callable getKotlinParameterDefaultsProxy() {
308+
this.getDeclaringType() = result.getDeclaringType() and
309+
exists(int proxyNParams, int extraLeadingParams, RefType lastParamType |
310+
proxyNParams = result.getNumberOfParameters() and
311+
extraLeadingParams = (proxyNParams - this.getNumberOfParameters()) - 2 and
312+
extraLeadingParams >= 0 and
313+
result.getParameterType(proxyNParams - 1) = lastParamType and
314+
result.getParameterType(proxyNParams - 2).(PrimitiveType).hasName("int") and
315+
(
316+
this instanceof Constructor and
317+
result instanceof Constructor and
318+
extraLeadingParams = 0 and
319+
lastParamType.hasQualifiedName("kotlin.jvm.internal", "DefaultConstructorMarker")
320+
or
321+
this instanceof Method and
322+
result instanceof Method and
323+
this.getName() + "$default" = result.getName() and
324+
extraLeadingParams <= 2 and
325+
lastParamType instanceof TypeObject
326+
)
327+
|
328+
forall(int paramIdx | paramIdx in [extraLeadingParams .. proxyNParams - 3] |
329+
this.getParameterType(paramIdx - extraLeadingParams).getErasure() =
330+
eraseRaw(result.getParameterType(paramIdx))
331+
)
332+
)
333+
}
334+
}
335+
336+
/** Gets the erasure of `t1` if it is a raw type, or `t1` itself otherwise. */
337+
private Type eraseRaw(Type t1) {
338+
if t1 instanceof RawType then result = t1.getErasure() else result = t1
297339
}
298340

299341
/** Holds if method `m1` overrides method `m2`. */

java/ql/test/kotlin/library-tests/parameter-defaults/PrintAst.expected

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,3 +1221,82 @@ test.kt:
12211221
# 173| 5: [BlockStmt] { ... }
12221222
# 173| 0: [ReturnStmt] return ...
12231223
# 173| 0: [VarAccess] t
1224+
# 177| 17: [Class] TestOverloadsWithDefaults
1225+
# 177| 1: [Constructor] TestOverloadsWithDefaults
1226+
# 177| 5: [BlockStmt] { ... }
1227+
# 177| 0: [SuperConstructorInvocationStmt] super(...)
1228+
# 177| 1: [BlockStmt] { ... }
1229+
# 179| 2: [Method] f
1230+
# 179| 3: [TypeAccess] Unit
1231+
#-----| 4: (Parameters)
1232+
# 179| 0: [Parameter] x
1233+
# 179| 0: [TypeAccess] int
1234+
# 179| 1: [Parameter] y
1235+
# 179| 0: [TypeAccess] String
1236+
# 179| 5: [BlockStmt] { ... }
1237+
# 179| 3: [Method] f$default
1238+
# 179| 3: [TypeAccess] Unit
1239+
#-----| 4: (Parameters)
1240+
# 179| 0: [Parameter] p0
1241+
# 179| 0: [TypeAccess] TestOverloadsWithDefaults
1242+
# 179| 1: [Parameter] p1
1243+
# 179| 0: [TypeAccess] int
1244+
# 179| 2: [Parameter] p2
1245+
# 179| 0: [TypeAccess] String
1246+
# 179| 3: [Parameter] p3
1247+
# 179| 0: [TypeAccess] int
1248+
# 179| 4: [Parameter] p4
1249+
# 179| 0: [TypeAccess] Object
1250+
# 179| 5: [BlockStmt] { ... }
1251+
# 179| 0: [IfStmt] if (...)
1252+
# 179| 0: [EQExpr] ... == ...
1253+
# 179| 0: [AndBitwiseExpr] ... & ...
1254+
# 179| 0: [IntegerLiteral] 2
1255+
# 179| 1: [VarAccess] p3
1256+
# 179| 1: [IntegerLiteral] 0
1257+
# 179| 1: [ExprStmt] <Expr>;
1258+
# 179| 0: [AssignExpr] ...=...
1259+
# 179| 0: [VarAccess] p2
1260+
# 179| 1: [StringLiteral] Hello world
1261+
# 179| 1: [ReturnStmt] return ...
1262+
# 179| 0: [MethodAccess] f(...)
1263+
# 179| -1: [VarAccess] p0
1264+
# 179| 0: [VarAccess] p1
1265+
# 179| 1: [VarAccess] p2
1266+
# 180| 4: [Method] f
1267+
# 180| 3: [TypeAccess] Unit
1268+
#-----| 4: (Parameters)
1269+
# 180| 0: [Parameter] z
1270+
# 180| 0: [TypeAccess] String
1271+
# 180| 1: [Parameter] w
1272+
# 180| 0: [TypeAccess] int
1273+
# 180| 5: [BlockStmt] { ... }
1274+
# 180| 5: [Method] f$default
1275+
# 180| 3: [TypeAccess] Unit
1276+
#-----| 4: (Parameters)
1277+
# 180| 0: [Parameter] p0
1278+
# 180| 0: [TypeAccess] TestOverloadsWithDefaults
1279+
# 180| 1: [Parameter] p1
1280+
# 180| 0: [TypeAccess] String
1281+
# 180| 2: [Parameter] p2
1282+
# 180| 0: [TypeAccess] int
1283+
# 180| 3: [Parameter] p3
1284+
# 180| 0: [TypeAccess] int
1285+
# 180| 4: [Parameter] p4
1286+
# 180| 0: [TypeAccess] Object
1287+
# 180| 5: [BlockStmt] { ... }
1288+
# 180| 0: [IfStmt] if (...)
1289+
# 180| 0: [EQExpr] ... == ...
1290+
# 180| 0: [AndBitwiseExpr] ... & ...
1291+
# 180| 0: [IntegerLiteral] 2
1292+
# 180| 1: [VarAccess] p3
1293+
# 180| 1: [IntegerLiteral] 0
1294+
# 180| 1: [ExprStmt] <Expr>;
1295+
# 180| 0: [AssignExpr] ...=...
1296+
# 180| 0: [VarAccess] p2
1297+
# 180| 1: [IntegerLiteral] 0
1298+
# 180| 1: [ReturnStmt] return ...
1299+
# 180| 0: [MethodAccess] f(...)
1300+
# 180| -1: [VarAccess] p0
1301+
# 180| 0: [VarAccess] p1
1302+
# 180| 1: [VarAccess] p2
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
| test.kt:5:3:7:3 | f | test.kt:5:3:7:3 | f$default |
2+
| test.kt:34:14:36:3 | f | test.kt:34:14:36:3 | f$default |
3+
| test.kt:68:1:80:1 | TestConstructor | test.kt:68:1:80:1 | TestConstructor |
4+
| test.kt:86:5:88:5 | f | test.kt:86:5:88:5 | f$default |
5+
| test.kt:106:7:108:7 | f | test.kt:106:7:108:7 | f$default |
6+
| test.kt:124:3:126:3 | f | test.kt:124:3:126:3 | f$default |
7+
| test.kt:135:3:135:43 | testReturn | test.kt:135:3:135:43 | testReturn$default |
8+
| test.kt:145:3:147:3 | f | test.kt:145:3:147:3 | f$default |
9+
| test.kt:158:3:158:35 | f | test.kt:158:3:158:35 | f$default |
10+
| test.kt:159:12:159:44 | g$main | test.kt:159:12:159:44 | g$main$default |
11+
| test.kt:160:13:160:45 | h | test.kt:160:13:160:45 | h$default |
12+
| test.kt:161:11:161:43 | i | test.kt:161:11:161:43 | i$default |
13+
| test.kt:171:3:171:97 | f | test.kt:171:3:171:97 | f$default |
14+
| test.kt:179:3:179:46 | f | test.kt:179:3:179:46 | f$default |
15+
| test.kt:180:3:180:34 | f | test.kt:180:3:180:34 | f$default |
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import java
2+
3+
from Callable realMethod, Callable defaultsProxy
4+
where
5+
defaultsProxy = realMethod.getKotlinParameterDefaultsProxy() and
6+
realMethod.fromSource()
7+
select realMethod, defaultsProxy

java/ql/test/kotlin/library-tests/parameter-defaults/test.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,10 @@ class TestGenericUsedWithinDefaultValue<T> {
173173
fun ident(t: T) = t
174174

175175
}
176+
177+
class TestOverloadsWithDefaults {
178+
179+
fun f(x: Int, y: String = "Hello world") { }
180+
fun f(z: String, w: Int = 0) { }
181+
182+
}

0 commit comments

Comments
 (0)