Skip to content

Commit 34eaff2

Browse files
Merge branch 'main' into victoria/java-cli-image-build-update
2 parents fd7a8eb + 1321946 commit 34eaff2

62 files changed

Lines changed: 1200 additions & 356 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

utbot-cli/src/main/kotlin/org/utbot/cli/GenerateTestsAbstractCommand.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.utbot.framework.plugin.api.TreatOverflowAsError
2929
import org.utbot.framework.plugin.api.TestCaseGenerator
3030
import org.utbot.framework.plugin.api.UtMethod
3131
import org.utbot.framework.plugin.api.UtMethodTestSet
32+
import org.utbot.framework.plugin.api.util.id
3233
import org.utbot.summary.summarize
3334
import java.io.File
3435
import java.lang.reflect.Method
@@ -205,7 +206,7 @@ abstract class GenerateTestsAbstractCommand(name: String, help: String) :
205206
forceStaticMocking == ForceStaticMocking.FORCE && staticsMocking is NoStaticMocking
206207
return CodeGenerator(
207208
testFramework = testFrameworkByName(testFramework),
208-
classUnderTest = classUnderTest.java,
209+
classUnderTest = classUnderTest.id,
209210
codegenLanguage = codegenLanguage,
210211
staticsMocking = staticsMocking,
211212
forceStaticMocking = forceStaticMocking,

utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,11 @@
11
package org.utbot.common
22

3-
import java.lang.reflect.Field
43
import java.lang.reflect.InvocationTargetException
54
import java.lang.reflect.Method
65

76

87
val Class<*>.packageName: String get() = `package`?.name?:""
98

10-
fun Class<*>.findField(name: String): Field =
11-
findFieldOrNull(name) ?: error("Can't find field $name in $this")
12-
13-
fun Class<*>.findFieldOrNull(name: String): Field? = generateSequence(this) { it.superclass }
14-
.mapNotNull {
15-
try {
16-
it.getField(name)
17-
} catch (e: NoSuchFieldException) {
18-
try {
19-
it.getDeclaredField(name)
20-
} catch (e: NoSuchFieldException) {
21-
null
22-
}
23-
}
24-
}
25-
.firstOrNull()
26-
279
fun Method.invokeCatching(obj: Any?, args: List<Any?>) = try {
2810
Result.success(invoke(obj, *args.toTypedArray()))
2911
} catch (e: InvocationTargetException) {

utbot-framework-api/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ dependencies {
1414
implementation group: 'io.github.microutils', name: 'kotlin-logging', version: kotlin_logging_version
1515
}
1616

17+
compileKotlin {
18+
kotlinOptions {
19+
freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn"
20+
}
21+
}
22+
1723
shadowJar {
1824
configurations = [project.configurations.compileClasspath]
1925
archiveClassifier.set('')

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

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,27 @@ internal val utbotHomePath = "${System.getProperty("user.home")}/.utbot"
2121
private val defaultSettingsPath = "$utbotHomePath/settings.properties"
2222
private const val defaultKeyForSettingsPath = "utbot.settings.path"
2323

24-
internal class SettingDelegate<T>(val initializer: () -> T) {
24+
/**
25+
* Stores current values for each setting from [UtSettings].
26+
*/
27+
private val settingsValues: MutableMap<KProperty<*>, Any?> = mutableMapOf()
28+
29+
internal class SettingDelegate<T>(val property: KProperty<*>, val initializer: () -> T) {
2530
private var value = initializer()
2631

32+
init {
33+
updateSettingValue()
34+
}
35+
2736
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = value
2837

2938
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
3039
this.value = value
40+
updateSettingValue()
41+
}
42+
43+
private fun updateSettingValue() {
44+
settingsValues[property] = value
3145
}
3246
}
3347

@@ -55,15 +69,13 @@ object UtSettings {
5569
defaultValue: T,
5670
converter: (String) -> T
5771
): PropertyDelegateProvider<UtSettings, SettingDelegate<T>> {
58-
return PropertyDelegateProvider { _, prop ->
59-
SettingDelegate {
72+
return PropertyDelegateProvider { _, property ->
73+
SettingDelegate(property) {
6074
try {
61-
properties.getProperty(prop.name)?.let(converter) ?: defaultValue
75+
properties.getProperty(property.name)?.let(converter) ?: defaultValue
6276
} catch (e: Throwable) {
6377
logger.info(e) { e.message }
6478
defaultValue
65-
} finally {
66-
properties.putIfAbsent(prop.name, defaultValue.toString())
6779
}
6880
}
6981
}
@@ -76,7 +88,6 @@ object UtSettings {
7688
private inline fun <reified T : Enum<T>> getEnumProperty(defaultValue: T) =
7789
getProperty(defaultValue) { enumValueOf(it) }
7890

79-
8091
/**
8192
* Setting to disable coroutines debug explicitly.
8293
*
@@ -381,9 +392,10 @@ object UtSettings {
381392
var skipTestGenerationForSyntheticMethods by getBooleanProperty(true)
382393

383394
override fun toString(): String =
384-
properties
395+
settingsValues
396+
.mapKeys { it.key.name }
385397
.entries
386-
.sortedBy { it.key.toString() }
398+
.sortedBy { it.key }
387399
.joinToString(separator = System.lineSeparator()) { "\t${it.key}=${it.value}" }
388400
}
389401

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

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import org.utbot.framework.plugin.api.util.charClassId
2020
import org.utbot.framework.plugin.api.util.constructor
2121
import org.utbot.framework.plugin.api.util.doubleClassId
2222
import org.utbot.framework.plugin.api.util.executableId
23-
import org.utbot.framework.plugin.api.util.findFieldOrNull
2423
import org.utbot.framework.plugin.api.util.floatClassId
2524
import org.utbot.framework.plugin.api.util.id
2625
import org.utbot.framework.plugin.api.util.intClassId
@@ -29,7 +28,9 @@ import org.utbot.framework.plugin.api.util.isPrimitive
2928
import org.utbot.framework.plugin.api.util.jClass
3029
import org.utbot.framework.plugin.api.util.longClassId
3130
import org.utbot.framework.plugin.api.util.method
31+
import org.utbot.framework.plugin.api.util.objectClassId
3232
import org.utbot.framework.plugin.api.util.primitiveTypeJvmNameOrNull
33+
import org.utbot.framework.plugin.api.util.safeJField
3334
import org.utbot.framework.plugin.api.util.shortClassId
3435
import org.utbot.framework.plugin.api.util.toReferenceTypeBytecodeSignature
3536
import org.utbot.framework.plugin.api.util.voidClassId
@@ -50,6 +51,8 @@ import soot.jimple.JimpleBody
5051
import soot.jimple.Stmt
5152
import java.io.File
5253
import java.lang.reflect.Modifier
54+
import kotlin.contracts.ExperimentalContracts
55+
import kotlin.contracts.contract
5356
import kotlin.jvm.internal.CallableReference
5457
import kotlin.reflect.KCallable
5558
import kotlin.reflect.KClass
@@ -58,6 +61,8 @@ import kotlin.reflect.full.instanceParameter
5861
import kotlin.reflect.jvm.javaConstructor
5962
import kotlin.reflect.jvm.javaType
6063

64+
const val SYMBOLIC_NULL_ADDR: Int = 0
65+
6166
data class UtMethod<R>(
6267
val callable: KCallable<R>,
6368
val clazz: KClass<*>
@@ -98,22 +103,6 @@ data class UtMethodTestSet(
98103
val clustersInfo: List<Pair<UtClusterInfo?, IntRange>> = listOf(null to executions.indices)
99104
)
100105

101-
data class CgMethodTestSet private constructor(
102-
val executableId: ExecutableId,
103-
val executions: List<UtExecution> = emptyList(),
104-
val jimpleBody: JimpleBody? = null,
105-
val errors: Map<String, Int> = emptyMap(),
106-
val clustersInfo: List<Pair<UtClusterInfo?, IntRange>> = listOf(null to executions.indices)
107-
) {
108-
constructor(from: UtMethodTestSet) : this(
109-
from.method.callable.executableId,
110-
from.executions,
111-
from.jimpleBody,
112-
from.errors,
113-
from.clustersInfo
114-
)
115-
}
116-
117106
data class Step(
118107
val stmt: Stmt,
119108
val depth: Int,
@@ -282,6 +271,27 @@ fun UtModel.hasDefaultValue() =
282271
*/
283272
fun UtModel.isMockModel() = this is UtCompositeModel && isMock
284273

274+
/**
275+
* Get model id (symbolic null value for UtNullModel)
276+
* or null if model has no id (e.g., a primitive model) or the id is null.
277+
*/
278+
fun UtModel.idOrNull(): Int? = when (this) {
279+
is UtNullModel -> SYMBOLIC_NULL_ADDR
280+
is UtReferenceModel -> id
281+
else -> null
282+
}
283+
284+
/**
285+
* Returns the model id if it is available, or throws an [IllegalStateException].
286+
*/
287+
@OptIn(ExperimentalContracts::class)
288+
fun UtModel?.getIdOrThrow(): Int {
289+
contract {
290+
returns() implies (this@getIdOrThrow != null)
291+
}
292+
return this?.idOrNull() ?: throw IllegalStateException("Model id must not be null: $this")
293+
}
294+
285295
/**
286296
* Model for nulls.
287297
*/
@@ -323,20 +333,24 @@ object UtVoidModel : UtModel(voidClassId)
323333
* Model for enum constant
324334
*/
325335
data class UtEnumConstantModel(
336+
override val id: Int?,
326337
override val classId: ClassId,
327338
val value: Enum<*>
328-
) : UtModel(classId) {
329-
override fun toString(): String = "$value"
339+
) : UtReferenceModel(id, classId) {
340+
// Model id is included for debugging purposes
341+
override fun toString(): String = "$value@$id"
330342
}
331343

332344
/**
333345
* Model for class reference
334346
*/
335347
data class UtClassRefModel(
348+
override val id: Int?,
336349
override val classId: ClassId,
337350
val value: Class<*>
338-
) : UtModel(classId) {
339-
override fun toString(): String = "$value"
351+
) : UtReferenceModel(id, classId) {
352+
// Model id is included for debugging purposes
353+
override fun toString(): String = "$value@$id"
340354
}
341355

342356
/**
@@ -366,7 +380,7 @@ data class UtCompositeModel(
366380
if (fields.isNotEmpty()) {
367381
append(" ")
368382
append(fields.entries.joinToString(", ", "{", "}") { (field, value) ->
369-
if (value.classId != classId || value.isNull()) "${field.name}: $value" else "${field.name}: not evaluated"
383+
if (value.classId != classId || value.isNull()) "(${field.declaringClass}) ${field.name}: $value" else "${field.name}: not evaluated"
370384
}) // TODO: here we can get an infinite recursion if we have cyclic dependencies.
371385
}
372386
if (mocks.isNotEmpty()) {
@@ -876,7 +890,7 @@ open class FieldId(val declaringClass: ClassId, val name: String) {
876890
return result
877891
}
878892

879-
override fun toString() = declaringClass.findFieldOrNull(name).toString()
893+
override fun toString() = safeJField.toString()
880894
}
881895

882896
inline fun <T> withReflection(block: () -> T): T {

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ package org.utbot.framework.plugin.api.impl
33
import org.utbot.framework.plugin.api.ClassId
44
import org.utbot.framework.plugin.api.FieldId
55
import org.utbot.framework.plugin.api.classId
6-
import org.utbot.framework.plugin.api.util.field
6+
import org.utbot.framework.plugin.api.util.jField
77
import org.utbot.framework.plugin.api.util.id
88
import java.lang.reflect.Modifier
99
import soot.Scene
@@ -32,25 +32,25 @@ interface FieldIdStrategy {
3232
class FieldIdReflectionStrategy(val fieldId: FieldId) : FieldIdStrategy {
3333

3434
override val isPublic: Boolean
35-
get() = Modifier.isPublic(fieldId.field.modifiers)
35+
get() = Modifier.isPublic(fieldId.jField.modifiers)
3636

3737
override val isProtected: Boolean
38-
get() = Modifier.isProtected(fieldId.field.modifiers)
38+
get() = Modifier.isProtected(fieldId.jField.modifiers)
3939

4040
override val isPrivate: Boolean
41-
get() = Modifier.isPrivate(fieldId.field.modifiers)
41+
get() = Modifier.isPrivate(fieldId.jField.modifiers)
4242

4343
override val isFinal: Boolean
44-
get() = Modifier.isFinal(fieldId.field.modifiers)
44+
get() = Modifier.isFinal(fieldId.jField.modifiers)
4545

4646
override val isStatic: Boolean
47-
get() = Modifier.isStatic(fieldId.field.modifiers)
47+
get() = Modifier.isStatic(fieldId.jField.modifiers)
4848

4949
override val isSynthetic: Boolean
50-
get() = fieldId.field.isSynthetic
50+
get() = fieldId.jField.isSynthetic
5151

5252
override val type: ClassId
53-
get() = fieldId.field.type.id
53+
get() = fieldId.jField.type.id
5454
}
5555

5656
class FieldIdSootStrategy(val declaringClass: ClassId, val fieldId: FieldId) : FieldIdStrategy {

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.utbot.framework.plugin.api.util
22

3-
import org.utbot.common.findFieldOrNull
43
import org.utbot.framework.plugin.api.BuiltinClassId
54
import org.utbot.framework.plugin.api.BuiltinMethodId
65
import org.utbot.framework.plugin.api.ClassId
@@ -118,6 +117,9 @@ val ClassId.isFloatType: Boolean
118117
val ClassId.isDoubleType: Boolean
119118
get() = this == doubleClassId || this == doubleWrapperClassId
120119

120+
val ClassId.isClassType: Boolean
121+
get() = this == classClassId
122+
121123
val voidClassId = ClassId("void")
122124
val booleanClassId = ClassId("boolean")
123125
val byteClassId = ClassId("byte")
@@ -139,6 +141,8 @@ val longWrapperClassId = java.lang.Long::class.id
139141
val floatWrapperClassId = java.lang.Float::class.id
140142
val doubleWrapperClassId = java.lang.Double::class.id
141143

144+
val classClassId = java.lang.Class::class.id
145+
142146
// We consider void wrapper as primitive wrapper
143147
// because voidClassId is considered primitive here
144148
val primitiveWrappers = setOf(
@@ -286,9 +290,20 @@ val ClassId.isMap: Boolean
286290
val ClassId.isIterableOrMap: Boolean
287291
get() = isIterable || isMap
288292

289-
fun ClassId.findFieldOrNull(fieldName: String): Field? = jClass.findFieldOrNull(fieldName)
293+
val ClassId.isEnum: Boolean
294+
get() = jClass.isEnum
290295

291-
fun ClassId.hasField(fieldName: String): Boolean = findFieldOrNull(fieldName) != null
296+
fun ClassId.findFieldByIdOrNull(fieldId: FieldId): Field? {
297+
if (isNotSubtypeOf(fieldId.declaringClass)) {
298+
return null
299+
}
300+
301+
return fieldId.safeJField
302+
}
303+
304+
fun ClassId.hasField(fieldId: FieldId): Boolean {
305+
return findFieldByIdOrNull(fieldId) != null
306+
}
292307

293308
fun ClassId.defaultValueModel(): UtModel = when (this) {
294309
intClassId -> UtPrimitiveModel(0)
@@ -303,11 +318,12 @@ fun ClassId.defaultValueModel(): UtModel = when (this) {
303318
}
304319

305320
// FieldId utils
321+
val FieldId.safeJField: Field?
322+
get() = declaringClass.jClass.declaredFields.firstOrNull { it.name == name }
306323

307324
// TODO: maybe cache it somehow in the future
308-
val FieldId.field: Field
309-
get() = declaringClass.jClass.declaredFields.firstOrNull { it.name == name }
310-
?: error("Field $name is not found in class ${declaringClass.jClass.name}")
325+
val FieldId.jField: Field
326+
get() = safeJField ?: error("Field $name is not declared in class ${declaringClass.jClass.name}")
311327

312328
// https://docstore.mik.ua/orelly/java-ent/jnut/ch03_13.htm
313329
val FieldId.isInnerClassEnclosingClassReference: Boolean

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ import org.utbot.framework.plugin.api.UtCompositeModel
2424
import org.utbot.framework.plugin.api.UtModel
2525
import org.utbot.framework.plugin.api.UtNullModel
2626
import org.utbot.framework.plugin.api.UtPrimitiveModel
27-
import org.utbot.framework.plugin.api.UtReferenceModel
27+
import org.utbot.framework.plugin.api.getIdOrThrow
28+
import org.utbot.framework.plugin.api.idOrNull
2829
import org.utbot.framework.plugin.api.util.id
2930
import org.utbot.framework.plugin.api.util.objectArrayClassId
3031
import org.utbot.framework.plugin.api.util.objectClassId
@@ -398,7 +399,7 @@ class AssociativeArrayWrapper : WrapperInterface {
398399
UtNullModel(objectClassId),
399400
stores = (0 until sizeValue).associateTo(mutableMapOf()) { i ->
400401
val model = touchedValues.stores[i]
401-
val addr = if (model is UtNullModel) 0 else (model as UtReferenceModel).id!!
402+
val addr = model.getIdOrThrow()
402403
addr to resolver.resolveModel(
403404
ObjectValue(
404405
TypeStorage(OBJECT_TYPE),

0 commit comments

Comments
 (0)