diff --git a/utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt b/utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt index 1f6bb848a5..7a6158665b 100644 --- a/utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt +++ b/utbot-core/src/main/kotlin/org/utbot/common/KClassUtil.kt @@ -1,29 +1,11 @@ package org.utbot.common -import java.lang.reflect.Field import java.lang.reflect.InvocationTargetException import java.lang.reflect.Method val Class<*>.packageName: String get() = `package`?.name?:"" -fun Class<*>.findField(name: String): Field = - findFieldOrNull(name) ?: error("Can't find field $name in $this") - -fun Class<*>.findFieldOrNull(name: String): Field? = generateSequence(this) { it.superclass } - .mapNotNull { - try { - it.getField(name) - } catch (e: NoSuchFieldException) { - try { - it.getDeclaredField(name) - } catch (e: NoSuchFieldException) { - null - } - } - } - .firstOrNull() - fun Method.invokeCatching(obj: Any?, args: List) = try { Result.success(invoke(obj, *args.toTypedArray())) } catch (e: InvocationTargetException) { diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt index 565bb51a25..ae2e311802 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/Api.kt @@ -20,7 +20,6 @@ import org.utbot.framework.plugin.api.util.charClassId import org.utbot.framework.plugin.api.util.constructor import org.utbot.framework.plugin.api.util.doubleClassId import org.utbot.framework.plugin.api.util.executableId -import org.utbot.framework.plugin.api.util.findFieldOrNull import org.utbot.framework.plugin.api.util.floatClassId import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.intClassId @@ -30,6 +29,7 @@ import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.longClassId import org.utbot.framework.plugin.api.util.method import org.utbot.framework.plugin.api.util.primitiveTypeJvmNameOrNull +import org.utbot.framework.plugin.api.util.safeJField import org.utbot.framework.plugin.api.util.shortClassId import org.utbot.framework.plugin.api.util.toReferenceTypeBytecodeSignature import org.utbot.framework.plugin.api.util.voidClassId @@ -366,7 +366,7 @@ data class UtCompositeModel( if (fields.isNotEmpty()) { append(" ") append(fields.entries.joinToString(", ", "{", "}") { (field, value) -> - if (value.classId != classId || value.isNull()) "${field.name}: $value" else "${field.name}: not evaluated" + if (value.classId != classId || value.isNull()) "(${field.declaringClass}) ${field.name}: $value" else "${field.name}: not evaluated" }) // TODO: here we can get an infinite recursion if we have cyclic dependencies. } if (mocks.isNotEmpty()) { @@ -876,7 +876,7 @@ open class FieldId(val declaringClass: ClassId, val name: String) { return result } - override fun toString() = declaringClass.findFieldOrNull(name).toString() + override fun toString() = safeJField.toString() } inline fun withReflection(block: () -> T): T { diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/impl/FieldIdStrategies.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/impl/FieldIdStrategies.kt index 8ce32fdbc2..21e23f0b26 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/impl/FieldIdStrategies.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/impl/FieldIdStrategies.kt @@ -3,7 +3,7 @@ package org.utbot.framework.plugin.api.impl import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.FieldId import org.utbot.framework.plugin.api.classId -import org.utbot.framework.plugin.api.util.field +import org.utbot.framework.plugin.api.util.jField import org.utbot.framework.plugin.api.util.id import java.lang.reflect.Modifier import soot.Scene @@ -32,25 +32,25 @@ interface FieldIdStrategy { class FieldIdReflectionStrategy(val fieldId: FieldId) : FieldIdStrategy { override val isPublic: Boolean - get() = Modifier.isPublic(fieldId.field.modifiers) + get() = Modifier.isPublic(fieldId.jField.modifiers) override val isProtected: Boolean - get() = Modifier.isProtected(fieldId.field.modifiers) + get() = Modifier.isProtected(fieldId.jField.modifiers) override val isPrivate: Boolean - get() = Modifier.isPrivate(fieldId.field.modifiers) + get() = Modifier.isPrivate(fieldId.jField.modifiers) override val isFinal: Boolean - get() = Modifier.isFinal(fieldId.field.modifiers) + get() = Modifier.isFinal(fieldId.jField.modifiers) override val isStatic: Boolean - get() = Modifier.isStatic(fieldId.field.modifiers) + get() = Modifier.isStatic(fieldId.jField.modifiers) override val isSynthetic: Boolean - get() = fieldId.field.isSynthetic + get() = fieldId.jField.isSynthetic override val type: ClassId - get() = fieldId.field.type.id + get() = fieldId.jField.type.id } class FieldIdSootStrategy(val declaringClass: ClassId, val fieldId: FieldId) : FieldIdStrategy { diff --git a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/IdUtil.kt b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/IdUtil.kt index 02779a6e93..29e4cc8995 100644 --- a/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/IdUtil.kt +++ b/utbot-framework-api/src/main/kotlin/org/utbot/framework/plugin/api/util/IdUtil.kt @@ -1,6 +1,5 @@ package org.utbot.framework.plugin.api.util -import org.utbot.common.findFieldOrNull import org.utbot.framework.plugin.api.BuiltinClassId import org.utbot.framework.plugin.api.BuiltinMethodId import org.utbot.framework.plugin.api.ClassId @@ -286,9 +285,17 @@ val ClassId.isMap: Boolean val ClassId.isIterableOrMap: Boolean get() = isIterable || isMap -fun ClassId.findFieldOrNull(fieldName: String): Field? = jClass.findFieldOrNull(fieldName) +fun ClassId.findFieldByIdOrNull(fieldId: FieldId): Field? { + if (isNotSubtypeOf(fieldId.declaringClass)) { + return null + } + + return fieldId.safeJField +} -fun ClassId.hasField(fieldName: String): Boolean = findFieldOrNull(fieldName) != null +fun ClassId.hasField(fieldId: FieldId): Boolean { + return findFieldByIdOrNull(fieldId) != null +} fun ClassId.defaultValueModel(): UtModel = when (this) { intClassId -> UtPrimitiveModel(0) @@ -303,11 +310,12 @@ fun ClassId.defaultValueModel(): UtModel = when (this) { } // FieldId utils +val FieldId.safeJField: Field? + get() = declaringClass.jClass.declaredFields.firstOrNull { it.name == name } // TODO: maybe cache it somehow in the future -val FieldId.field: Field - get() = declaringClass.jClass.declaredFields.firstOrNull { it.name == name } - ?: error("Field $name is not found in class ${declaringClass.jClass.name}") +val FieldId.jField: Field + get() = safeJField ?: error("Field $name is not declared in class ${declaringClass.jClass.name}") // https://docstore.mik.ua/orelly/java-ent/jnut/ch03_13.htm val FieldId.isInnerClassEnclosingClassReference: Boolean diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Hierarchy.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Hierarchy.kt index 113485b18a..c610ab822c 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Hierarchy.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Hierarchy.kt @@ -28,10 +28,12 @@ class Hierarchy(private val typeRegistry: TypeRegistry) { type as? RefType ?: error("$type is not a refType") val realType = typeRegistry.findRealType(type) as RefType + val realFieldDeclaringType = typeRegistry.findRealType(field.declaringClass.type) as RefType - val ancestorType = ancestors(realType.sootClass.id).lastOrNull { it.declaresField(field.subSignature) }?.type - ?: error("No such field ${field.subSignature} found in ${realType.sootClass.name}") - return ChunkId("$ancestorType", field.name) + if (realFieldDeclaringType.sootClass !in ancestors(realType.sootClass.id)) { + error("No such field ${field.subSignature} found in ${realType.sootClass.name}") + } + return ChunkId("$realFieldDeclaringType", field.name) } /** diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Strings.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Strings.kt index cb0e1fba1d..8c31fda3ad 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Strings.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Strings.kt @@ -313,7 +313,7 @@ sealed class UtAbstractStringBuilderWrapper(className: String) : BaseOverriddenW val arrayValuesChunkId = typeRegistry.arrayChunkId(charArrayType) - val valuesFieldChunkId = hierarchy.chunkIdForField(utStringClass.type, overriddenClass.valueField) + val valuesFieldChunkId = hierarchy.chunkIdForField(overriddenClass.type, overriddenClass.valueField) val valuesArrayAddrDescriptor = MemoryChunkDescriptor(valuesFieldChunkId, wrapper.type, charType) val valuesArrayAddr = findArray(valuesArrayAddrDescriptor, MemoryState.CURRENT).select(wrapper.addr) diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt index 4563012cb4..74c8d7b624 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/Traverser.kt @@ -8,7 +8,6 @@ import kotlinx.collections.immutable.toPersistentMap import kotlinx.collections.immutable.toPersistentSet import org.utbot.common.WorkaroundReason.HACK import org.utbot.common.WorkaroundReason.REMOVE_ANONYMOUS_CLASSES -import org.utbot.common.findField import org.utbot.common.unreachableBranch import org.utbot.common.withAccessibility import org.utbot.common.workaround @@ -90,8 +89,9 @@ import org.utbot.framework.plugin.api.MethodId import org.utbot.framework.plugin.api.UtMethod import org.utbot.framework.plugin.api.classId import org.utbot.framework.plugin.api.id -import org.utbot.framework.plugin.api.util.id +import org.utbot.framework.plugin.api.util.jField import org.utbot.framework.plugin.api.util.jClass +import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.signature import org.utbot.framework.plugin.api.util.utContext import org.utbot.framework.util.executableId @@ -582,7 +582,7 @@ class Traverser( declaringClass: SootClass, stmt: Stmt ): SymbolicStateUpdate { - val concreteValue = extractConcreteValue(field, declaringClass) + val concreteValue = extractConcreteValue(field) val (symbolicResult, symbolicStateUpdate) = toMethodResult(concreteValue, field.type) val symbolicValue = (symbolicResult as SymbolicSuccess).value @@ -634,12 +634,20 @@ class Traverser( // Some fields are inaccessible with reflection, so we have to instantiate it by ourselves. // Otherwise, extract it from the class. // TODO JIRA:1593 - private fun extractConcreteValue(field: SootField, declaringClass: SootClass): Any? = + private fun extractConcreteValue(field: SootField): Any? = when (field.signature) { SECURITY_FIELD_SIGNATURE -> SecurityManager() FIELD_FILTER_MAP_FIELD_SIGNATURE -> mapOf(Reflection::class to arrayOf("fieldFilterMap", "methodFilterMap")) METHOD_FILTER_MAP_FIELD_SIGNATURE -> emptyMap, Array>() - else -> declaringClass.id.jClass.findField(field.name).let { it.withAccessibility { it.get(null) } } + else -> { + val fieldId = field.fieldId + val jField = fieldId.jField + jField.let { + it.withAccessibility { + it.get(null) + } + } + } } private fun isStaticInstanceInMethodResult(id: ClassId, methodResult: MethodResult?) = diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/TypeResolver.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/TypeResolver.kt index 95565eb600..323dd552e6 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/TypeResolver.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/TypeResolver.kt @@ -70,8 +70,6 @@ class TypeResolver(private val typeRegistry: TypeRegistry, private val hierarchy hierarchy .ancestors(type.sootClass.id) .flatMap { it.fields } - .asReversed() // to take fields of the farthest parent in the distinctBy - .distinctBy { it.name } // TODO we lose hidden fields here JIRA:315 } /** diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/ValueConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/ValueConstructor.kt index 06928beda1..74750c6005 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/ValueConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/ValueConstructor.kt @@ -1,7 +1,5 @@ package org.utbot.engine -import org.utbot.common.findField -import org.utbot.common.findFieldOrNull import org.utbot.common.invokeCatching import org.utbot.common.withAccessibility import org.utbot.framework.plugin.api.ClassId @@ -37,6 +35,7 @@ import org.utbot.framework.plugin.api.UtValueExecutionState import org.utbot.framework.plugin.api.UtVoidModel import org.utbot.framework.plugin.api.isMockModel import org.utbot.framework.plugin.api.util.constructor +import org.utbot.framework.plugin.api.util.jField import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.method import org.utbot.framework.plugin.api.util.utContext @@ -212,9 +211,8 @@ class ValueConstructor { val classInstance = javaClass.anyInstance constructedObjects[model] = classInstance - model.fields.forEach { (field, fieldModel) -> - val declaredField = - javaClass.findFieldOrNull(field.name) ?: error("Can't find field: $field for $javaClass") + model.fields.forEach { (fieldId, fieldModel) -> + val declaredField = fieldId.jField val accessible = declaredField.isAccessible try { @@ -228,7 +226,7 @@ class ValueConstructor { fieldModel.classId.name, model.classId.name, UtConcreteValue(classInstance), - field.name + fieldId.name ) } val value = construct(fieldModel, target).value @@ -360,7 +358,7 @@ class ValueConstructor { val instanceClassId = instanceModel.classId val fieldModel = directSetterModel.fieldModel - val field = instance::class.java.findField(directSetterModel.fieldId.name) + val field = directSetterModel.fieldId.jField val isAccessible = field.isAccessible try { diff --git a/utbot-framework/src/main/kotlin/org/utbot/engine/util/statics/concrete/EnumConcreteUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/engine/util/statics/concrete/EnumConcreteUtils.kt index f1d547628c..96329b4c01 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/engine/util/statics/concrete/EnumConcreteUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/engine/util/statics/concrete/EnumConcreteUtils.kt @@ -10,7 +10,7 @@ import org.utbot.engine.pc.select import org.utbot.engine.symbolic.SymbolicStateUpdate import org.utbot.engine.symbolic.asHardConstraint import org.utbot.framework.plugin.api.FieldId -import org.utbot.framework.plugin.api.util.field +import org.utbot.framework.plugin.api.util.jField import soot.SootClass import soot.SootField import soot.SootMethod @@ -43,7 +43,7 @@ fun associateEnumSootFieldsWithConcreteValues( enumConstants: List> ): List>> = enumFields.map { enumSootField -> - val enumField = enumSootField.fieldId.field + val enumField = enumSootField.fieldId.jField val fieldValues = if (enumSootField.isStatic) { val staticFieldValue = enumField.withAccessibility { enumField.get(null) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgFieldStateManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgFieldStateManager.kt index 570dbe3a6f..64a50e17a8 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgFieldStateManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgFieldStateManager.kt @@ -177,7 +177,7 @@ internal class CgFieldStateManagerImpl(val context: CgContext) } // if previous field has type that does not have current field, this field is inaccessible - if (index > 0 && !path[index - 1].type.hasField(fieldPathElement.field.name)) { + if (index > 0 && !path[index - 1].type.hasField(fieldPathElement.field)) { lastAccessibleIndex = index - 1 break } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt index 3a5bc8e7c3..744eecb7fa 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgMethodConstructor.kt @@ -121,7 +121,7 @@ import org.utbot.framework.plugin.api.util.doubleArrayClassId import org.utbot.framework.plugin.api.util.doubleClassId import org.utbot.framework.plugin.api.util.doubleWrapperClassId import org.utbot.framework.plugin.api.util.executable -import org.utbot.framework.plugin.api.util.field +import org.utbot.framework.plugin.api.util.jField import org.utbot.framework.plugin.api.util.floatArrayClassId import org.utbot.framework.plugin.api.util.floatClassId import org.utbot.framework.plugin.api.util.floatWrapperClassId @@ -873,8 +873,8 @@ internal class CgMethodConstructor(val context: CgContext) : CgContextOwner by c private fun FieldId.getAccessExpression(variable: CgVariable): CgExpression = // Can directly access field only if it is declared in variable class (or in its ancestors) // and is accessible from current package - if (variable.type.hasField(name) && isAccessibleFrom(testClassPackageName)) { - if (field.isStatic) CgStaticFieldAccess(this) else CgFieldAccess(variable, this) + if (variable.type.hasField(this) && isAccessibleFrom(testClassPackageName)) { + if (jField.isStatic) CgStaticFieldAccess(this) else CgFieldAccess(variable, this) } else { testClassThisInstance[getFieldValue](variable, stringLiteral(name)) } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt index 880b199022..0f13a1a958 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/constructor/tree/CgVariableConstructor.kt @@ -47,8 +47,8 @@ import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.UtReferenceModel import org.utbot.framework.plugin.api.UtVoidModel import org.utbot.framework.plugin.api.util.defaultValueModel -import org.utbot.framework.plugin.api.util.field -import org.utbot.framework.plugin.api.util.findFieldOrNull +import org.utbot.framework.plugin.api.util.jField +import org.utbot.framework.plugin.api.util.findFieldByIdOrNull import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.intClassId import org.utbot.framework.plugin.api.util.isArray @@ -128,9 +128,9 @@ internal class CgVariableConstructor(val context: CgContext) : } for ((fieldId, fieldModel) in model.fields) { - val field = fieldId.field + val field = fieldId.jField val variableForField = getOrCreateVariable(fieldModel) - val fieldFromVariableSpecifiedType = obj.type.findFieldOrNull(field.name) + val fieldFromVariableSpecifiedType = obj.type.findFieldByIdOrNull(fieldId) // we cannot set field directly if variable declared type does not have such field // or we cannot directly create variable for field with the specified type (it is private, for example) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt index d1452b2cef..170f9c743b 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/MockValueConstructor.kt @@ -1,7 +1,5 @@ package org.utbot.framework.concrete -import org.utbot.common.findField -import org.utbot.common.findFieldOrNull import org.utbot.common.invokeCatching import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.ConstructorId @@ -33,6 +31,7 @@ import org.utbot.framework.plugin.api.UtVoidModel import org.utbot.framework.plugin.api.isMockModel import org.utbot.framework.plugin.api.util.constructor import org.utbot.framework.plugin.api.util.executableId +import org.utbot.framework.plugin.api.util.jField import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.method import org.utbot.framework.plugin.api.util.utContext @@ -169,9 +168,8 @@ class MockValueConstructor( mockInstance } - model.fields.forEach { (field, fieldModel) -> - val declaredField = - javaClass.findFieldOrNull(field.name) ?: error("Can't find field: $field for $javaClass") + model.fields.forEach { (fieldId, fieldModel) -> + val declaredField = fieldId.jField val accessible = declaredField.isAccessible declaredField.isAccessible = true @@ -179,7 +177,7 @@ class MockValueConstructor( modifiersField.isAccessible = true val target = mockTarget(fieldModel) { - FieldMockTarget(fieldModel.classId.name, model.classId.name, UtConcreteValue(classInstance), field.name) + FieldMockTarget(fieldModel.classId.name, model.classId.name, UtConcreteValue(classInstance), fieldId.name) } val value = construct(fieldModel, target).value val instance = if (Modifier.isStatic(declaredField.modifiers)) null else classInstance @@ -394,7 +392,7 @@ class MockValueConstructor( val instanceClassId = instanceModel.classId val fieldModel = directSetterModel.fieldModel - val field = instance::class.java.findField(directSetterModel.fieldId.name) + val field = directSetterModel.fieldId.jField val isAccessible = field.isAccessible try { diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtExecutionInstrumentation.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtExecutionInstrumentation.kt index 5c587a48ee..6a7ca07ec2 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtExecutionInstrumentation.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/concrete/UtExecutionInstrumentation.kt @@ -23,7 +23,7 @@ import org.utbot.framework.plugin.api.UtNewInstanceInstrumentation import org.utbot.framework.plugin.api.UtStaticMethodInstrumentation import org.utbot.framework.plugin.api.UtTimeoutException import org.utbot.framework.plugin.api.util.UtContext -import org.utbot.framework.plugin.api.util.field +import org.utbot.framework.plugin.api.util.jField import org.utbot.framework.plugin.api.util.id import org.utbot.framework.plugin.api.util.singleExecutableId import org.utbot.framework.plugin.api.util.utContext @@ -178,7 +178,7 @@ object UtExecutionInstrumentation : Instrumentation { val stateAfterParametersWithThis = params.map { construct(it.value, it.clazz.id) } val stateAfterStatics = (staticFields.keys/* + traceHandler.computePutStatics()*/) .associateWith { fieldId -> - fieldId.field.run { construct(withAccessibility { get(null) }, fieldId.type) } + fieldId.jField.run { construct(withAccessibility { get(null) }, fieldId.type) } } val (stateAfterThis, stateAfterParameters) = if (stateBefore.thisInstance == null) { null to stateAfterParametersWithThis @@ -258,7 +258,7 @@ object UtExecutionInstrumentation : Instrumentation { val savedFields = mutableMapOf() try { staticFields.forEach { (fieldId, value) -> - fieldId.field.run { + fieldId.jField.run { withAccessibility { savedFields[fieldId] = get(null) set(null, value) @@ -268,7 +268,7 @@ object UtExecutionInstrumentation : Instrumentation { return block() } finally { savedFields.forEach { (fieldId, value) -> - fieldId.field.run { + fieldId.jField.run { withAccessibility { set(null, value) } diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/UtModelTestCaseChecker.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/UtModelTestCaseChecker.kt index 177f63565b..2d66c07750 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/UtModelTestCaseChecker.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/UtModelTestCaseChecker.kt @@ -6,10 +6,10 @@ import org.utbot.common.ClassLocation import org.utbot.common.FileUtil.findPathToClassFiles import org.utbot.common.FileUtil.locateClass import org.utbot.common.WorkaroundReason.HACK -import org.utbot.common.findField import org.utbot.common.workaround import org.utbot.engine.prettify import org.utbot.framework.UtSettings.checkSolverTimeoutMillis +import org.utbot.framework.plugin.api.ClassId import org.utbot.framework.plugin.api.CodegenLanguage import org.utbot.framework.plugin.api.FieldId import org.utbot.framework.plugin.api.MockStrategyApi @@ -27,8 +27,6 @@ import org.utbot.framework.plugin.api.getOrThrow import org.utbot.framework.plugin.api.util.UtContext import org.utbot.framework.plugin.api.util.defaultValueModel import org.utbot.framework.plugin.api.util.executableId -import org.utbot.framework.plugin.api.util.fieldId -import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.plugin.api.util.withUtContext import java.nio.file.Path import kotlin.reflect.KClass @@ -176,8 +174,8 @@ internal abstract class UtModelTestCaseChecker( /** * Finds field model in [UtCompositeModel] and [UtAssembleModel]. For assemble model supports direct field access only. */ - protected fun UtModel.findField(fieldName: String): UtModel = - findField(this.classId.jClass.findField(fieldName).fieldId) + protected fun UtModel.findField(fieldName: String, declaringClass: ClassId = this.classId): UtModel = + findField(FieldId(declaringClass, fieldName)) /** * Finds field model in [UtCompositeModel] and [UtAssembleModel]. For assemble model supports direct field access only. diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumTest.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumTest.kt index 48fb11b8ba..57628fc21c 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumTest.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/enums/ClassWithEnumTest.kt @@ -1,6 +1,5 @@ package org.utbot.examples.enums -import org.utbot.common.findField import org.utbot.examples.UtValueTestCaseChecker import org.utbot.examples.DoNotCalculate import org.utbot.examples.enums.ClassWithEnum.StatusEnum.ERROR @@ -13,6 +12,7 @@ import org.utbot.framework.plugin.api.FieldId import org.utbot.framework.plugin.api.util.id import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test +import org.utbot.framework.plugin.api.util.jField class ClassWithEnumTest : UtValueTestCaseChecker(testClass = ClassWithEnum::class) { @Test @@ -111,7 +111,7 @@ class ClassWithEnumTest : UtValueTestCaseChecker(testClass = ClassWithEnum::clas eq(1), { t, staticsAfter, r -> // for some reasons x is inaccessible - val x = t.javaClass.findField("x").get(t) as Int + val x = FieldId(t.javaClass.id, "x").jField.get(t) as Int val y = staticsAfter[FieldId(ClassWithEnum.ClassWithStaticField::class.id, "y")]!!.value as Int diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/objects/HiddenFieldAccessModifiersTest.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/objects/HiddenFieldAccessModifiersTest.kt new file mode 100644 index 0000000000..2a66eb2288 --- /dev/null +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/objects/HiddenFieldAccessModifiersTest.kt @@ -0,0 +1,21 @@ +package org.utbot.examples.objects + +import org.utbot.examples.UtValueTestCaseChecker +import org.utbot.examples.eq +import org.junit.jupiter.api.Test + +internal class HiddenFieldAccessModifiersTest : UtValueTestCaseChecker(testClass = HiddenFieldAccessModifiersExample::class) { + @Test + fun testCheckSuperFieldEqualsOne() { + // TODO: currently, codegen can't handle tests with field hiding (see #646) + withEnabledTestingCodeGeneration(testCodeGeneration = false) { + check( + HiddenFieldAccessModifiersExample::checkSuperFieldEqualsOne, + eq(3), + { o, _ -> o == null }, + { _, r -> r == true }, + { _, r -> r == false }, + ) + } + } +} \ No newline at end of file diff --git a/utbot-framework/src/test/kotlin/org/utbot/examples/objects/HiddenFieldExampleTest.kt b/utbot-framework/src/test/kotlin/org/utbot/examples/objects/HiddenFieldExampleTest.kt index 70664a6359..d316d2a68d 100644 --- a/utbot-framework/src/test/kotlin/org/utbot/examples/objects/HiddenFieldExampleTest.kt +++ b/utbot-framework/src/test/kotlin/org/utbot/examples/objects/HiddenFieldExampleTest.kt @@ -3,12 +3,10 @@ package org.utbot.examples.objects import org.utbot.examples.UtValueTestCaseChecker import org.utbot.examples.DoNotCalculate import org.utbot.examples.eq -import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test internal class HiddenFieldExampleTest : UtValueTestCaseChecker(testClass = HiddenFieldExample::class) { @Test - // Engine creates HiddenFieldSuccClass instead of HiddenFieldSuperClass, feels wrong field and matchers fail fun testCheckHiddenField() { check( HiddenFieldExample::checkHiddenField, @@ -22,18 +20,18 @@ internal class HiddenFieldExampleTest : UtValueTestCaseChecker(testClass = Hidde } @Test - @Disabled("SAT-315 Engine cannot work with hidden fields") - // Engine translates calls to super.b as calls to succ.b fun testCheckSuccField() { - check( - HiddenFieldExample::checkSuccField, - eq(5), - { o, _ -> o == null }, - { o, r -> o.a == 1 && r == 1 }, - { o, r -> o.a != 1 && o.b == 2.0 && r == 2 }, - { o, r -> o.a != 1 && o.b != 2.0 && (o as HiddenFieldSuperClass).b == 3 && r == 3 }, - { o, r -> o.a != 1 && o.b != 2.0 && (o as HiddenFieldSuperClass).b != 3 && r == 4 }, - coverage = DoNotCalculate - ) + // TODO: currently, codegen can't handle tests with field hiding (see #646) + withEnabledTestingCodeGeneration(testCodeGeneration = false) { + check( + HiddenFieldExample::checkSuccField, + eq(5), + { o, _ -> o == null }, + { o, r -> o.a == 1 && r == 1 }, + { o, r -> o.a != 1 && o.b == 2.0 && r == 2 }, + { o, r -> o.a != 1 && o.b != 2.0 && (o as HiddenFieldSuperClass).b == 3 && r == 3 }, + { o, r -> o.a != 1 && o.b != 2.0 && (o as HiddenFieldSuperClass).b != 3 && r == 4 }, + ) + } } } \ No newline at end of file diff --git a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt index a7ec3e5780..f4aef6ead6 100644 --- a/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt +++ b/utbot-instrumentation-tests/src/test/kotlin/org/utbot/examples/et/TestStaticsUsage.kt @@ -3,7 +3,7 @@ package org.utbot.examples.et import org.utbot.examples.objects.ObjectWithStaticFieldsClass import org.utbot.examples.objects.ObjectWithStaticFieldsExample import org.utbot.framework.plugin.api.util.UtContext -import org.utbot.framework.plugin.api.util.field +import org.utbot.framework.plugin.api.util.jField import org.utbot.instrumentation.execute import org.utbot.instrumentation.instrumentation.et.ExecutionTraceInstrumentation import org.utbot.instrumentation.withInstrumentation @@ -39,7 +39,7 @@ class StaticsUsageDetectionTest { classInstance.x = 200 classInstance.y = 200 val result = it.execute(ObjectWithStaticFieldsExample::setStaticField, arrayOf(instance, classInstance)) - assertEquals(ObjectWithStaticFieldsClass::staticValue.javaField, result.usedStatics.single().field) + assertEquals(ObjectWithStaticFieldsClass::staticValue.javaField, result.usedStatics.single().jField) } } diff --git a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt index 0d7c785153..b4ea56bab0 100644 --- a/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt +++ b/utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/InvokeWithStaticsInstrumentation.kt @@ -1,7 +1,7 @@ package org.utbot.instrumentation.instrumentation import org.utbot.common.withAccessibility -import org.utbot.framework.plugin.api.util.field +import org.utbot.framework.plugin.api.util.jField import org.utbot.instrumentation.util.StaticEnvironment import java.lang.reflect.Field import java.lang.reflect.Modifier @@ -46,7 +46,7 @@ class InvokeWithStaticsInstrumentation : Instrumentation> { private fun setStaticFields(staticEnvironment: StaticEnvironment?) { staticEnvironment?.run { listOfFields.forEach { (fieldId, value) -> - fieldId.field.run { + fieldId.jField.run { withAccessibility { set(null, value) } diff --git a/utbot-sample/src/main/java/org/utbot/examples/objects/HiddenFieldAccessModifiersExample.java b/utbot-sample/src/main/java/org/utbot/examples/objects/HiddenFieldAccessModifiersExample.java new file mode 100644 index 0000000000..16cf7f50b9 --- /dev/null +++ b/utbot-sample/src/main/java/org/utbot/examples/objects/HiddenFieldAccessModifiersExample.java @@ -0,0 +1,7 @@ +package org.utbot.examples.objects; + +public class HiddenFieldAccessModifiersExample { + public boolean checkSuperFieldEqualsOne(HiddenFieldAccessModifiersSucc b) { + return b.getF() == 1; + } +} diff --git a/utbot-sample/src/main/java/org/utbot/examples/objects/HiddenFieldAccessModifiersSucc.java b/utbot-sample/src/main/java/org/utbot/examples/objects/HiddenFieldAccessModifiersSucc.java new file mode 100644 index 0000000000..ba200f176f --- /dev/null +++ b/utbot-sample/src/main/java/org/utbot/examples/objects/HiddenFieldAccessModifiersSucc.java @@ -0,0 +1,5 @@ +package org.utbot.examples.objects; + +public class HiddenFieldAccessModifiersSucc extends HiddenFieldAccessModifiersSuper { + private int f; +} diff --git a/utbot-sample/src/main/java/org/utbot/examples/objects/HiddenFieldAccessModifiersSuper.java b/utbot-sample/src/main/java/org/utbot/examples/objects/HiddenFieldAccessModifiersSuper.java new file mode 100644 index 0000000000..1d819d711d --- /dev/null +++ b/utbot-sample/src/main/java/org/utbot/examples/objects/HiddenFieldAccessModifiersSuper.java @@ -0,0 +1,11 @@ +package org.utbot.examples.objects; + +public class HiddenFieldAccessModifiersSuper { + public int f; + public int getF() { + return this.f; + } + public void setF(int val) { + this.f = val; + } +}