@@ -118,7 +118,9 @@ import org.utbot.framework.plugin.api.FieldId
118118import org.utbot.framework.plugin.api.MethodId
119119import org.utbot.framework.plugin.api.classId
120120import org.utbot.framework.plugin.api.id
121+ import org.utbot.framework.plugin.api.util.allDeclaredFieldIds
121122import org.utbot.framework.plugin.api.util.executable
123+ import org.utbot.framework.plugin.api.util.fieldId
122124import org.utbot.framework.plugin.api.util.jField
123125import org.utbot.framework.plugin.api.util.jClass
124126import org.utbot.framework.plugin.api.util.id
@@ -256,8 +258,11 @@ class Traverser(
256258
257259 /* *
258260 * Contains information about the generic types used in the parameters of the method under test.
261+ *
262+ * Mutable set here is required since this object might be passed into several methods
263+ * and get several piece of information about their parameterized types
259264 */
260- private val parameterAddrToGenericType = mutableMapOf<UtAddrExpression , ParameterizedType >()
265+ private val instanceAddrToGenericType = mutableMapOf<UtAddrExpression , MutableSet < ParameterizedType > >()
261266
262267 private val preferredCexInstanceCache = mutableMapOf<ObjectValue , MutableSet <SootField >>()
263268
@@ -1036,7 +1041,8 @@ class Traverser(
10361041
10371042 if (createdValue is ReferenceValue ) {
10381043 // Update generic type info for method under test' parameters
1039- updateGenericTypeInfo(identityRef, createdValue)
1044+ val index = (identityRef as ? ParameterRef )?.index?.plus(1 ) ? : 0
1045+ updateGenericTypeInfoFromMethod(methodUnderTest, createdValue, index)
10401046
10411047 if (isNonNullable) {
10421048 queuedSymbolicStateUpdates + = mkNot(
@@ -1087,81 +1093,94 @@ class Traverser(
10871093 return UtMockInfoGenerator { mockAddr -> UtObjectMockInfo (type.id, mockAddr) }
10881094 }
10891095
1096+ private fun updateGenericTypeInfoFromMethod (method : ExecutableId , value : ReferenceValue , parameterIndex : Int ) {
1097+ val type = extractParameterizedType(method, parameterIndex) as ? ParameterizedType ? : return
1098+
1099+ updateGenericTypeInfo(type, value)
1100+ }
1101+
10901102 /* *
10911103 * Stores information about the generic types used in the parameters of the method under test.
10921104 */
1093- private fun updateGenericTypeInfo (identityRef : IdentityRef , value : ReferenceValue ) {
1105+ private fun updateGenericTypeInfo (type : ParameterizedType , value : ReferenceValue ) {
1106+ val typeStorages = type.actualTypeArguments.map { actualTypeArgument ->
1107+ when (actualTypeArgument) {
1108+ is WildcardType -> {
1109+ val upperBounds = actualTypeArgument.upperBounds
1110+ val lowerBounds = actualTypeArgument.lowerBounds
1111+ val allTypes = upperBounds + lowerBounds
1112+
1113+ if (allTypes.any { it is GenericArrayType }) {
1114+ val errorTypes = allTypes.filterIsInstance<GenericArrayType >()
1115+ TODO (" we do not support GenericArrayTypeImpl yet, and $errorTypes found. SAT-1446" )
1116+ }
1117+
1118+ val upperBoundsTypes = typeResolver.intersectInheritors(upperBounds)
1119+ val lowerBoundsTypes = typeResolver.intersectAncestors(lowerBounds)
1120+
1121+ typeResolver.constructTypeStorage(OBJECT_TYPE , upperBoundsTypes.intersect(lowerBoundsTypes))
1122+ }
1123+ is TypeVariable <* > -> { // it is a type variable for the whole class, not the function type variable
1124+ val upperBounds = actualTypeArgument.bounds
1125+
1126+ if (upperBounds.any { it is GenericArrayType }) {
1127+ val errorTypes = upperBounds.filterIsInstance<GenericArrayType >()
1128+ TODO (" we do not support GenericArrayType yet, and $errorTypes found. SAT-1446" )
1129+ }
1130+
1131+ val upperBoundsTypes = typeResolver.intersectInheritors(upperBounds)
1132+
1133+ typeResolver.constructTypeStorage(OBJECT_TYPE , upperBoundsTypes)
1134+ }
1135+ is GenericArrayType -> {
1136+ // TODO bug with T[][], because there is no such time T JIRA:1446
1137+ typeResolver.constructTypeStorage(OBJECT_TYPE , useConcreteType = false )
1138+ }
1139+ is ParameterizedType , is Class <* > -> {
1140+ val sootType = Scene .v().getType(actualTypeArgument.rawType.typeName)
1141+
1142+ typeResolver.constructTypeStorage(sootType, useConcreteType = false )
1143+ }
1144+ else -> error(" Unsupported argument type ${actualTypeArgument::class } " )
1145+ }
1146+ }
1147+
1148+ queuedSymbolicStateUpdates + = typeRegistry
1149+ .genericTypeParameterConstraint(value.addr, typeStorages)
1150+ .asHardConstraint()
1151+
1152+ instanceAddrToGenericType.getOrPut(value.addr) { mutableSetOf () }.add(type)
1153+
1154+ typeRegistry.saveObjectParameterTypeStorages(value.addr, typeStorages)
1155+ }
1156+
1157+ private fun extractParameterizedType (
1158+ method : ExecutableId ,
1159+ index : Int
1160+ ): java.lang.reflect.Type ? {
10941161 // If we don't have access to methodUnderTest's jClass, the engine should not fail
10951162 // We just won't update generic information for it
1096- val callable = runCatching { methodUnderTest .executable }.getOrNull() ? : return
1163+ val callable = runCatching { method .executable }.getOrNull() ? : return null
10971164
1098- val type = if (identityRef is ThisRef ) {
1165+ val type = if (index == 0 ) {
10991166 // TODO: for ThisRef both methods don't return parameterized type
1100- if (methodUnderTest .isConstructor) {
1167+ if (method .isConstructor) {
11011168 callable.annotatedReturnType?.type
11021169 } else {
11031170 callable.declaringClass // same as it was, but it isn't parametrized type
1104- ? : error(" No instanceParameter for ${ callable} found" )
1171+ ? : error(" No instanceParameter for $callable found" )
11051172 }
11061173 } else {
11071174 // Sometimes out of bound exception occurred here, e.g., com.alibaba.fescar.core.model.GlobalStatus.<init>
11081175 workaround(HACK ) {
1109- val index = (identityRef as ParameterRef ).index
11101176 val valueParameters = callable.genericParameterTypes
11111177
1112- if (index > valueParameters.lastIndex) return
1113- valueParameters[index]
1178+ if (index - 1 > valueParameters.lastIndex) return null
1179+ valueParameters[index - 1 ]
11141180 }
11151181 }
11161182
1117- if (type is ParameterizedType ) {
1118- val typeStorages = type.actualTypeArguments.map { actualTypeArgument ->
1119- when (actualTypeArgument) {
1120- is WildcardType -> {
1121- val upperBounds = actualTypeArgument.upperBounds
1122- val lowerBounds = actualTypeArgument.lowerBounds
1123- val allTypes = upperBounds + lowerBounds
1124-
1125- if (allTypes.any { it is GenericArrayType }) {
1126- val errorTypes = allTypes.filterIsInstance<GenericArrayType >()
1127- TODO (" we do not support GenericArrayTypeImpl yet, and $errorTypes found. SAT-1446" )
1128- }
1129-
1130- val upperBoundsTypes = typeResolver.intersectInheritors(upperBounds)
1131- val lowerBoundsTypes = typeResolver.intersectAncestors(lowerBounds)
1132-
1133- typeResolver.constructTypeStorage(OBJECT_TYPE , upperBoundsTypes.intersect(lowerBoundsTypes))
1134- }
1135- is TypeVariable <* > -> { // it is a type variable for the whole class, not the function type variable
1136- val upperBounds = actualTypeArgument.bounds
1137-
1138- if (upperBounds.any { it is GenericArrayType }) {
1139- val errorTypes = upperBounds.filterIsInstance<GenericArrayType >()
1140- TODO (" we do not support GenericArrayType yet, and $errorTypes found. SAT-1446" )
1141- }
1142-
1143- val upperBoundsTypes = typeResolver.intersectInheritors(upperBounds)
1144-
1145- typeResolver.constructTypeStorage(OBJECT_TYPE , upperBoundsTypes)
1146- }
1147- is GenericArrayType -> {
1148- // TODO bug with T[][], because there is no such time T JIRA:1446
1149- typeResolver.constructTypeStorage(OBJECT_TYPE , useConcreteType = false )
1150- }
1151- is ParameterizedType , is Class <* > -> {
1152- val sootType = Scene .v().getType(actualTypeArgument.rawType.typeName)
1153-
1154- typeResolver.constructTypeStorage(sootType, useConcreteType = false )
1155- }
1156- else -> error(" Unsupported argument type ${actualTypeArgument::class } " )
1157- }
1158- }
1159-
1160- queuedSymbolicStateUpdates + = typeRegistry.genericTypeParameterConstraint(value.addr, typeStorages).asHardConstraint()
1161- parameterAddrToGenericType + = value.addr to type
1162-
1163- typeRegistry.saveObjectParameterTypeStorages(value.addr, typeStorages)
1164- }
1183+ return type
11651184 }
11661185
11671186 private fun TraversalContext.traverseIfStmt (current : JIfStmt ) {
@@ -2084,9 +2103,33 @@ class Traverser(
20842103 checkAndMarkLibraryFieldSpeculativelyNotNull(field, createdField)
20852104 }
20862105
2106+ updateGenericInfoForField(createdField, field)
2107+
20872108 return createdField
20882109 }
20892110
2111+ /* *
2112+ * Updates generic info for provided [field] and [createdField] using
2113+ * type information. If [createdField] is not a reference value or
2114+ * if field's type is not a parameterized one, nothing will happen.
2115+ */
2116+ private fun updateGenericInfoForField (createdField : SymbolicValue , field : SootField ) {
2117+ runCatching {
2118+ if (createdField !is ReferenceValue ) return
2119+
2120+ // We must have `runCatching` here since might be a situation when we do not have
2121+ // such declaring class in a classpath, that might (but should not) lead to an exception
2122+ val jClass = field.declaringClass.id.jClass
2123+ val requiredField = generateSequence(jClass) { it.superclass }
2124+ .flatMap { it.declaredFields.asSequence() }
2125+ .singleOrNull { it.name == field.name && it.declaringClass.name == field.declaringClass.name }
2126+
2127+ val genericInfo = requiredField?.genericType as ? ParameterizedType ? : return
2128+
2129+ updateGenericTypeInfo(genericInfo, createdField)
2130+ }
2131+ }
2132+
20902133 /* *
20912134 * Marks the [createdField] as speculatively not null if the [field] is considering as
20922135 * not producing [NullPointerException].
@@ -2519,7 +2562,11 @@ class Traverser(
25192562 // While using simplifications with RewritingVisitor, assertions can maintain types
25202563 // for objects (especially objects with type equals to type parameter of generic)
25212564 // better than engine.
2522- val types = instanceOfConstraint?.typeStorage?.possibleConcreteTypes ? : instance.possibleConcreteTypes
2565+ val types = instanceOfConstraint
2566+ ?.typeStorage
2567+ ?.possibleConcreteTypes
2568+ ?.takeIf { it.size < instance.possibleConcreteTypes.size }
2569+ ? : instance.possibleConcreteTypes
25232570
25242571 val allPossibleConcreteTypes = typeResolver
25252572 .constructTypeStorage(instance.type, useConcreteType = false )
@@ -2650,6 +2697,29 @@ class Traverser(
26502697 * Returns results of native calls cause other calls push changes directly to path selector.
26512698 */
26522699 private fun TraversalContext.commonInvokePart (invocation : Invocation ): List <MethodResult > {
2700+ val method = invocation.method.executableId
2701+
2702+ // This code is supposed to support generic information from signatures for nested methods.
2703+ // If we have some method 'foo` and a method `bar(List<Integer>), and inside `foo`
2704+ // there is an invocation `bar(object)`, this object must have information about
2705+ // its `Integer` generic type.
2706+
2707+ // Note that we must have `runCatching` here since might be a situation when we do not have
2708+ // such declaring class in a classpath, that might (but should not) lead to an exception
2709+ invocation.parameters.forEachIndexed { index, param ->
2710+ if (param !is ReferenceValue ) return @forEachIndexed
2711+
2712+ runCatching {
2713+ updateGenericTypeInfoFromMethod(method, param, parameterIndex = index + 1 )
2714+ }
2715+ }
2716+
2717+ if (invocation.instance != null ) {
2718+ runCatching {
2719+ updateGenericTypeInfoFromMethod(method, invocation.instance, parameterIndex = 0 )
2720+ }
2721+ }
2722+
26532723 /* *
26542724 * First, check if there is override for the invocation itself, not for the targets.
26552725 *
@@ -3469,16 +3539,13 @@ class Traverser(
34693539 if (baseTypeAfterCast is RefType ) {
34703540 // Find parameterized type for the object if it is a parameter of the method under test and it has generic type
34713541 val newAddr = addr.accept(solver.simplificator) as UtAddrExpression
3472- val parameterizedType = when (newAddr.internal) {
3473- is UtArraySelectExpression -> parameterAddrToGenericType [findTheMostNestedAddr(newAddr.internal)]
3474- is UtBvConst -> parameterAddrToGenericType [newAddr]
3542+ val parameterizedTypes = when (newAddr.internal) {
3543+ is UtArraySelectExpression -> instanceAddrToGenericType [findTheMostNestedAddr(newAddr.internal)]
3544+ is UtBvConst -> instanceAddrToGenericType [newAddr]
34753545 else -> null
34763546 }
34773547
3478- if (parameterizedType != null ) {
3479- // Find all generics used in the type of the parameter and it's superclasses
3480- // If we're trying to cast something related to the parameter and typeAfterCast is equal to one of the generic
3481- // types used in it, don't throw ClassCastException
3548+ parameterizedTypes?.forEach { parameterizedType ->
34823549 val genericTypes = generateSequence(parameterizedType) { it.ownerType as ? ParameterizedType }
34833550 .flatMapTo(mutableSetOf ()) { it.actualTypeArguments.map { arg -> arg.typeName } }
34843551
0 commit comments