Merge pull request #10788 from smowton/smowton/feature/kotlin-default-proxy-getter

Kotlin: Add Callable.getKotlinParameterDefaultsProxy
This commit is contained in:
Chris Smowton
2022-10-12 14:16:09 +01:00
committed by GitHub
5 changed files with 150 additions and 0 deletions

View File

@@ -294,6 +294,48 @@ class Callable extends StmtParent, Member, @callable {
constrs(this, _, result, _, _, _) or
methods(this, _, result, _, _, _)
}
/**
* Gets this callable's Kotlin proxy that supplies default parameter values, if one exists.
*
* For example, for the Kotlin declaration `fun f(x: Int, y: Int = 0, z: String = "1")`,
* this will get the synthetic proxy method that fills in the default values for `y` and `z`
* if not supplied, and to which the Kotlin extractor dispatches calls to `f` that are missing
* one or more parameter value. Similarly, constructors with one or more default parameter values
* have a corresponding constructor that fills in default values.
*/
Callable getKotlinParameterDefaultsProxy() {
this.getDeclaringType() = result.getDeclaringType() and
exists(int proxyNParams, int extraLeadingParams, RefType lastParamType |
proxyNParams = result.getNumberOfParameters() and
extraLeadingParams = (proxyNParams - this.getNumberOfParameters()) - 2 and
extraLeadingParams >= 0 and
result.getParameterType(proxyNParams - 1) = lastParamType and
result.getParameterType(proxyNParams - 2).(PrimitiveType).hasName("int") and
(
this instanceof Constructor and
result instanceof Constructor and
extraLeadingParams = 0 and
lastParamType.hasQualifiedName("kotlin.jvm.internal", "DefaultConstructorMarker")
or
this instanceof Method and
result instanceof Method and
this.getName() + "$default" = result.getName() and
extraLeadingParams <= 2 and
lastParamType instanceof TypeObject
)
|
forall(int paramIdx | paramIdx in [extraLeadingParams .. proxyNParams - 3] |
this.getParameterType(paramIdx - extraLeadingParams).getErasure() =
eraseRaw(result.getParameterType(paramIdx))
)
)
}
}
/** Gets the erasure of `t1` if it is a raw type, or `t1` itself otherwise. */
private Type eraseRaw(Type t1) {
if t1 instanceof RawType then result = t1.getErasure() else result = t1
}
/** Holds if method `m1` overrides method `m2`. */

View File

