Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -570,12 +570,31 @@ class UtLambdaModel(
val capturedValues: MutableList<UtModel> = 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"

Expand All @@ -591,6 +610,18 @@ class UtLambdaModel(
}

override fun hashCode(): Int = id

companion object {
private const val fakeName = "<FAKE>"

/**
* 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)
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand All @@ -91,6 +107,9 @@ class UtModelConstructor(
return model
}
}
if (isProxyLambda(value)) {
return constructFakeLambda(value!!, classId)
}
return when (value) {
null -> UtNullModel(classId)
is Unit -> UtVoidModel
Expand Down