mirror of
https://github.com/github/codeql.git
synced 2026-05-01 03:35:13 +02:00
Extract anonymous class for property references (class, constructor, call to constructor, optional parameters)
This commit is contained in:
@@ -2528,8 +2528,7 @@ open class KotlinFileExtractor(
|
||||
extractTypeAccess(e.classType, locId, callable, id, 0, exprParent.enclosingStmt)
|
||||
}
|
||||
is IrPropertyReference -> {
|
||||
// TODO
|
||||
logger.errorElement("Unhandled IrPropertyReference", e)
|
||||
extractPropertyReference(e, parent, callable)
|
||||
}
|
||||
else -> {
|
||||
logger.errorElement("Unrecognised IrExpression: " + e.javaClass, e)
|
||||
@@ -2592,6 +2591,133 @@ open class KotlinFileExtractor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractPropertyReference(
|
||||
propertyReferenceExpr: IrPropertyReference,
|
||||
parent: StmtExprParent,
|
||||
callable: Label<out DbCallable>
|
||||
) {
|
||||
with("property reference", propertyReferenceExpr) {
|
||||
/*
|
||||
* Extract generated class:
|
||||
* ```
|
||||
* class C : kotlin.jvm.internal.PropertyReference, kotlin.reflect.KMutableProperty0<R> {
|
||||
* private dispatchReceiver: TD
|
||||
* constructor(dispatchReceiver: TD) {
|
||||
* super()
|
||||
* this.dispatchReceiver = dispatchReceiver
|
||||
* }
|
||||
*
|
||||
* fun get(): R { return this.dispatchReceiver.FN1() }
|
||||
*
|
||||
* fun set(a0: R): Unit { return this.dispatchReceiver.FN2(a0) }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Variations:
|
||||
* - KProperty vs KMutableProperty
|
||||
* - KProperty0<> vs KProperty1<,>
|
||||
* - no receiver vs dispatchReceiver vs extensionReceiver
|
||||
**/
|
||||
|
||||
val target = propertyReferenceExpr.getter ?: run {
|
||||
logger.errorElement("Expected to find getter for property reference.", propertyReferenceExpr)
|
||||
return
|
||||
}
|
||||
|
||||
val locId = tw.getLocation(propertyReferenceExpr)
|
||||
|
||||
val extensionParameter = target.owner.extensionReceiverParameter
|
||||
val dispatchParameter = target.owner.dispatchReceiverParameter
|
||||
|
||||
var parameters = LinkedList<IrValueParameter>()
|
||||
if (extensionParameter != null && propertyReferenceExpr.extensionReceiver == null) {
|
||||
parameters.addFirst(extensionParameter)
|
||||
}
|
||||
if (dispatchParameter != null && propertyReferenceExpr.dispatchReceiver == null) {
|
||||
parameters.addFirst(dispatchParameter)
|
||||
}
|
||||
|
||||
val parameterTypes = parameters.map { it.type }
|
||||
val kPropertyTypeArguments = parameterTypes + target.owner.returnType
|
||||
|
||||
val kPropertyType = propertyReferenceExpr.type
|
||||
|
||||
val javaResult = TypeResult(tw.getFreshIdLabel<DbClass>(), "", "")
|
||||
val kotlinResult = TypeResult(tw.getFreshIdLabel<DbKt_notnull_type>(), "", "")
|
||||
tw.writeKt_notnull_types(kotlinResult.id, javaResult.id)
|
||||
val ids = LocallyVisibleFunctionLabels(
|
||||
TypeResults(javaResult, kotlinResult),
|
||||
tw.getFreshIdLabel(),
|
||||
tw.getFreshIdLabel(), // not used
|
||||
tw.getFreshIdLabel()
|
||||
)
|
||||
|
||||
val currentDeclaration = declarationStack.peek()
|
||||
// The base class could be `Any`. `PropertyReference` is used to keep symmetry with function references.
|
||||
val baseClass = pluginContext.referenceClass(FqName("kotlin.jvm.internal.PropertyReference"))?.owner?.typeWith()
|
||||
?: pluginContext.irBuiltIns.anyType
|
||||
|
||||
val id = extractGeneratedClass(ids, listOf(baseClass, kPropertyType), locId, currentDeclaration)
|
||||
|
||||
val helper = FunctionReferenceHelper(locId, ids)
|
||||
val firstAssignmentStmtIdx = 1
|
||||
val extensionParameterIndex: Int
|
||||
val dispatchReceiver = propertyReferenceExpr.dispatchReceiver
|
||||
val dispatchFieldId: Label<DbField>?
|
||||
if (dispatchReceiver != null) {
|
||||
dispatchFieldId = tw.getFreshIdLabel()
|
||||
extensionParameterIndex = 1
|
||||
|
||||
extractField(dispatchFieldId, "<dispatchReceiver>", dispatchReceiver.type, id, locId, DescriptorVisibilities.PRIVATE, propertyReferenceExpr, false)
|
||||
helper.extractParameterToFieldAssignmentInConstructor("<dispatchReceiver>", dispatchReceiver.type, dispatchFieldId, 0, firstAssignmentStmtIdx)
|
||||
} else {
|
||||
dispatchFieldId = null
|
||||
extensionParameterIndex = 0
|
||||
}
|
||||
|
||||
val extensionReceiver = propertyReferenceExpr.extensionReceiver
|
||||
val extensionFieldId: Label<out DbField>?
|
||||
if (extensionReceiver != null) {
|
||||
extensionFieldId = tw.getFreshIdLabel()
|
||||
|
||||
extractField(extensionFieldId, "<extensionReceiver>", extensionReceiver.type, id, locId, DescriptorVisibilities.PRIVATE, propertyReferenceExpr, false)
|
||||
helper.extractParameterToFieldAssignmentInConstructor( "<extensionReceiver>", extensionReceiver.type, extensionFieldId, 0 + extensionParameterIndex, firstAssignmentStmtIdx + extensionParameterIndex)
|
||||
} else {
|
||||
extensionFieldId = null
|
||||
}
|
||||
|
||||
|
||||
// todo: add get and set methods with body, call to reflection target (get and set), arguments
|
||||
|
||||
// todo: property ref
|
||||
// Add constructor (property ref) call:
|
||||
val exprParent = parent.expr(propertyReferenceExpr, callable)
|
||||
val idCtorRef = tw.getFreshIdLabel<DbNewexpr>()
|
||||
tw.writeExprs_newexpr(idCtorRef, ids.type.javaResult.id, exprParent.parent, exprParent.idx)
|
||||
tw.writeExprsKotlinType(idCtorRef, ids.type.kotlinResult.id)
|
||||
tw.writeHasLocation(idCtorRef, locId)
|
||||
tw.writeCallableEnclosingExpr(idCtorRef, callable)
|
||||
tw.writeStatementEnclosingExpr(idCtorRef, exprParent.enclosingStmt)
|
||||
tw.writeCallableBinding(idCtorRef, ids.constructor)
|
||||
|
||||
extractTypeAccess(kPropertyType, locId, callable, idCtorRef, -3, exprParent.enclosingStmt)
|
||||
|
||||
// todo: property ref:
|
||||
//tw.writeMemberRefBinding(idMemberRef, targetCallableId)
|
||||
|
||||
// constructor arguments:
|
||||
if (dispatchReceiver != null) {
|
||||
extractExpressionExpr(dispatchReceiver, callable, idCtorRef, 0, exprParent.enclosingStmt)
|
||||
}
|
||||
|
||||
if (extensionReceiver != null) {
|
||||
extractExpressionExpr(extensionReceiver, callable, idCtorRef, 0 + extensionParameterIndex, exprParent.enclosingStmt)
|
||||
}
|
||||
|
||||
tw.writeIsAnonymClass(id, idCtorRef)
|
||||
}
|
||||
}
|
||||
|
||||
private fun extractFunctionReference(
|
||||
functionReferenceExpr: IrFunctionReference,
|
||||
parent: StmtExprParent,
|
||||
@@ -2634,6 +2760,7 @@ open class KotlinFileExtractor(
|
||||
val typeArguments = if (target is IrConstructorSymbol) {
|
||||
(target.owner.returnType as? IrSimpleType)?.arguments
|
||||
} else {
|
||||
// todo: do we need to check the arguments of the extensionReceiver?
|
||||
(functionReferenceExpr.dispatchReceiver?.type as? IrSimpleType)?.arguments
|
||||
}
|
||||
|
||||
@@ -2661,11 +2788,12 @@ open class KotlinFileExtractor(
|
||||
val ids = LocallyVisibleFunctionLabels(
|
||||
TypeResults(javaResult, kotlinResult),
|
||||
tw.getFreshIdLabel(),
|
||||
tw.getFreshIdLabel(),
|
||||
tw.getFreshIdLabel(), // not used
|
||||
tw.getFreshIdLabel()
|
||||
)
|
||||
|
||||
val currentDeclaration = declarationStack.peek()
|
||||
// `FunctionReference` base class is required, because that's implementing `KFunction`.
|
||||
val baseClass = pluginContext.referenceClass(FqName("kotlin.jvm.internal.FunctionReference"))?.owner?.typeWith()
|
||||
?: pluginContext.irBuiltIns.anyType
|
||||
|
||||
|
||||
@@ -18,11 +18,33 @@ reflection.kt:
|
||||
# 48| 0: [MethodAccess] println(...)
|
||||
# 48| -1: [TypeAccess] ConsoleKt
|
||||
# 48| 0: [MethodAccess] get(...)
|
||||
# 48| -1: [ClassInstanceExpr] new (...)
|
||||
# 48| -4: [AnonymousClass] new KProperty1<String,Character>(...) { ... }
|
||||
# 48| 1: [Constructor]
|
||||
# 48| 5: [BlockStmt] { ... }
|
||||
# 48| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 48| -3: [TypeAccess] KProperty1<String,Character>
|
||||
# 48| 0: [StringLiteral] abc
|
||||
# 49| 1: [ExprStmt] <Expr>;
|
||||
# 49| 0: [MethodAccess] println(...)
|
||||
# 49| -1: [TypeAccess] ConsoleKt
|
||||
# 49| 0: [MethodAccess] get(...)
|
||||
# 49| -1: [ClassInstanceExpr] new (...)
|
||||
# 49| -4: [AnonymousClass] new KProperty0<Character>(...) { ... }
|
||||
# 49| 1: [Constructor]
|
||||
#-----| 4: (Parameters)
|
||||
# 49| 0: [Parameter] <extensionReceiver>
|
||||
# 49| 5: [BlockStmt] { ... }
|
||||
# 49| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 49| 1: [ExprStmt] <Expr>;
|
||||
# 49| 0: [AssignExpr] ...=...
|
||||
# 49| 0: [VarAccess] this.<extensionReceiver>
|
||||
# 49| -1: [ThisAccess] this
|
||||
# 49| 1: [VarAccess] <extensionReceiver>
|
||||
# 49| 1: [FieldDeclaration] String <extensionReceiver>;
|
||||
# 49| -1: [TypeAccess] String
|
||||
# 49| -3: [TypeAccess] KProperty0<Character>
|
||||
# 49| 0: [StringLiteral] abcd
|
||||
# 3| 2: [Class] Reflection
|
||||
# 3| 1: [Constructor] Reflection
|
||||
# 3| 5: [BlockStmt] { ... }
|
||||
@@ -55,6 +77,12 @@ reflection.kt:
|
||||
# 6| -1: [VarAccess] ref
|
||||
# 8| 2: [LocalVariableDeclStmt] var ...;
|
||||
# 8| 1: [LocalVariableDeclExpr] x0
|
||||
# 8| 0: [ClassInstanceExpr] new (...)
|
||||
# 8| -4: [AnonymousClass] new KProperty1<C,Integer>(...) { ... }
|
||||
# 8| 1: [Constructor]
|
||||
# 8| 5: [BlockStmt] { ... }
|
||||
# 8| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 8| -3: [TypeAccess] KProperty1<C,Integer>
|
||||
# 9| 3: [LocalVariableDeclStmt] var ...;
|
||||
# 9| 1: [LocalVariableDeclExpr] x1
|
||||
# 9| 0: [MethodAccess] get(...)
|
||||
@@ -98,8 +126,31 @@ reflection.kt:
|
||||
# 12| 0: [VarAccess] x0
|
||||
# 13| 7: [LocalVariableDeclStmt] var ...;
|
||||
# 13| 1: [LocalVariableDeclExpr] x5
|
||||
# 13| 0: [ClassInstanceExpr] new (...)
|
||||
# 13| -4: [AnonymousClass] new KProperty0<Integer>(...) { ... }
|
||||
# 13| 1: [Constructor]
|
||||
#-----| 4: (Parameters)
|
||||
# 13| 0: [Parameter] <dispatchReceiver>
|
||||
# 13| 5: [BlockStmt] { ... }
|
||||
# 13| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 13| 1: [ExprStmt] <Expr>;
|
||||
# 13| 0: [AssignExpr] ...=...
|
||||
# 13| 0: [VarAccess] this.<dispatchReceiver>
|
||||
# 13| -1: [ThisAccess] this
|
||||
# 13| 1: [VarAccess] <dispatchReceiver>
|
||||
# 13| 1: [FieldDeclaration] C <dispatchReceiver>;
|
||||
# 13| -1: [TypeAccess] C
|
||||
# 13| -3: [TypeAccess] KProperty0<Integer>
|
||||
# 13| 0: [ClassInstanceExpr] new C(...)
|
||||
# 13| -3: [TypeAccess] C
|
||||
# 15| 8: [LocalVariableDeclStmt] var ...;
|
||||
# 15| 1: [LocalVariableDeclExpr] y0
|
||||
# 15| 0: [ClassInstanceExpr] new (...)
|
||||
# 15| -4: [AnonymousClass] new KMutableProperty1<C,Integer>(...) { ... }
|
||||
# 15| 1: [Constructor]
|
||||
# 15| 5: [BlockStmt] { ... }
|
||||
# 15| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 15| -3: [TypeAccess] KMutableProperty1<C,Integer>
|
||||
# 16| 9: [LocalVariableDeclStmt] var ...;
|
||||
# 16| 1: [LocalVariableDeclExpr] y1
|
||||
# 16| 0: [MethodAccess] set(...)
|
||||
@@ -146,6 +197,23 @@ reflection.kt:
|
||||
# 19| 0: [VarAccess] y0
|
||||
# 20| 13: [LocalVariableDeclStmt] var ...;
|
||||
# 20| 1: [LocalVariableDeclExpr] y5
|
||||
# 20| 0: [ClassInstanceExpr] new (...)
|
||||
# 20| -4: [AnonymousClass] new KMutableProperty0<Integer>(...) { ... }
|
||||
# 20| 1: [Constructor]
|
||||
#-----| 4: (Parameters)
|
||||
# 20| 0: [Parameter] <dispatchReceiver>
|
||||
# 20| 5: [BlockStmt] { ... }
|
||||
# 20| 0: [SuperConstructorInvocationStmt] super(...)
|
||||
# 20| 1: [ExprStmt] <Expr>;
|
||||
# 20| 0: [AssignExpr] ...=...
|
||||
# 20| 0: [VarAccess] this.<dispatchReceiver>
|
||||
# 20| -1: [ThisAccess] this
|
||||
# 20| 1: [VarAccess] <dispatchReceiver>
|
||||
# 20| 1: [FieldDeclaration] C <dispatchReceiver>;
|
||||
# 20| -1: [TypeAccess] C
|
||||
# 20| -3: [TypeAccess] KMutableProperty0<Integer>
|
||||
# 20| 0: [ClassInstanceExpr] new C(...)
|
||||
# 20| -3: [TypeAccess] C
|
||||
# 22| 14: [LocalVariableDeclStmt] var ...;
|
||||
# 22| 1: [LocalVariableDeclExpr] prop
|
||||
# 22| 0: [CastExpr] (...)...
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
variableInitializerType
|
||||
| reflection.kt:5:9:5:54 | KFunction<Double> ref | file://<external>/KFunction.class:0:0:0:0 | KFunction<Double> | reflection.kt:5:49:5:54 | new Function2<Ccc,Integer,Double>(...) { ... } | file://<external>/Function2.class:0:0:0:0 | Function2<Ccc,Integer,Double> | true |
|
||||
| reflection.kt:5:9:5:54 | KFunction<Double> ref | file://<external>/KFunction.class:0:0:0:0 | KFunction<Double> | reflection.kt:5:49:5:54 | new Function2<Ccc,Integer,Double>(...) { ... } | file://<external>/FunctionReference.class:0:0:0:0 | FunctionReference | true |
|
||||
| reflection.kt:8:9:8:42 | KProperty1<C,Integer> x0 | file://<external>/KProperty1.class:0:0:0:0 | KProperty1<C,Integer> | reflection.kt:8:38:8:42 | new KProperty1<C,Integer>(...) { ... } | file://<external>/KProperty1.class:0:0:0:0 | KProperty1<C,Integer> | true |
|
||||
| reflection.kt:8:9:8:42 | KProperty1<C,Integer> x0 | file://<external>/KProperty1.class:0:0:0:0 | KProperty1<C,Integer> | reflection.kt:8:38:8:42 | new KProperty1<C,Integer>(...) { ... } | file://<external>/PropertyReference.class:0:0:0:0 | PropertyReference | true |
|
||||
| reflection.kt:11:9:11:53 | Getter<C,Integer> x3 | file://<external>/KProperty1$Getter.class:0:0:0:0 | Getter<C,Integer> | file://<external>/KProperty1$Getter.class:0:0:0:0 | Getter<C,Integer> | file://<external>/Function1.class:0:0:0:0 | Function1<C,Integer> | true |
|
||||
| reflection.kt:11:9:11:53 | Getter<C,Integer> x3 | file://<external>/KProperty1$Getter.class:0:0:0:0 | Getter<C,Integer> | file://<external>/KProperty1$Getter.class:0:0:0:0 | Getter<C,Integer> | file://<external>/KProperty$Getter.class:0:0:0:0 | Getter<Integer> | true |
|
||||
| reflection.kt:12:9:12:44 | KFunction<Integer> x4 | file://<external>/KFunction.class:0:0:0:0 | KFunction<Integer> | reflection.kt:12:38:12:44 | new Function1<T,V>(...) { ... } | file://<external>/Function1.class:0:0:0:0 | Function1<T,V> | true |
|
||||
| reflection.kt:12:9:12:44 | KFunction<Integer> x4 | file://<external>/KFunction.class:0:0:0:0 | KFunction<Integer> | reflection.kt:12:38:12:44 | new Function1<T,V>(...) { ... } | file://<external>/FunctionReference.class:0:0:0:0 | FunctionReference | true |
|
||||
| reflection.kt:13:9:13:41 | KProperty0<Integer> x5 | file://<external>/KProperty0.class:0:0:0:0 | KProperty0<Integer> | reflection.kt:13:35:13:41 | new KProperty0<Integer>(...) { ... } | file://<external>/KProperty0.class:0:0:0:0 | KProperty0<Integer> | true |
|
||||
| reflection.kt:13:9:13:41 | KProperty0<Integer> x5 | file://<external>/KProperty0.class:0:0:0:0 | KProperty0<Integer> | reflection.kt:13:35:13:41 | new KProperty0<Integer>(...) { ... } | file://<external>/PropertyReference.class:0:0:0:0 | PropertyReference | true |
|
||||
| reflection.kt:15:9:15:49 | KMutableProperty1<C,Integer> y0 | file://<external>/KMutableProperty1.class:0:0:0:0 | KMutableProperty1<C,Integer> | reflection.kt:15:45:15:49 | new KMutableProperty1<C,Integer>(...) { ... } | file://<external>/KMutableProperty1.class:0:0:0:0 | KMutableProperty1<C,Integer> | true |
|
||||
| reflection.kt:15:9:15:49 | KMutableProperty1<C,Integer> y0 | file://<external>/KMutableProperty1.class:0:0:0:0 | KMutableProperty1<C,Integer> | reflection.kt:15:45:15:49 | new KMutableProperty1<C,Integer>(...) { ... } | file://<external>/PropertyReference.class:0:0:0:0 | PropertyReference | true |
|
||||
| reflection.kt:18:9:18:60 | Setter<C,Integer> y3 | file://<external>/KMutableProperty1$Setter.class:0:0:0:0 | Setter<C,Integer> | file://<external>/KMutableProperty1$Setter.class:0:0:0:0 | Setter<C,Integer> | file://<external>/Function2.class:0:0:0:0 | Function2<C,Integer,Unit> | true |
|
||||
| reflection.kt:18:9:18:60 | Setter<C,Integer> y3 | file://<external>/KMutableProperty1$Setter.class:0:0:0:0 | Setter<C,Integer> | file://<external>/KMutableProperty1$Setter.class:0:0:0:0 | Setter<C,Integer> | file://<external>/KMutableProperty$Setter.class:0:0:0:0 | Setter<Integer> | true |
|
||||
| reflection.kt:19:9:19:50 | KFunction<Unit> y4 | file://<external>/KFunction.class:0:0:0:0 | KFunction<Unit> | reflection.kt:19:44:19:50 | new Function2<T,V,Unit>(...) { ... } | file://<external>/Function2.class:0:0:0:0 | Function2<T,V,Unit> | true |
|
||||
| reflection.kt:19:9:19:50 | KFunction<Unit> y4 | file://<external>/KFunction.class:0:0:0:0 | KFunction<Unit> | reflection.kt:19:44:19:50 | new Function2<T,V,Unit>(...) { ... } | file://<external>/FunctionReference.class:0:0:0:0 | FunctionReference | true |
|
||||
| reflection.kt:20:9:20:48 | KMutableProperty0<Integer> y5 | file://<external>/KMutableProperty0.class:0:0:0:0 | KMutableProperty0<Integer> | reflection.kt:20:42:20:48 | new KMutableProperty0<Integer>(...) { ... } | file://<external>/KMutableProperty0.class:0:0:0:0 | KMutableProperty0<Integer> | true |
|
||||
| reflection.kt:20:9:20:48 | KMutableProperty0<Integer> y5 | file://<external>/KMutableProperty0.class:0:0:0:0 | KMutableProperty0<Integer> | reflection.kt:20:42:20:48 | new KMutableProperty0<Integer>(...) { ... } | file://<external>/PropertyReference.class:0:0:0:0 | PropertyReference | true |
|
||||
| reflection.kt:22:9:22:91 | KProperty2<C,Integer,Integer> prop | file://<external>/KProperty2.class:0:0:0:0 | KProperty2<C,Integer,Integer> | file://<external>/KProperty2.class:0:0:0:0 | KProperty2<C,Integer,Integer> | file://<external>/Function2.class:0:0:0:0 | Function2<C,Integer,Integer> | true |
|
||||
| reflection.kt:22:9:22:91 | KProperty2<C,Integer,Integer> prop | file://<external>/KProperty2.class:0:0:0:0 | KProperty2<C,Integer,Integer> | file://<external>/KProperty2.class:0:0:0:0 | KProperty2<C,Integer,Integer> | file://<external>/KProperty.class:0:0:0:0 | KProperty<Integer> | true |
|
||||
invocation
|
||||
|
||||
Reference in New Issue
Block a user