Skip to content

Commit ebf9bd0

Browse files
committed
Create speculativeNotNull implementation for Spring
1 parent 5ab14c8 commit ebf9bd0

File tree

13 files changed

+63
-24
lines changed

13 files changed

+63
-24
lines changed

utbot-framework/src/main/kotlin/org/utbot/engine/util/trusted/TrustedPackages.kt renamed to utbot-framework-api/src/main/kotlin/org/utbot/framework/TrustedPackages.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
package org.utbot.engine.util.trusted
1+
package org.utbot.framework
22

3-
import org.utbot.framework.TrustedLibraries
43
import soot.SootClass
54

65
/**

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,14 @@ import kotlin.contracts.ExperimentalContracts
5656
import kotlin.contracts.contract
5757
import org.utbot.common.isAbstract
5858
import org.utbot.common.isStatic
59+
import org.utbot.framework.isFromTrustedLibrary
5960
import org.utbot.framework.plugin.api.TypeReplacementMode.*
61+
import org.utbot.framework.plugin.api.util.allDeclaredFieldIds
62+
import org.utbot.framework.plugin.api.util.fieldId
6063
import org.utbot.framework.plugin.api.util.isSubtypeOf
6164
import org.utbot.framework.plugin.api.util.utContext
6265
import org.utbot.framework.process.OpenModulesContainer
66+
import soot.SootField
6367

6468
const val SYMBOLIC_NULL_ADDR: Int = 0
6569

@@ -1196,6 +1200,7 @@ enum class TypeReplacementMode {
11961200
* @param mockFrameworkInstalled shows if we have installed framework dependencies
11971201
* @param staticsMockingIsConfigured shows if we have installed static mocking tools
11981202
*/
1203+
@Suppress("KDocUnresolvedReference")
11991204
open class ApplicationContext(
12001205
val mockFrameworkInstalled: Boolean = true,
12011206
staticsMockingIsConfigured: Boolean = true,
@@ -1229,6 +1234,26 @@ open class ApplicationContext(
12291234
* if it is guided with some additional information.
12301235
*/
12311236
open fun replaceTypeIfNeeded(type: RefType): ClassId? = null
1237+
1238+
/**
1239+
* Sets the restrictions on speculative not null
1240+
* constraints in current application context.
1241+
*
1242+
* @see docs/SpeculativeFieldNonNullability.md for more information.
1243+
*/
1244+
open fun avoidSpeculativeNotNullChecks(field: SootField): Boolean =
1245+
UtSettings.maximizeCoverageUsingReflection || !field.declaringClass.isFromTrustedLibrary()
1246+
1247+
/**
1248+
* Checks whether accessing [field] (with a method invocation or field access) speculatively
1249+
* cannot produce [NullPointerException] (according to its finality or accessibility).
1250+
*
1251+
* @see docs/SpeculativeFieldNonNullability.md for more information.
1252+
*/
1253+
open fun speculativelyCannotProduceNullPointerException(
1254+
field: SootField,
1255+
classUnderTest: ClassId,
1256+
): Boolean = field.isFinal || !field.isPublic
12321257
}
12331258

12341259
/**
@@ -1265,6 +1290,21 @@ class SpringApplicationContext(
12651290
} else {
12661291
null
12671292
}
1293+
1294+
override fun avoidSpeculativeNotNullChecks(field: SootField): Boolean = false
1295+
1296+
/**
1297+
* In Spring applications we can mark as speculatively not null
1298+
* fields if they are mocked and injecting into class under test so on.
1299+
*
1300+
* Fields are not mocked if their actual type is obtained from [springInjectedClasses].
1301+
*
1302+
*/
1303+
override fun speculativelyCannotProduceNullPointerException(
1304+
field: SootField,
1305+
classUnderTest: ClassId,
1306+
): Boolean =
1307+
field.fieldId in classUnderTest.allDeclaredFieldIds && field.declaringClass.id !in springInjectedClasses
12681308
}
12691309

12701310
val RefType.isAbstractType

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import org.utbot.framework.plugin.api.MethodId
1111
import org.utbot.framework.plugin.api.UtModel
1212
import org.utbot.framework.plugin.api.UtNullModel
1313
import org.utbot.framework.plugin.api.UtPrimitiveModel
14+
import org.utbot.framework.plugin.api.id
15+
import soot.SootField
1416
import java.lang.reflect.Constructor
1517
import java.lang.reflect.Executable
1618
import java.lang.reflect.Field
@@ -451,6 +453,9 @@ val ClassId.allDeclaredFieldIds: Sequence<FieldId>
451453
.flatMap { it.declaredFields.asSequence() }
452454
.map { it.fieldId }
453455