@@ -1221,3 +1221,82 @@ test.kt:
# 173| 5: [BlockStmt] { ... }
# 173| 0: [ReturnStmt] return ...
# 173| 0: [VarAccess] t
# 177| 17: [Class] TestOverloadsWithDefaults
# 177| 1: [Constructor] TestOverloadsWithDefaults
# 177| 5: [BlockStmt] { ... }
# 177| 0: [SuperConstructorInvocationStmt] super(...)
# 177| 1: [BlockStmt] { ... }
# 179| 2: [Method] f
# 179| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 179| 0: [Parameter] x
# 179| 0: [TypeAccess] int
# 179| 1: [Parameter] y
# 179| 0: [TypeAccess] String
# 179| 5: [BlockStmt] { ... }
# 179| 3: [Method] f$default
# 179| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 179| 0: [Parameter] p0
# 179| 0: [TypeAccess] TestOverloadsWithDefaults
# 179| 1: [Parameter] p1
# 179| 0: [TypeAccess] int
# 179| 2: [Parameter] p2
# 179| 0: [TypeAccess] String
# 179| 3: [Parameter] p3
# 179| 0: [TypeAccess] int
# 179| 4: [Parameter] p4
# 179| 0: [TypeAccess] Object
# 179| 5: [BlockStmt] { ... }
# 179| 0: [IfStmt] if (...)
# 179| 0: [EQExpr] ... == ...
# 179| 0: [AndBitwiseExpr] ... & ...
# 179| 0: [IntegerLiteral] 2
# 179| 1: [VarAccess] p3
# 179| 1: [IntegerLiteral] 0
# 179| 1: [ExprStmt] <Expr>;
# 179| 0: [AssignExpr] ...=...
# 179| 0: [VarAccess] p2
# 179| 1: [StringLiteral] Hello world
# 179| 1: [ReturnStmt] return ...
# 179| 0: [MethodAccess] f(...)
# 179| -1: [VarAccess] p0
# 179| 0: [VarAccess] p1
# 179| 1: [VarAccess] p2
# 180| 4: [Method] f
# 180| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 180| 0: [Parameter] z
# 180| 0: [TypeAccess] String
# 180| 1: [Parameter] w
# 180| 0: [TypeAccess] int
# 180| 5: [BlockStmt] { ... }
# 180| 5: [Method] f$default
# 180| 3: [TypeAccess] Unit
#-----| 4: (Parameters)
# 180| 0: [Parameter] p0
# 180| 0: [TypeAccess] TestOverloadsWithDefaults
# 180| 1: [Parameter] p1
# 180| 0: [TypeAccess] String
# 180| 2: [Parameter] p2
# 180| 0: [TypeAccess] int
# 180| 3: [Parameter] p3
# 180| 0: [TypeAccess] int
# 180| 4: [Parameter] p4
# 180| 0: [TypeAccess] Object
# 180| 5: [BlockStmt] { ... }
# 180| 0: [IfStmt] if (...)
# 180| 0: [EQExpr] ... == ...
# 180| 0: [AndBitwiseExpr] ... & ...
# 180| 0: [IntegerLiteral] 2
# 180| 1: [VarAccess] p3
# 180| 1: [IntegerLiteral] 0
# 180| 1: [ExprStmt] <Expr>;
# 180| 0: [AssignExpr] ...=...
# 180| 0: [VarAccess] p2
# 180| 1: [IntegerLiteral] 0
# 180| 1: [ReturnStmt] return ...
# 180| 0: [MethodAccess] f(...)
# 180| -1: [VarAccess] p0
# 180| 0: [VarAccess] p1
# 180| 1: [VarAccess] p2

View File

@@ -0,0 +1,15 @@
| test.kt:5:3:7:3 | f | test.kt:5:3:7:3 | f$default |
| test.kt:34:14:36:3 | f | test.kt:34:14:36:3 | f$default |
| test.kt:68:1:80:1 | TestConstructor | test.kt:68:1:80:1 | TestConstructor |
| test.kt:86:5:88:5 | f | test.kt:86:5:88:5 | f$default |
| test.kt:106:7:108:7 | f | test.kt:106:7:108:7 | f$default |
| test.kt:124:3:126:3 | f | test.kt:124:3:126:3 | f$default |
| test.kt:135:3:135:43 | testReturn | test.kt:135:3:135:43 | testReturn$default |
| test.kt:145:3:147:3 | f | test.kt:145:3:147:3 | f$default |
| test.kt:158:3:158:35 | f | test.kt:158:3:158:35 | f$default |
| test.kt:159:12:159:44 | g$main | test.kt:159:12:159:44 | g$main$default |
| test.kt:160:13:160:45 | h | test.kt:160:13:160:45 | h$default |
| test.kt:161:11:161:43 | i | test.kt:161:11:161:43 | i$default |
| test.kt:171:3:171:97 | f | test.kt:171:3:171:97 | f$default |
| test.kt:179:3:179:46 | f | test.kt:179:3:179:46 | f$default |
| test.kt:180:3:180:34 | f | test.kt:180:3:180:34 | f$default |

View File

@@ -0,0 +1,7 @@
import java
from Callable realMethod, Callable defaultsProxy
where
defaultsProxy = realMethod.getKotlinParameterDefaultsProxy() and
realMethod.fromSource()
select realMethod, defaultsProxy

View File

@@ -173,3 +173,10 @@ class TestGenericUsedWithinDefaultValue<T> {
fun ident(t: T) = t
}
class TestOverloadsWithDefaults {
fun f(x: Int, y: String = "Hello world") { }
fun f(z: String, w: Int = 0) { }
}