From a393231550ad076b6eb03f8b61adc2824e4dcbb7 Mon Sep 17 00:00:00 2001 From: IlyaMuravjov Date: Fri, 1 Sep 2023 16:45:24 +0300 Subject: [PATCH] Do necessary down casts when generating method calls --- .../services/access/CgCallableAccessManager.kt | 10 ++++++++-- .../framework/codegen/tree/CgMethodConstructor.kt | 2 +- .../codegen/tree/CgVariableConstructor.kt | 2 +- .../framework/codegen/tree/ConstructorUtils.kt | 14 ++++++++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/access/CgCallableAccessManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/access/CgCallableAccessManager.kt index cb29b17f6f..4f332c1939 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/access/CgCallableAccessManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/access/CgCallableAccessManager.kt @@ -29,6 +29,7 @@ import org.utbot.framework.codegen.domain.models.CgVariable import org.utbot.framework.codegen.services.access.CgCallableAccessManagerImpl.FieldAccessorSuitability.* import org.utbot.framework.codegen.tree.CgComponents.getStatementConstructorBy import org.utbot.framework.codegen.tree.CgComponents.getVariableConstructorBy +import org.utbot.framework.codegen.tree.downcastIfNeeded import org.utbot.framework.codegen.tree.getAmbiguousOverloadsOf import org.utbot.framework.codegen.tree.importIfNeeded import org.utbot.framework.codegen.tree.isUtil @@ -114,7 +115,11 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA override operator fun CgIncompleteMethodCall.invoke(vararg args: Any?): CgMethodCall { val resolvedArgs = args.resolve() val methodCall = if (method.canBeCalledWith(caller, resolvedArgs)) { - CgMethodCall(caller, method, resolvedArgs.guardedForDirectCallOf(method)).takeCallerFromArgumentsIfNeeded() + CgMethodCall( + caller = caller?.let { downcastIfNeeded(method.classId, caller) }, + executableId = method, + arguments = resolvedArgs.guardedForDirectCallOf(method) + ).takeCallerFromArgumentsIfNeeded() } else { method.callWithReflection(caller, resolvedArgs) } @@ -200,7 +205,8 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA // this executable can be called on builtin type this.type is BuiltinClassId && this.type in builtinCallersWithoutReflection -> true - else -> false + // receiver can be downcasted before call + else -> executable.isAccessibleFrom(testClassPackageName) } // For some builtin types we need to clarify diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt index 8839623ff3..93aa88e93b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgMethodConstructor.kt @@ -1159,7 +1159,7 @@ open class CgMethodConstructor(val context: CgContext) : CgContextOwner by conte } else if (context.codegenLanguage == CodegenLanguage.JAVA && !jField.isStatic && canBeReadViaGetterFrom(context) ) { - CgMethodCall(variable, getter, emptyList()) + variable[getter]() } else { utilsClassId[getFieldValue](variable, this.declaringClass.name, this.name) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt index 9569f56152..2f5506f12a 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/CgVariableConstructor.kt @@ -215,7 +215,7 @@ open class CgVariableConstructor(val context: CgContext) : } else if (context.codegenLanguage == CodegenLanguage.JAVA && !field.isStatic && fieldId.canBeSetViaSetterFrom(context) ) { - +CgMethodCall(obj, fieldId.setter, listOf(valueForField)) + +obj[fieldId.setter](valueForField) } else { // composite models must not have info about static fields, hence only non-static fields are set here +utilsClassId[setField](obj, fieldId.declaringClass.name, fieldId.name, valueForField) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/ConstructorUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/ConstructorUtils.kt index cf56a49cf3..80d652c6da 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/ConstructorUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/ConstructorUtils.kt @@ -291,6 +291,20 @@ internal fun CgContextOwner.typeCast( return CgTypeCast(denotableTargetType, expression, isSafetyCast) } +/** + * Casts [expression] to [targetType] only if downcast is needed, + * e.g. this method will cast `Collection` to `Set`, but not vice-versa. + * + * @see typeCast + */ +internal fun CgContextOwner.downcastIfNeeded( + targetType: ClassId, + expression: CgExpression, + isSafetyCast: Boolean = false +): CgExpression = + if (expression.type isSubtypeOf targetType) expression + else typeCast(targetType, expression, isSafetyCast) + /** * Sets an element of arguments array in parameterized test, * if test framework represents arguments as array.