456+
val SootField.fieldId: FieldId
457+
get() = FieldId(declaringClass.id, name)
458+
454459
// FieldId utils
455460
val FieldId.safeJField: Field?
456461
get() = declaringClass.jClass.declaredFields.firstOrNull { it.name == name }

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import org.utbot.framework.plugin.api.UtModel
2828
import org.utbot.framework.plugin.api.UtNullModel
2929
import org.utbot.framework.plugin.api.UtPrimitiveModel
3030
import org.utbot.framework.plugin.api.getIdOrThrow
31+
import org.utbot.framework.plugin.api.util.fieldId
3132
import org.utbot.framework.plugin.api.util.id
3233
import org.utbot.framework.plugin.api.util.objectArrayClassId
3334
import org.utbot.framework.plugin.api.util.objectClassId

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import org.utbot.framework.plugin.api.UtAssembleModel
1111
import org.utbot.framework.plugin.api.UtExecutableCallModel
1212
import org.utbot.framework.plugin.api.UtModel
1313
import org.utbot.framework.plugin.api.UtReferenceModel
14+
import org.utbot.framework.plugin.api.util.fieldId
1415
import org.utbot.framework.plugin.api.util.id
1516
import org.utbot.framework.plugin.api.util.methodId
1617
import soot.SootClass

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import org.utbot.framework.util.graph
3131
import org.utbot.framework.plugin.api.id
3232
import org.utbot.framework.plugin.api.util.booleanClassId
3333
import org.utbot.framework.plugin.api.util.constructorId
34+
import org.utbot.framework.plugin.api.util.fieldId
3435
import org.utbot.framework.plugin.api.util.id
3536
import org.utbot.framework.plugin.api.util.methodId
3637
import org.utbot.framework.plugin.api.util.objectClassId

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,6 @@ val JimpleLocal.variable: LocalVariable
285285
val Type.defaultSymValue: UtExpression
286286
get() = toSort().defaultValue
287287

288-
val SootField.fieldId: FieldId
289-
get() = FieldId(declaringClass.id, name)
290-
291288
val SootField.isEnumConstant: Boolean
292289
get() = name in declaringClass.id.enumConstants.orEmpty().map { enum -> enum.name }
293290

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import org.utbot.engine.types.STRING_TYPE
4141
import org.utbot.engine.types.SeqType
4242
import org.utbot.engine.types.TypeResolver
4343
import org.utbot.framework.plugin.api.id
44+
import org.utbot.framework.plugin.api.util.fieldId
4445
import org.utbot.framework.plugin.api.util.isEnum
4546
import soot.ArrayType
4647
import soot.CharType

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ import org.utbot.framework.UtSettings
104104
import org.utbot.framework.plugin.api.visible.UtStreamConsumingException
105105
import org.utbot.framework.plugin.api.UtStreamConsumingFailure
106106
import org.utbot.framework.plugin.api.util.constructor.ValueConstructor
107+
import org.utbot.framework.plugin.api.util.fieldId
107108
import org.utbot.framework.plugin.api.util.isStatic
108109

109110
// hack

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.utbot.framework.plugin.api.UtNullModel
2323
import org.utbot.framework.plugin.api.id
2424
import org.utbot.framework.plugin.api.util.constructorId
2525
import org.utbot.framework.plugin.api.util.defaultValueModel
26+
import org.utbot.framework.plugin.api.util.fieldId
2627
import org.utbot.framework.plugin.api.util.intClassId
2728
import org.utbot.framework.plugin.api.util.objectClassId
2829
import org.utbot.framework.plugin.api.util.stringClassId

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

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -105,17 +105,16 @@ import org.utbot.engine.types.OBJECT_TYPE
105105
import org.utbot.engine.types.SECURITY_FIELD_SIGNATURE
106106
import org.utbot.engine.types.TypeRegistry
107107
import org.utbot.engine.types.TypeResolver
108-
import org.utbot.engine.util.trusted.isFromTrustedLibrary
109108
import org.utbot.engine.util.statics.concrete.associateEnumSootFieldsWithConcreteValues
110109
import org.utbot.engine.util.statics.concrete.isEnumAffectingExternalStatics
111110
import org.utbot.engine.util.statics.concrete.isEnumValuesFieldName
112111
import org.utbot.engine.util.statics.concrete.makeEnumNonStaticFieldsUpdates
113112
import org.utbot.engine.util.statics.concrete.makeEnumStaticFieldsUpdates
114113
import org.utbot.engine.util.statics.concrete.makeSymbolicValuesFromEnumConcreteValues
115114
import org.utbot.framework.UtSettings
116-
import org.utbot.framework.UtSettings.maximizeCoverageUsingReflection
117115
import org.utbot.framework.UtSettings.preferredCexOption
118116
import org.utbot.framework.UtSettings.substituteStaticsWithSymbolicVariable
117+
import org.utbot.framework.isFromTrustedLibrary
119118
import org.utbot.framework.plugin.api.ApplicationContext
120119
import org.utbot.framework.plugin.api.ClassId
121120
import org.utbot.framework.plugin.api.ExecutableId
@@ -128,6 +127,7 @@ import org.utbot.framework.plugin.api.classId
128127
import org.utbot.framework.plugin.api.id
129128
import org.utbot.framework.plugin.api.isAbstractType
130129
import org.utbot.framework.plugin.api.util.executable
130+
import org.utbot.framework.plugin.api.util.fieldId
131131
import org.utbot.framework.plugin.api.util.findFieldByIdOrNull
132132
import org.utbot.framework.plugin.api.util.jField
133133
import org.utbot.framework.plugin.api.util.jClass
@@ -2322,35 +2322,26 @@ class Traverser(
23222322
}
23232323

