Skip to content

Commit 9a2a1fe

Browse files
Fix traversing concrete types in NoImplementors mode (#1991)
1 parent 290c095 commit 9a2a1fe

File tree

2 files changed

+36
-17
lines changed
  • utbot-framework/src/main/kotlin/org/utbot/engine
  • utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api

2 files changed

+36
-17
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1245,13 +1245,16 @@ class SpringApplicationContext(
12451245
* if there is the unique implementor in bean definitions.
12461246
*/
12471247
override fun replaceTypeIfNeeded(type: RefType): ClassId? =
1248-
if (type.sootClass.isInterface || type.sootClass.isAbstract) {
1248+
if (type.isAbstractType) {
12491249
springInjectedClasses.singleOrNull { it.isSubtypeOf(type.id) }
12501250
} else {
12511251
null
12521252
}
12531253
}
12541254

1255+
val RefType.isAbstractType
1256+
get() = this.sootClass.isAbstract || this.sootClass.isInterface
1257+
12551258
interface CodeGenerationSettingItem {
12561259
val id: String
12571260
val displayName: String

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

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,13 @@ import org.utbot.framework.plugin.api.TypeReplacementMode.KnownImplementor
126126
import org.utbot.framework.plugin.api.TypeReplacementMode.NoImplementors
127127
import org.utbot.framework.plugin.api.classId
128128
import org.utbot.framework.plugin.api.id
129+
import org.utbot.framework.plugin.api.isAbstractType
129130
import org.utbot.framework.plugin.api.util.executable
130131
import org.utbot.framework.plugin.api.util.findFieldByIdOrNull
131132
import org.utbot.framework.plugin.api.util.jField
132133
import org.utbot.framework.plugin.api.util.jClass
133134
import org.utbot.framework.plugin.api.util.id
135+
import org.utbot.framework.plugin.api.util.isAbstract
134136
import org.utbot.framework.plugin.api.util.isConstructor
135137
import org.utbot.framework.plugin.api.util.utContext
136138
import org.utbot.framework.util.executableId
@@ -1375,6 +1377,7 @@ class Traverser(
13751377
mockInfoGenerator: UtMockInfoGenerator? = null
13761378
): ObjectValue {
13771379
touchAddress(addr)
1380+
val nullEqualityConstraint = mkEq(addr, nullObjectAddr)
13781381

13791382
// Some types (e.g., interfaces) need to be mocked or replaced with the concrete implementor.
13801383
// Typically, this implementor is selected by SMT solver later.
@@ -1397,8 +1400,6 @@ class Traverser(
13971400
return ObjectValue(typeStorage, addr)
13981401
}
13991402

1400-
val nullEqualityConstraint = mkEq(addr, nullObjectAddr)
1401-
14021403
if (mockInfoGenerator != null) {
14031404
val mockInfo = mockInfoGenerator.generate(addr)
14041405

@@ -1499,21 +1500,16 @@ class Traverser(
14991500
"but there is no mock info generator provided to construct a mock value."
15001501
}
15011502

1502-
return createMockedObject(addr, type, mockInfoGenerator)
1503+
return createMockedObject(addr, type, mockInfoGenerator, nullEqualityConstraint)
15031504
}
15041505

15051506
val concreteImplementation = when (applicationContext.typeReplacementMode) {
1506-
AnyImplementor -> {
1507-
val isMockConstraint = mkEq(typeRegistry.isMock(addr), UtFalse)
1508-
1509-
queuedSymbolicStateUpdates += typeHardConstraint
1510-
queuedSymbolicStateUpdates += mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1507+
AnyImplementor -> findConcreteImplementation(addr, type, typeHardConstraint, nullEqualityConstraint)
15111508

1512-
// If we have this$0 with UtArrayList type, we have to create such instance.
1513-
// We should create an object with typeStorage of all possible real types and concrete implementation
1514-
// Otherwise we'd have either a wrong type in the resolver, or missing method like 'preconditionCheck'.
1515-
wrapperToClass[type]?.first()?.let { wrapper(it, addr) }?.concrete
1516-
}
1509+
// If our type is not abstract, both in `KnownImplementors` and `NoImplementors` mode,
1510+
// we should just still use concrete implementation that represents itself
1511+
//
1512+
// Otherwise:
15171513
// In case of `KnownImplementor` mode we should have already tried to replace type using `replaceTypeIfNeeded`.
15181514
// However, this replacement attempt might be unsuccessful even if some possible concrete types are present.
15191515
// For example, we may have two concrete implementors present in Spring bean definitions, so we do not know
@@ -1523,8 +1519,12 @@ class Traverser(
15231519
// Mocking can be impossible here as there are no guaranties that `mockInfoGenerator` is instantiated.
15241520
KnownImplementor,
15251521
NoImplementors -> {
1522+
if (!type.isAbstractType) {
1523+
findConcreteImplementation(addr, type, typeHardConstraint, nullEqualityConstraint)
1524+
}
1525+
15261526
mockInfoGenerator?.let {
1527-
return createMockedObject(addr, type, it)
1527+
return createMockedObject(addr, type, it, nullEqualityConstraint)
15281528
}
15291529

15301530
queuedSymbolicStateUpdates += mkFalse().asHardConstraint()
@@ -1535,13 +1535,29 @@ class Traverser(
15351535
return ObjectValue(typeStorage, addr, concreteImplementation)
15361536
}
15371537

1538+
private fun findConcreteImplementation(
1539+
addr: UtAddrExpression,
1540+
type: RefType,
1541+
typeHardConstraint: HardConstraint,
1542+
nullEqualityConstraint: UtBoolExpression,
1543+
): Concrete? {
1544+
val isMockConstraint = mkEq(typeRegistry.isMock(addr), UtFalse)
1545+
1546+
queuedSymbolicStateUpdates += typeHardConstraint
1547+
queuedSymbolicStateUpdates += mkOr(isMockConstraint, nullEqualityConstraint).asHardConstraint()
1548+
1549+
// If we have this$0 with UtArrayList type, we have to create such instance.
1550+
// We should create an object with typeStorage of all possible real types and concrete implementation
1551+
// Otherwise we'd have either a wrong type in the resolver, or missing method like 'preconditionCheck'.
1552+
return wrapperToClass[type]?.first()?.let { wrapper(it, addr) }?.concrete
1553+
}
1554+
15381555
private fun createMockedObject(
15391556
addr: UtAddrExpression,
15401557
type: RefType,
15411558
mockInfoGenerator: UtMockInfoGenerator,
1559+
nullEqualityConstraint: UtBoolExpression,
15421560
): ObjectValue {
1543-
val nullEqualityConstraint = mkEq(addr, nullObjectAddr)
1544-
15451561
val mockInfo = mockInfoGenerator.generate(addr)
15461562
val mockedObjectInfo = mocker.forceMock(type, mockInfoGenerator.generate(addr))
15471563

0 commit comments

Comments
 (0)