Add get/set method extraction for property references

This commit is contained in:
Tamas Vajk
2022-02-23 13:23:56 +01:00
committed by Ian Lynagh
parent 4ce813a720
commit b4b1976bc4
2 changed files with 229 additions and 22 deletions

View File

@@ -2619,27 +2619,15 @@ open class KotlinFileExtractor(
* - no receiver vs dispatchReceiver vs extensionReceiver
**/
val target = propertyReferenceExpr.getter ?: run {
logger.errorElement("Expected to find getter for property reference.", propertyReferenceExpr)
val getter = propertyReferenceExpr.getter
val setter = propertyReferenceExpr.setter
if (getter == null && setter == null) {
logger.errorElement("Expected to find getter or setter 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>(), "", "")
@@ -2686,8 +2674,165 @@ open class KotlinFileExtractor(
extensionFieldId = null
}
val accessor = (getter ?: setter)!!
val extensionParameter = accessor.owner.extensionReceiverParameter
val dispatchParameter = accessor.owner.dispatchReceiverParameter
// todo: add get and set methods with body, call to reflection target (get and set), arguments
var parameters = LinkedList<IrValueParameter>()
if (extensionParameter != null && propertyReferenceExpr.extensionReceiver == null) {
parameters.addFirst(extensionParameter)
}
if (dispatchParameter != null && propertyReferenceExpr.dispatchReceiver == null) {
parameters.addFirst(dispatchParameter)
}
if (getter != null) {
val getterParameterTypes = parameters.map { it.type }
val getLabels = addFunctionManual("get", getterParameterTypes, getter.owner.returnType, id, locId)
// Return statement of generated function:
val retId = tw.getFreshIdLabel<DbReturnstmt>()
tw.writeStmts_returnstmt(retId, getLabels.blockId, 0, getLabels.methodId)
tw.writeHasLocation(retId, locId)
// Call to target function:
val callId: Label<out DbExpr>
val callType = useType(getter.owner.returnType)
callId = tw.getFreshIdLabel<DbMethodaccess>()
tw.writeExprs_methodaccess(callId, callType.javaResult.id, retId, 0)
tw.writeExprsKotlinType(callId, callType.kotlinResult.id)
extractTypeArguments(propertyReferenceExpr, callId, getLabels.methodId, retId, -2, true)
helper.writeExpressionMetadataToTrapFile(callId, getLabels.methodId, retId)
// todo: type arguments
val getterCallableId = useFunction<DbCallable>(getter.owner, null)
@Suppress("UNCHECKED_CAST")
tw.writeCallableBinding(callId as Label<out DbCaller>, getterCallableId)
fun writeVariableAccessInFunctionBody(
pType: TypeResults,
idx: Int,
variable: Label<out DbVariable>
): Label<DbVaraccess> {
val pId = tw.getFreshIdLabel<DbVaraccess>()
tw.writeExprs_varaccess(pId, pType.javaResult.id, callId, idx)
tw.writeExprsKotlinType(pId, pType.kotlinResult.id)
tw.writeVariableBinding(pId, variable)
helper.writeExpressionMetadataToTrapFile(pId, getLabels.methodId, retId)
return pId
}
fun writeFieldAccessInFunctionBody(pType: IrType, idx: Int, variable: Label<out DbField>) {
val accessId = writeVariableAccessInFunctionBody(useType(pType), idx, variable)
val thisId = tw.getFreshIdLabel<DbThisaccess>()
tw.writeExprs_thisaccess(thisId, ids.type.javaResult.id, accessId, -1)
tw.writeExprsKotlinType(thisId, ids.type.kotlinResult.id)
helper.writeExpressionMetadataToTrapFile(thisId, getLabels.methodId, retId)
}
val useFirstArgAsDispatch: Boolean
if (dispatchReceiver != null) {
writeFieldAccessInFunctionBody(dispatchReceiver.type, -1, dispatchFieldId!!)
useFirstArgAsDispatch = false
} else {
useFirstArgAsDispatch = dispatchParameter != null
}
val extensionIdxOffset: Int
if (extensionReceiver != null) {
writeFieldAccessInFunctionBody(extensionReceiver.type, 0, extensionFieldId!!)
extensionIdxOffset = 1
} else {
extensionIdxOffset = 0
}
val dispatchIdxOffset = if (useFirstArgAsDispatch) 1 else 0
for ((pIdx, p) in getLabels.parameters.withIndex()) {
val childIdx = if (pIdx == 0 && useFirstArgAsDispatch) {
-1
} else {
pIdx + extensionIdxOffset - dispatchIdxOffset
}
writeVariableAccessInFunctionBody(p.second, childIdx, p.first)
}
}
if (setter != null) {
val setterParameterTypes = parameters.map { it.type } + setter.owner.valueParameters.map { it.type }
val setLabels = addFunctionManual("set", setterParameterTypes, setter.owner.returnType, id, locId)
// Return statement of generated function:
val retId = tw.getFreshIdLabel<DbReturnstmt>()
tw.writeStmts_returnstmt(retId, setLabels.blockId, 0, setLabels.methodId)
tw.writeHasLocation(retId, locId)
// Call to target function:
val callId: Label<out DbExpr>
val callType = useType(setter.owner.returnType)
callId = tw.getFreshIdLabel<DbMethodaccess>()
tw.writeExprs_methodaccess(callId, callType.javaResult.id, retId, 0)
tw.writeExprsKotlinType(callId, callType.kotlinResult.id)
extractTypeArguments(propertyReferenceExpr, callId, setLabels.methodId, retId, -2, true)
helper.writeExpressionMetadataToTrapFile(callId, setLabels.methodId, retId)
// todo: type arguments
val setterCallableId = useFunction<DbCallable>(setter.owner, null)
@Suppress("UNCHECKED_CAST")
tw.writeCallableBinding(callId as Label<out DbCaller>, setterCallableId)
fun writeVariableAccessInFunctionBody(
pType: TypeResults,
idx: Int,
variable: Label<out DbVariable>
): Label<DbVaraccess> {
val pId = tw.getFreshIdLabel<DbVaraccess>()
tw.writeExprs_varaccess(pId, pType.javaResult.id, callId, idx)
tw.writeExprsKotlinType(pId, pType.kotlinResult.id)
tw.writeVariableBinding(pId, variable)
helper.writeExpressionMetadataToTrapFile(pId, setLabels.methodId, retId)
return pId
}
fun writeFieldAccessInFunctionBody(pType: IrType, idx: Int, variable: Label<out DbField>) {
val accessId = writeVariableAccessInFunctionBody(useType(pType), idx, variable)
val thisId = tw.getFreshIdLabel<DbThisaccess>()
tw.writeExprs_thisaccess(thisId, ids.type.javaResult.id, accessId, -1)
tw.writeExprsKotlinType(thisId, ids.type.kotlinResult.id)
helper.writeExpressionMetadataToTrapFile(thisId, setLabels.methodId, retId)
}
val useFirstArgAsDispatch: Boolean
if (dispatchReceiver != null) {
writeFieldAccessInFunctionBody(dispatchReceiver.type, -1, dispatchFieldId!!)
useFirstArgAsDispatch = false
} else {
useFirstArgAsDispatch = dispatchParameter != null
}
val extensionIdxOffset: Int
if (extensionReceiver != null) {
writeFieldAccessInFunctionBody(extensionReceiver.type, 0, extensionFieldId!!)
extensionIdxOffset = 1
} else {
extensionIdxOffset = 0
}
val dispatchIdxOffset = if (useFirstArgAsDispatch) 1 else 0
for ((pIdx, p) in setLabels.parameters.withIndex()) {
val childIdx = if (pIdx == 0 && useFirstArgAsDispatch) {
-1
} else {
pIdx + extensionIdxOffset - dispatchIdxOffset
}
writeVariableAccessInFunctionBody(p.second, childIdx, p.first)
}
}
// todo: property ref
// Add constructor (property ref) call:
@@ -2972,9 +3117,16 @@ open class KotlinFileExtractor(
}
/**
* Adds a function named "invoke" with the specified parameter types and return type to the class identified by parentId.
* Adds a function named "invoke" with the specified parameter types and return type to the class identified by `parentId`.
*/
private fun addFunctionInvoke(parameterTypes: List<IrType>, returnType: IrType, parentId: Label<out DbReftype>, locId: Label<DbLocation>): FunctionLabels {
return addFunctionManual(OperatorNameConventions.INVOKE.asString(), parameterTypes, returnType, parentId, locId)
}
/**
* Extracts a function with the given name, parameter types, return type, and containing type.
*/
private fun addFunctionManual(name: String, parameterTypes: List<IrType>, returnType: IrType, parentId: Label<out DbReftype>, locId: Label<DbLocation>): FunctionLabels {
val methodId = tw.getFreshIdLabel<DbMethod>()
val parameters = parameterTypes.mapIndexed { idx, p ->
@@ -2987,8 +3139,7 @@ open class KotlinFileExtractor(
val paramsSignature = parameters.joinToString(separator = ",", prefix = "(", postfix = ")") { it.second.javaResult.signature!! }
val rt = useType(returnType, TypeContext.RETURN)
val shortName = OperatorNameConventions.INVOKE.asString()
tw.writeMethods(methodId, shortName, "$shortName$paramsSignature", rt.javaResult.id, parentId, methodId)
tw.writeMethods(methodId, name, "$name$paramsSignature", rt.javaResult.id, parentId, methodId)
tw.writeMethodsKotlinType(methodId, rt.kotlinResult.id)
tw.writeHasLocation(methodId, locId)
@@ -3000,7 +3151,6 @@ open class KotlinFileExtractor(
return FunctionLabels(methodId, blockId, parameters)
}
/*
* This function generates an implementation for `fun kotlin.FunctionN<R>.invoke(vararg args: Any?): R`
*

View File

@@ -23,6 +23,13 @@ reflection.kt:
# 48| 1: [Constructor]
# 48| 5: [BlockStmt] { ... }
# 48| 0: [SuperConstructorInvocationStmt] super(...)
# 48| 1: [Method] get
#-----| 4: (Parameters)
# 48| 0: [Parameter] a0
# 48| 5: [BlockStmt] { ... }
# 48| 0: [ReturnStmt] return ...
# 48| 0: [MethodAccess] getLastChar(...)
# 48| 0: [VarAccess] a0
# 48| -3: [TypeAccess] KProperty1<String,Character>
# 48| 0: [StringLiteral] abc
# 49| 1: [ExprStmt] <Expr>;
@@ -43,6 +50,12 @@ reflection.kt:
# 49| 1: [VarAccess] <extensionReceiver>
# 49| 1: [FieldDeclaration] String <extensionReceiver>;
# 49| -1: [TypeAccess] String
# 49| 1: [Method] get
# 49| 5: [BlockStmt] { ... }
# 49| 0: [ReturnStmt] return ...
# 49| 0: [MethodAccess] getLastChar(...)
# 49| 0: [VarAccess] this.<extensionReceiver>
# 49| -1: [ThisAccess] this
# 49| -3: [TypeAccess] KProperty0<Character>
# 49| 0: [StringLiteral] abcd
# 3| 2: [Class] Reflection
@@ -82,6 +95,13 @@ reflection.kt:
# 8| 1: [Constructor]
# 8| 5: [BlockStmt] { ... }
# 8| 0: [SuperConstructorInvocationStmt] super(...)
# 8| 1: [Method] get
#-----| 4: (Parameters)
# 8| 0: [Parameter] a0
# 8| 5: [BlockStmt] { ... }
# 8| 0: [ReturnStmt] return ...
# 8| 0: [MethodAccess] getP0(...)
# 8| -1: [VarAccess] a0
# 8| -3: [TypeAccess] KProperty1<C,Integer>
# 9| 3: [LocalVariableDeclStmt] var ...;
# 9| 1: [LocalVariableDeclExpr] x1
@@ -140,6 +160,12 @@ reflection.kt:
# 13| 1: [VarAccess] <dispatchReceiver>
# 13| 1: [FieldDeclaration] C <dispatchReceiver>;
# 13| -1: [TypeAccess] C
# 13| 1: [Method] get
# 13| 5: [BlockStmt] { ... }
# 13| 0: [ReturnStmt] return ...
# 13| 0: [MethodAccess] getP0(...)
# 13| -1: [VarAccess] this.<dispatchReceiver>
# 13| -1: [ThisAccess] this
# 13| -3: [TypeAccess] KProperty0<Integer>
# 13| 0: [ClassInstanceExpr] new C(...)
# 13| -3: [TypeAccess] C
@@ -150,6 +176,22 @@ reflection.kt:
# 15| 1: [Constructor]
# 15| 5: [BlockStmt] { ... }
# 15| 0: [SuperConstructorInvocationStmt] super(...)
# 15| 1: [Method] get
#-----| 4: (Parameters)
# 15| 0: [Parameter] a0
# 15| 5: [BlockStmt] { ... }
# 15| 0: [ReturnStmt] return ...
# 15| 0: [MethodAccess] getP1(...)
# 15| -1: [VarAccess] a0
# 15| 1: [Method] set
#-----| 4: (Parameters)
# 15| 0: [Parameter] a0
# 15| 1: [Parameter] a1
# 15| 5: [BlockStmt] { ... }
# 15| 0: [ReturnStmt] return ...
# 15| 0: [MethodAccess] setP1(...)
# 15| -1: [VarAccess] a0
# 15| 0: [VarAccess] a1
# 15| -3: [TypeAccess] KMutableProperty1<C,Integer>
# 16| 9: [LocalVariableDeclStmt] var ...;
# 16| 1: [LocalVariableDeclExpr] y1
@@ -211,6 +253,21 @@ reflection.kt:
# 20| 1: [VarAccess] <dispatchReceiver>
# 20| 1: [FieldDeclaration] C <dispatchReceiver>;
# 20| -1: [TypeAccess] C
# 20| 1: [Method] get
# 20| 5: [BlockStmt] { ... }
# 20| 0: [ReturnStmt] return ...
# 20| 0: [MethodAccess] getP1(...)
# 20| -1: [VarAccess] this.<dispatchReceiver>
# 20| -1: [ThisAccess] this
# 20| 1: [Method] set
#-----| 4: (Parameters)
# 20| 0: [Parameter] a0
# 20| 5: [BlockStmt] { ... }
# 20| 0: [ReturnStmt] return ...
# 20| 0: [MethodAccess] setP1(...)
# 20| -1: [VarAccess] this.<dispatchReceiver>
# 20| -1: [ThisAccess] this
# 20| 0: [VarAccess] a0
# 20| -3: [TypeAccess] KMutableProperty0<Integer>
# 20| 0: [ClassInstanceExpr] new C(...)
# 20| -3: [TypeAccess] C