Skip to content

Commit 96336a9

Browse files
committed
Support Spring guided type replacements in symbolic engine
1 parent a720808 commit 96336a9

File tree

3 files changed

+43
-5
lines changed

3 files changed

+43
-5
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ import java.io.File
5555
import kotlin.contracts.ExperimentalContracts
5656
import kotlin.contracts.contract
5757
import org.utbot.common.isAbstract
58+
import org.utbot.common.isStatic
59+
import org.utbot.framework.plugin.api.util.isSubtypeOf
5860
import org.utbot.framework.plugin.api.util.utContext
5961

6062
const val SYMBOLIC_NULL_ADDR: Int = 0
@@ -1151,12 +1153,21 @@ class WildcardTypeParameter : TypeParameters(emptyList())
11511153
/**
11521154
* Additional data describing user project.
11531155
*/
1154-
interface ApplicationContext
1156+
interface ApplicationContext {
1157+
1158+
/**
1159+
* Finds a type to replace the original during symbolic
1160+
* analysis if it is guided with some additional information.
1161+
*/
1162+
fun replaceTypeIfNeeded(type: RefType): ClassId?
1163+
}
11551164

11561165
/**
11571166
* A context to use when no additional data is required.
11581167
*/
1159-
object EmptyApplicationContext: ApplicationContext
1168+
object EmptyApplicationContext: ApplicationContext {
1169+
override fun replaceTypeIfNeeded(type: RefType): ClassId? = null
1170+
}
11601171

11611172
/**
11621173
* Data we get from Spring application context
@@ -1167,9 +1178,24 @@ object EmptyApplicationContext: ApplicationContext
11671178
data class SpringApplicationContext(
11681179
val beanQualifiedNames: List<String> = emptyList(),
11691180
): ApplicationContext {
1170-
private val springInjectedClasses: List<ClassId> by lazy {
1171-
beanQualifiedNames.map { fqn -> utContext.classLoader.loadClass(fqn).id }
1181+
1182+
val springInjectedClasses: List<ClassId> by lazy {
1183+
beanQualifiedNames
1184+
.map { fqn -> utContext.classLoader.loadClass(fqn) }
1185+
.filterNot { it.isAbstract || it.isInterface || it.isLocalClass || it.isMemberClass && !it.isStatic }
1186+
.map { it.id }
11721187
}
1188+
1189+
/**
1190+
* Replaces an interface type with its implementor type
1191+
* if there is the unique implementor in bean definitions.
1192+
*/
1193+
override fun replaceTypeIfNeeded(type: RefType): ClassId? =
1194+
if (type.sootClass.isInterface) {
1195+
springInjectedClasses.singleOrNull { it.isSubtypeOf(type.id) }
1196+
} else {
1197+
null
1198+
}
11731199
}
11741200

11751201
interface CodeGenerationSettingItem {

utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1376,6 +1376,18 @@ class Traverser(
13761376
): ObjectValue {
13771377
touchAddress(addr)
13781378

1379+
//TODO: remove !! after PR-1889 merge, context cannot be null any more
1380+
val concreteClassId = applicationContext!!.replaceTypeIfNeeded(type)
1381+
concreteClassId?.let {
1382+
val sootType = typeResolver.classOrDefault(it.canonicalName)
1383+
val typeStorage = typeResolver.constructTypeStorage(sootType, useConcreteType = false)
1384+
1385+
val typeHardConstraint = typeRegistry.typeConstraint(addr, typeStorage).all().asHardConstraint()
1386+
queuedSymbolicStateUpdates += typeHardConstraint
1387+
1388+
return ObjectValue(typeStorage, addr)
1389+
}
1390+
13791391
val nullEqualityConstraint = mkEq(addr, nullObjectAddr)
13801392

13811393
if (mockInfoGenerator != null) {

utbot-framework/src/main/kotlin/org/utbot/engine/types/TypeResolver.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy
9595
.toSet()
9696
}
9797

98-
private fun classOrDefault(typeName: String): RefType =
98+
fun classOrDefault(typeName: String): RefType =
9999
runCatching { Scene.v().getRefType(typeName) }.getOrDefault(OBJECT_TYPE)
100100

101101
fun findFields(type: RefType) = typeRegistry.findFields(type) {

0 commit comments

Comments
 (0)