Skip to content

Commit 1d1864d

Browse files
committed
Make Spring-specific no NPE speculation to only trigger for mocks
1 parent eb8ece9 commit 1d1864d

File tree

4 files changed

+47
-9
lines changed

4 files changed

+47
-9
lines changed

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

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ import org.utbot.framework.UtSettings
116116
import org.utbot.framework.UtSettings.preferredCexOption
117117
import org.utbot.framework.UtSettings.substituteStaticsWithSymbolicVariable
118118
import org.utbot.framework.isFromTrustedLibrary
119-
import org.utbot.framework.context.ApplicationContext
120119
import org.utbot.framework.context.NonNullSpeculator
121120
import org.utbot.framework.context.TypeReplacer
122121
import org.utbot.framework.plugin.api.ClassId
@@ -2336,10 +2335,18 @@ class Traverser(
23362335
* Marks the [createdField] as speculatively not null if the [field] is considering
23372336
* as not producing [NullPointerException].
23382337
*
2339-
* See more detailed documentation in [ApplicationContext] mentioned methods.
2338+
* See more detailed documentation in [NonNullSpeculator] mentioned methods.
23402339
*/
2341-
private fun checkAndMarkLibraryFieldSpeculativelyNotNull(field: SootField, createdField: SymbolicValue) {
2342-
if (nonNullSpeculator.speculativelyCannotProduceNullPointerException(field, methodUnderTest.classId))
2340+
private fun checkAndMarkLibraryFieldSpeculativelyNotNull(
2341+
field: SootField,
2342+
createdField: SymbolicValue,
2343+
) {
2344+
if (nonNullSpeculator.speculativelyCannotProduceNullPointerException(
2345+
field = field,
2346+
isMocked = (createdField as? ObjectValue)?.asWrapperOrNull is UtMockWrapper,
2347+
classUnderTest = methodUnderTest.classId,
2348+
)
2349+
)
23432350
markAsSpeculativelyNotNull(createdField.addr)
23442351
}
23452352

utbot-framework/src/main/kotlin/org/utbot/framework/context/NonNullSpeculator.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ interface NonNullSpeculator {
88
* Checks whether accessing [field] (with a method invocation or field access) speculatively
99
* cannot produce [NullPointerException] (according to its finality or accessibility).
1010
*
11+
* @param [isMocked] true if engine decided it will use either `null` or mock for the [field] value
12+
*
1113
* @see docs/SpeculativeFieldNonNullability.md for more information.
1214
*/
1315
fun speculativelyCannotProduceNullPointerException(
1416
field: SootField,
17+
isMocked: Boolean,
1518
classUnderTest: ClassId,
1619
): Boolean
1720
}

utbot-framework/src/main/kotlin/org/utbot/framework/context/simple/SimpleNonNullSpeculator.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import soot.SootField
99
class SimpleNonNullSpeculator : NonNullSpeculator {
1010
override fun speculativelyCannotProduceNullPointerException(
1111
field: SootField,
12+
isMocked: Boolean,
1213
classUnderTest: ClassId,
1314
): Boolean =
1415
!UtSettings.maximizeCoverageUsingReflection &&
Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package org.utbot.framework.context.spring
22

3+
import mu.KotlinLogging
34
import org.utbot.framework.context.NonNullSpeculator
45
import org.utbot.framework.plugin.api.ClassId
5-
import org.utbot.framework.plugin.api.classId
6+
import org.utbot.framework.plugin.api.FieldId
67
import org.utbot.framework.plugin.api.util.allDeclaredFieldIds
78
import org.utbot.framework.plugin.api.util.fieldId
89
import soot.SootField
@@ -11,9 +12,35 @@ class SpringNonNullSpeculator(
1112
private val delegateNonNullSpeculator: NonNullSpeculator,
1213
private val springApplicationContext: SpringApplicationContext
1314
) : NonNullSpeculator {
14-
override fun speculativelyCannotProduceNullPointerException(field: SootField, classUnderTest: ClassId): Boolean =
15-
// TODO add ` || delegateNonNullSpeculator.speculativelyCannotProduceNullPointerException(field, classUnderTest)`
16-
// (TODO is added as a part of only equivalent transformations refactoring PR and should be completed in the follow up PR)
17-
field.fieldId in classUnderTest.allDeclaredFieldIds && field.type.classId !in springApplicationContext.allInjectedSuperTypes
15+
companion object {
16+
private val logger = KotlinLogging.logger {}
17+
private val loggedSpeculations = mutableSetOf<Speculation>()
18+
}
1819

20+
private data class Speculation(
21+
val field: FieldId,
22+
val isMocked: Boolean,
23+
val classUnderTest: ClassId,
24+
val speculativelyCannotProduceNPE: Boolean,
25+
)
26+
27+
override fun speculativelyCannotProduceNullPointerException(
28+
field: SootField,
29+
isMocked: Boolean,
30+
classUnderTest: ClassId
31+
): Boolean {
32+
if (delegateNonNullSpeculator.speculativelyCannotProduceNullPointerException(field, isMocked, classUnderTest))
33+
return true
34+
35+
if (field.fieldId !in classUnderTest.allDeclaredFieldIds)
36+
return false
37+
38+
val speculativelyCannotProduceNPE = isMocked
39+
40+
val speculation = Speculation(field.fieldId, isMocked, classUnderTest, speculativelyCannotProduceNPE)
41+
if (loggedSpeculations.add(speculation))
42+
logger.info { "New speculation: $speculation" }
43+
44+
return speculativelyCannotProduceNPE
45+
}
1946
}

0 commit comments

Comments
 (0)