diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index c6d03794be..5d73d3b825 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -570,12 +570,31 @@ class UtLambdaModel( val capturedValues: MutableList = mutableListOf(), ) : UtReferenceModel(id, samType) { + val isFake: Boolean = lambdaName == fakeName + val lambdaMethodId: MethodId - get() = declaringClass.jClass - .declaredMethods - .singleOrNull { it.name == lambdaName } - ?.executableId // synthetic lambda methods should not have overloads, so we always expect there to be only one method with the given name - ?: error("More than one method with name $lambdaName found in class: ${declaringClass.canonicalName}") + get() { + if (isFake) { + val targetMethod = samType.jClass.declaredMethods.single() + return object : MethodId( + declaringClass, + fakeName, + targetMethod.returnType.id, + targetMethod.parameterTypes.map { it.id } + ) { + override val modifiers: Int = ModifierFactory.invoke { + public = true + static = true + final = true + } + } + } + return declaringClass.jClass + .declaredMethods + .singleOrNull { it.name == lambdaName } + ?.executableId // synthetic lambda methods should not have overloads, so we always expect there to be only one method with the given name + ?: error("More than one method with name $lambdaName found in class: ${declaringClass.canonicalName}") + } override fun toString(): String = "Anonymous function $lambdaName implementing functional interface $declaringClass" @@ -591,6 +610,18 @@ class UtLambdaModel( } override fun hashCode(): Int = id + + companion object { + private const val fakeName = "" + + /** + * Create a non-existent lambda with fake method. + * + * That's temporary solution for building lambdas from concrete values. + */ + fun createFake(id: Int, samType: ClassId, declaringClass: ClassId) = + UtLambdaModel(id, samType, declaringClass, fakeName) + } } /** diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtModelConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtModelConstructor.kt index 8fade3f329..38c61d7590 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtModelConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtModelConstructor.kt @@ -35,6 +35,7 @@ import org.utbot.framework.util.valueToClassId import java.lang.reflect.Modifier import java.util.IdentityHashMap import java.util.stream.BaseStream +import org.utbot.framework.plugin.api.util.utContext /** * Represents common interface for model constructors. @@ -79,6 +80,21 @@ class UtModelConstructor( return objectToModelCache[value]?.let { (it as? UtReferenceModel)?.id } ?: computeUnusedIdAndUpdate() } + private val proxyLambdaSubstring = "$\$Lambda$" + + private fun isProxyLambda(value: Any?): Boolean { + if (value == null) { + return false + } + return proxyLambdaSubstring in value::class.java.name + } + + private fun constructFakeLambda(value: Any, classId: ClassId): UtLambdaModel { + val baseClassName = value::class.java.name.substringBefore(proxyLambdaSubstring) + val baseClass = utContext.classLoader.loadClass(baseClassName).id + return UtLambdaModel.createFake(handleId(value), classId, baseClass) + } + /** * Constructs a UtModel from a concrete [value] with a specific [classId]. The result can be a [UtAssembleModel] * as well. @@ -91,6 +107,9 @@ class UtModelConstructor( return model } } + if (isProxyLambda(value)) { + return constructFakeLambda(value!!, classId) + } return when (value) { null -> UtNullModel(classId) is Unit -> UtVoidModel