23242324
/**
2325-
* Marks the [createdField] as speculatively not null if the [field] is considering as
2326-
* not producing [NullPointerException].
2325+
* Marks the [createdField] as speculatively not null if the [field] is considering
2326+
* as not producing [NullPointerException].
23272327
*
2328-
* @see [SootField.speculativelyCannotProduceNullPointerException], [markAsSpeculativelyNotNull], [isFromTrustedLibrary].
2328+
* See more detailed documentation in [ApplicationContext] mentioned methods.
23292329
*/
23302330
private fun checkAndMarkLibraryFieldSpeculativelyNotNull(field: SootField, createdField: SymbolicValue) {
2331-
if (maximizeCoverageUsingReflection || !field.declaringClass.isFromTrustedLibrary()) {
2331+
if (applicationContext.avoidSpeculativeNotNullChecks(field) ||
2332+
!applicationContext.speculativelyCannotProduceNullPointerException(field, methodUnderTest.classId)) {
23322333
return
23332334
}
23342335

2335-
if (field.speculativelyCannotProduceNullPointerException()) {
2336-
markAsSpeculativelyNotNull(createdField.addr)
2337-
}
2336+
markAsSpeculativelyNotNull(createdField.addr)
23382337
}
23392338

2340-
/**
2341-
* Checks whether accessing [this] field (with a method invocation or field access) speculatively can produce
2342-
* [NullPointerException] (according to its finality or accessibility).
2343-
*
2344-
* @see docs/SpeculativeFieldNonNullability.md for more information.
2345-
*/
2346-
@Suppress("KDocUnresolvedReference")
2347-
private fun SootField.speculativelyCannotProduceNullPointerException(): Boolean = isFinal || !isPublic
2348-
23492339
private fun createArray(pName: String, type: ArrayType): ArrayValue {
23502340
val addr = UtAddrExpression(mkBVConst(pName, UtIntSort))
23512341
return createArray(addr, type, useConcreteType = false)
23522342
}
23532343

2344+
23542345
/**
23552346
* Creates an array with given [addr] and [type].
23562347
*

utbot-framework/src/main/kotlin/org/utbot/engine/util/statics/concrete/EnumConcreteUtils.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import org.utbot.engine.symbolic.SymbolicStateUpdate
1111
import org.utbot.engine.symbolic.asHardConstraint
1212
import org.utbot.engine.types.TypeResolver
1313
import org.utbot.framework.plugin.api.FieldId
14+
import org.utbot.framework.plugin.api.util.fieldId
1415
import org.utbot.framework.plugin.api.util.jField
1516
import soot.SootClass
1617
import soot.SootField

utbot-framework/src/main/kotlin/org/utbot/framework/modifications/ExecutablesAnalyzer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
package org.utbot.framework.modifications
22

3-
import org.utbot.engine.fieldId
43
import org.utbot.framework.plugin.api.ClassId
54
import org.utbot.framework.plugin.api.ExecutableId
65
import org.utbot.framework.plugin.api.FieldId
76
import org.utbot.framework.plugin.api.id
7+
import org.utbot.framework.plugin.api.util.fieldId
88
import org.utbot.framework.util.executableId
99
import soot.Scene
1010
import soot.SootMethod

0 commit comments

Comments
 (0)