Skip to content

Commit dc9d990

Browse files
authored
Avoid presence of our internal types in generated code (#1244)
* Remove our types from type storages * Replace constructors with static methods for TypeStorage * Remove our classes from the hierarchy
1 parent 27a1af8 commit dc9d990

File tree

11 files changed

+143
-39
lines changed

11 files changed

+143
-39
lines changed

utbot-framework-api/src/main/kotlin/org/utbot/framework/UtSettings.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,18 @@ object UtSettings : AbstractSettings(
382382
* and test generation.
383383
*/
384384
var useSandbox by getBooleanProperty(true)
385+
386+
/**
387+
* If this options set in true, all soot classes will be removed from a Soot Scene,
388+
* therefore, you will be unable to test soot classes.
389+
*/
390+
var removeSootClassesFromHierarchy by getBooleanProperty(true)
391+
392+
/**
393+
* If this options set in true, all UtBot classes will be removed from a Soot Scene,
394+
* therefore, you will be unable to test UtBot classes.
395+
*/
396+
var removeUtBotClassesFromHierarchy by getBooleanProperty(true)
385397
}
386398

387399
/**

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -501,7 +501,7 @@ class AssociativeArrayWrapper : WrapperInterface {
501501
stores = (0 until sizeValue).associateWithTo(mutableMapOf()) { i ->
502502
resolver.resolveModel(
503503
ObjectValue(
504-
TypeStorage(OBJECT_TYPE),
504+
TypeStorage.constructTypeStorageWithSingleType(OBJECT_TYPE),
505505
UtAddrExpression(touchedArrayExpression.select(mkInt(i)))
506506
)
507507
)
@@ -527,7 +527,7 @@ class AssociativeArrayWrapper : WrapperInterface {
527527
val addr = model.getIdOrThrow()
528528
addr to resolver.resolveModel(
529529
ObjectValue(
530-
TypeStorage(OBJECT_TYPE),
530+
TypeStorage.constructTypeStorageWithSingleType(OBJECT_TYPE),
531531
UtAddrExpression(storageArrayExpression.select(mkInt(addr)))
532532
)
533533
)

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

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -83,22 +83,25 @@ inline fun <R> SymbolicFailure.fold(
8383
data class Parameter(private val localVariable: LocalVariable, private val type: Type, val value: SymbolicValue)
8484

8585
/**
86-
* Keeps most common type and possible types, to resolve types in uncertain situations, like virtual invokes.
86+
* Contains type information about some object: set of its [possibleConcreteTypes] and their [leastCommonType].
87+
* Note that in some situations [leastCommonType] will not present in [possibleConcreteTypes] set, and
88+
* it should not be used to encode this type information into a solver.
8789
*
8890
* Note: [leastCommonType] might be an interface or abstract type in opposite to the [possibleConcreteTypes]
8991
* that **usually** contains only concrete types (so-called appropriate). The only way to create [TypeStorage] with
90-
* inappropriate possibleType is to create it using constructor with the only type.
92+
* inappropriate possibleType is to create it using static methods [constructTypeStorageUnsafe] and
93+
* [constructTypeStorageWithSingleType].
94+
*
95+
* The right way to create an instance of TypeStorage is to use methods provided by [TypeResolver], e.g.,
96+
* [TypeResolver.constructTypeStorage].
9197
*
9298
* @see isAppropriate
99+
* @see TypeResolver.constructTypeStorage
93100
*/
94-
data class TypeStorage(val leastCommonType: Type, val possibleConcreteTypes: Set<Type>) {
101+
class TypeStorage private constructor(val leastCommonType: Type, val possibleConcreteTypes: Set<Type>) {
95102
private val hashCode = Objects.hash(leastCommonType, possibleConcreteTypes)
96103

97-
/**
98-
* Construct a type storage with some type. In this case [possibleConcreteTypes] might contains
99-
* abstract class or interface. Usually it means such typeStorage represents wrapper object type.
100-
*/
101-
constructor(concreteType: Type) : this(concreteType, setOf(concreteType))
104+
private constructor(concreteType: Type) : this(concreteType, setOf(concreteType))
102105

103106
fun isObjectTypeStorage(): Boolean = possibleConcreteTypes.size == objectTypeStorage.possibleConcreteTypes.size
104107

@@ -121,6 +124,29 @@ data class TypeStorage(val leastCommonType: Type, val possibleConcreteTypes: Set
121124
} else {
122125
"(leastCommonType=$leastCommonType, ${possibleConcreteTypes.size} possibleTypes=${possibleConcreteTypes.take(10)})"
123126
}
127+
128+
companion object {
129+
/**
130+
* Constructs a type storage with particular leastCommonType and set of possibleConcreteTypes.
131+
* This method doesn't give any guarantee on correctness of the constructed type storage and
132+
* should not be used directly except the situations where you want to create abnormal type storage,
133+
* for example, a one that contains interfaces in [possibleConcreteTypes].
134+
*
135+
* In regular cases you should use [TypeResolver.constructTypeStorage] method instead.
136+
*/
137+
fun constructTypeStorageUnsafe(
138+
leastCommonType: Type,
139+
possibleConcreteTypes: Set<Type>
140+
): TypeStorage = TypeStorage(leastCommonType, possibleConcreteTypes)
141+
142+
/**
143+
* Constructs a type storage with some type. In this case [possibleConcreteTypes] might contain
144+
* an abstract class or an interface. Usually it means such typeStorage represents wrapper object type.
145+
*/
146+
fun constructTypeStorageWithSingleType(
147+
leastCommonType: Type
148+
): TypeStorage = TypeStorage(leastCommonType)
149+
}
124150
}
125151

126152
sealed class InvokeResult

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,10 @@ data class Memory( // TODO: split purely symbolic memory and information about s
366366
class TypeRegistry {
367367
init {
368368
// initializes type storage for OBJECT_TYPE from current scene
369-
objectTypeStorage = TypeStorage(OBJECT_TYPE, Scene.v().classes.mapTo(mutableSetOf()) { it.type })
369+
objectTypeStorage = TypeStorage.constructTypeStorageUnsafe(
370+
OBJECT_TYPE,
371+
Scene.v().classes.mapTo(mutableSetOf()) { it.type }
372+
)
370373
}
371374

372375
private val typeIdBiMap = HashBiMap.create<Type, Int>()
@@ -612,9 +615,10 @@ class TypeRegistry {
612615
fun createClassRef(baseType: Type, numDimensions: Int = 0): MethodResult {
613616
val addr = classRefBiMap.getOrPut(baseType) { nextClassRefAddr() }
614617

615-
val objectValue = ObjectValue(TypeStorage(CLASS_REF_TYPE), addr)
618+
val classRefTypeStorage = TypeStorage.constructTypeStorageWithSingleType(CLASS_REF_TYPE)
619+
val objectValue = ObjectValue(objectTypeStorage, addr)
616620

617-
val typeConstraint = typeConstraint(addr, TypeStorage(CLASS_REF_TYPE)).all()
621+
val typeConstraint = typeConstraint(addr, classRefTypeStorage).all()
618622

619623
val typeId = mkInt(findTypeId(baseType))
620624
val symNumDimensions = mkInt(numDimensions)

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ class OptionalWrapper(private val utOptionalClass: UtOptionalClass) : BaseOverri
6565
): List<InvokeResult>? {
6666
when (method.signature) {
6767
AS_OPTIONAL_METHOD_SIGNATURE -> {
68-
return listOf(MethodResult(wrapper.copy(typeStorage = TypeStorage(method.returnType))))
68+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(method.returnType)
69+
val resultingWrapper = wrapper.copy(typeStorage = typeStorage)
70+
val methodResult = MethodResult(resultingWrapper)
71+
72+
return listOf(methodResult)
6973
}
7074
UT_OPTIONAL_EQ_GENERIC_TYPE_SIGNATURE -> {
7175
return listOf(

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ class Resolver(
427427
// if the value is Object, we have to construct array or an object depending on the number of dimensions
428428
// it is possible if we had an object and we casted it into array
429429
val constructedType = holder.constructTypeOrNull(value.addr, value.type) ?: return UtNullModel(value.type.id)
430-
val typeStorage = TypeStorage(constructedType)
430+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(constructedType)
431431

432432
return if (constructedType is ArrayType) {
433433
constructArrayModel(ArrayValue(typeStorage, value.addr))
@@ -1034,7 +1034,9 @@ class Resolver(
10341034
val constructedType = holder.constructTypeOrNull(addr, defaultType) ?: return UtNullModel(defaultType.id)
10351035

10361036
if (defaultType.isJavaLangObject() && constructedType is ArrayType) {
1037-
return constructArrayModel(ArrayValue(TypeStorage(constructedType), addr))
1037+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(constructedType)
1038+
val arrayValue = ArrayValue(typeStorage, addr)
1039+
return constructArrayModel(arrayValue)
10381040
} else {
10391041
val concreteType = typeResolver.findAnyConcreteInheritorIncludingOrDefault(
10401042
constructedType as RefType,

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import org.utbot.framework.plugin.api.UtAssembleModel
2323
import org.utbot.framework.plugin.api.UtExecutableCallModel
2424
import org.utbot.framework.plugin.api.UtModel
2525
import org.utbot.framework.plugin.api.UtPrimitiveModel
26-
import org.utbot.framework.plugin.api.UtStatementModel
2726
import org.utbot.framework.plugin.api.classId
2827
import org.utbot.framework.plugin.api.id
2928
import org.utbot.framework.plugin.api.util.charArrayClassId
@@ -60,7 +59,8 @@ class StringWrapper : BaseOverriddenWrapper(utStringClass.name) {
6059
): List<InvokeResult>? {
6160
return when (method.subSignature) {
6261
toStringMethodSignature -> {
63-
listOf(MethodResult(wrapper.copy(typeStorage = TypeStorage(method.returnType))))
62+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(method.returnType)
63+
listOf(MethodResult(wrapper.copy(typeStorage = typeStorage)))
6464
}
6565
matchesMethodSignature -> {
6666
symbolicMatchesMethodImpl(wrapper, parameters)
@@ -200,7 +200,11 @@ sealed class UtAbstractStringBuilderWrapper(className: String) : BaseOverriddenW
200200
parameters: List<SymbolicValue>
201201
): List<InvokeResult>? {
202202
if (method.subSignature == asStringBuilderMethodSignature) {
203-
return listOf(MethodResult(wrapper.copy(typeStorage = TypeStorage(method.returnType))))
203+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(method.returnType)
204+
val resultingWrapper = wrapper.copy(typeStorage = typeStorage)
205+
val methodResult = MethodResult(resultingWrapper)
206+
207+
return listOf(methodResult)
204208
}
205209

206210
return null

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ data class PrimitiveValue(
5151
val expr: UtExpression,
5252
override val concrete: Concrete? = null
5353
) : SymbolicValue() {
54-
constructor(type: Type, expr: UtExpression) : this(TypeStorage(type), expr)
54+
constructor(type: Type, expr: UtExpression) : this(TypeStorage.constructTypeStorageWithSingleType(type), expr)
5555

5656
override val type get() = typeStorage.leastCommonType
5757

@@ -179,7 +179,7 @@ fun SymbolicValue.toConcrete(): Any = when (this) {
179179

180180
// TODO: one more constructor?
181181
fun objectValue(type: RefType, addr: UtAddrExpression, implementation: WrapperInterface) =
182-
ObjectValue(TypeStorage(type), addr, Concrete(implementation))
182+
ObjectValue(TypeStorage.constructTypeStorageWithSingleType(type), addr, Concrete(implementation))
183183

184184
val voidValue
185185
get() = PrimitiveValue(VoidType.v(), nullObjectAddr)

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

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,7 @@ class Traverser(
899899
// Ignores the result of resolve().
900900
resolve(fieldRef)
901901
val baseObject = resolve(fieldRef.base) as ObjectValue
902-
val typeStorage = TypeStorage(fieldRef.field.declaringClass.type)
902+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(fieldRef.field.declaringClass.type)
903903
baseObject.copy(typeStorage = typeStorage)
904904
}
905905
is StaticFieldRef -> {
@@ -1251,7 +1251,12 @@ class Traverser(
12511251
// It is required because we do not want to have situations when some object might have
12521252
// only artificial classes as their possible, that would cause problems in the type constraints.
12531253
val typeStorage = if (leastCommonType in wrapperToClass.keys) {
1254-
typeStoragePossiblyWithOverriddenTypes.copy(possibleConcreteTypes = wrapperToClass.getValue(leastCommonType))
1254+
val possibleConcreteTypes = wrapperToClass.getValue(leastCommonType)
1255+
1256+
TypeStorage.constructTypeStorageUnsafe(
1257+
typeStoragePossiblyWithOverriddenTypes.leastCommonType,
1258+
possibleConcreteTypes
1259+
)
12551260
} else {
12561261
typeStoragePossiblyWithOverriddenTypes
12571262
}
@@ -1308,7 +1313,10 @@ class Traverser(
13081313
createObject(addr, refType, useConcreteType = true)
13091314
}
13101315
} else {
1311-
queuedSymbolicStateUpdates += typeRegistry.typeConstraint(addr, TypeStorage(refType)).all().asHardConstraint()
1316+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(refType)
1317+
val typeConstraint = typeRegistry.typeConstraint(addr, typeStorage).all().asHardConstraint()
1318+
1319+
queuedSymbolicStateUpdates += typeConstraint
13121320

13131321
objectValue(refType, addr, StringWrapper()).also {
13141322
initStringLiteral(it, constant.value)
@@ -1418,8 +1426,10 @@ class Traverser(
14181426
}
14191427

14201428
private fun initStringLiteral(stringWrapper: ObjectValue, value: String) {
1429+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(utStringClass.type)
1430+
14211431
queuedSymbolicStateUpdates += objectUpdate(
1422-
stringWrapper.copy(typeStorage = TypeStorage(utStringClass.type)),
1432+
stringWrapper.copy(typeStorage = typeStorage),
14231433
STRING_LENGTH,
14241434
mkInt(value.length)
14251435
)
@@ -1432,7 +1442,7 @@ class Traverser(
14321442
queuedSymbolicStateUpdates += arrayUpdateWithValue(it.addr, arrayType, defaultValue as UtArrayExpressionBase)
14331443
}
14341444
queuedSymbolicStateUpdates += objectUpdate(
1435-
stringWrapper.copy(typeStorage = TypeStorage(utStringClass.type)),
1445+
stringWrapper.copy(typeStorage = typeStorage),
14361446
STRING_VALUE,
14371447
arrayValue.addr
14381448
)
@@ -1720,7 +1730,8 @@ class Traverser(
17201730
val chunkId = typeRegistry.arrayChunkId(type)
17211731
touchMemoryChunk(MemoryChunkDescriptor(chunkId, type, elementType))
17221732

1723-
return ArrayValue(TypeStorage(type), addr).also {
1733+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(type)
1734+
return ArrayValue(typeStorage, addr).also {
17241735
queuedSymbolicStateUpdates += typeRegistry.typeConstraint(addr, it.typeStorage).all().asHardConstraint()
17251736
}
17261737
}
@@ -2949,7 +2960,9 @@ class Traverser(
29492960

29502961
val memoryUpdate = MemoryUpdate(touchedChunkDescriptors = persistentSetOf(descriptor))
29512962

2952-
val clone = ArrayValue(TypeStorage(array.type), addr)
2963+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(array.type)
2964+
val clone = ArrayValue(typeStorage, addr)
2965+
29532966
return MethodResult(clone, constraints.asHardConstraint(), memoryUpdates = memoryUpdate)
29542967
}
29552968

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

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy
112112
if (numDimensions == 0) baseType else baseType.makeArrayType(numDimensions)
113113
}
114114

115-
return TypeStorage(type, concretePossibleTypes).removeInappropriateTypes()
115+
return TypeStorage.constructTypeStorageUnsafe(type, concretePossibleTypes).removeInappropriateTypes()
116116
}
117117

118118
private fun isInappropriateOrArrayOfMocksOrLocals(numDimensions: Int, baseType: Type?): Boolean {
@@ -122,6 +122,12 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy
122122

123123
val baseSootClass = baseType.sootClass
124124

125+
// We don't want to have our wrapper's classes as a part of a regular TypeStorage instance
126+
// Note that we cannot have here 'isOverridden' since iterators of our wrappers are not wrappers
127+
if (wrapperToClass[baseType] != null) {
128+
return true
129+
}
130+
125131
if (numDimensions == 0 && baseSootClass.isInappropriate) {
126132
// interface, abstract class, or local, or mock could not be constructed
127133
return true
@@ -152,7 +158,7 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy
152158
*/
153159
fun constructTypeStorage(type: Type, useConcreteType: Boolean): TypeStorage {
154160
// create a typeStorage with concreteType even if the type belongs to an interface or an abstract class
155-
if (useConcreteType) return TypeStorage(type)
161+
if (useConcreteType) return TypeStorage.constructTypeStorageWithSingleType(type)
156162

157163
val baseType = type.baseType
158164

@@ -182,7 +188,7 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy
182188
else -> error("Unexpected type $type")
183189
}
184190

185-
return TypeStorage(type, possibleTypes).removeInappropriateTypes()
191+
return TypeStorage.constructTypeStorageUnsafe(type, possibleTypes).removeInappropriateTypes()
186192
}
187193

188194
/**
@@ -215,16 +221,20 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy
215221
return@filter true
216222
}.toSet()
217223

218-
return copy(possibleConcreteTypes = appropriateTypes)
224+
return TypeStorage.constructTypeStorageUnsafe(leastCommonType, appropriateTypes)
219225
}
220226

221227
/**
222228
* Constructs a nullObject with TypeStorage containing all the inheritors for the given type
223229
*/
224-
fun nullObject(type: Type) = when (type) {
225-
is RefType, is NullType, is VoidType -> ObjectValue(TypeStorage(type), nullObjectAddr)
226-
is ArrayType -> ArrayValue(TypeStorage(type), nullObjectAddr)
227-
else -> error("Unsupported nullType $type")
230+
fun nullObject(type: Type): ReferenceValue {
231+
val typeStorage = TypeStorage.constructTypeStorageWithSingleType(type)
232+
233+
return when (type) {
234+
is RefType, is NullType, is VoidType -> ObjectValue(typeStorage, nullObjectAddr)
235+
is ArrayType -> ArrayValue(typeStorage, nullObjectAddr)
236+
else -> error("Unsupported nullType $type")
237+
}
228238
}
229239

230240
fun downCast(arrayValue: ArrayValue, typeToCast: ArrayType): ArrayValue {

0 commit comments

Comments
 (0)