From 32a33946e2214b5f546f9d382a281a11022da437 Mon Sep 17 00:00:00 2001 From: Egor Kulikov Date: Fri, 30 Sep 2022 16:40:12 +0300 Subject: [PATCH] Additional corrections on a call --- .../UtBotFieldModificatorsTest.kt | 2 +- .../assemble/AssembleModelGenerator.kt | 29 ++++++++------ .../codegen/model/util/FieldIdUtil.kt | 10 ++--- .../modifications/DirectAccessorsAnalyzer.kt | 9 +++-- .../UtBotFieldsModificatorsSearcher.kt | 38 +------------------ 5 files changed, 28 insertions(+), 60 deletions(-) diff --git a/utbot-framework-test/src/test/kotlin/org/utbot/framework/modificators/UtBotFieldModificatorsTest.kt b/utbot-framework-test/src/test/kotlin/org/utbot/framework/modificators/UtBotFieldModificatorsTest.kt index 5d5bc987c6..1b8eedaa93 100644 --- a/utbot-framework-test/src/test/kotlin/org/utbot/framework/modificators/UtBotFieldModificatorsTest.kt +++ b/utbot-framework-test/src/test/kotlin/org/utbot/framework/modificators/UtBotFieldModificatorsTest.kt @@ -192,7 +192,7 @@ internal class UtBotFieldModificatorsTest { //We use sorting here to make comparing with sorted in advance expected collections easier private fun runFieldModificatorsSearch(analysisMode: AnalysisMode) = - fieldsModificatorsSearcher.findModificators(analysisMode, null) + fieldsModificatorsSearcher.findModificators(analysisMode) .map { (key, value) -> val modificatorNames = value.filterNot { it.name.startsWith("direct_set_") }.map { it.name } key.name to modificatorNames.toSortedSet() diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt index 0d9f5d7f4a..7c6366d4ea 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/assemble/AssembleModelGenerator.kt @@ -36,6 +36,7 @@ import org.utbot.framework.plugin.api.hasDefaultValue import org.utbot.framework.plugin.api.isMockModel import org.utbot.framework.plugin.api.util.defaultValueModel import org.utbot.framework.plugin.api.util.executableId +import org.utbot.framework.plugin.api.util.isSubtypeOf import org.utbot.framework.plugin.api.util.jClass import org.utbot.framework.util.nextModelName import java.lang.reflect.Constructor @@ -43,13 +44,13 @@ import java.util.IdentityHashMap /** * Creates [UtAssembleModel] from any [UtModel] or it's inner models if possible - * during generation test for [packageName]. +tmp * during generation test for [basePackageName]. * * Needs utContext be set and Soot be initialized. * * Note: Caches class related information, can be reused if classes don't change. */ -class AssembleModelGenerator(private val packageName: String) { +class AssembleModelGenerator(private val basePackageName: String) { //Instantiated models are stored to avoid cyclic references during reference graph analysis private val instantiatedModels: IdentityHashMap = @@ -100,8 +101,7 @@ class AssembleModelGenerator(private val packageName: String) { * Note: Two identity equal [UtModel]s are represented by one instance model. */ fun createAssembleModels(models: List): IdentityHashMap { - val allModelsAreLocatedInPackage = models.all { it.classId.packageName.startsWith(packageName)} - if (!UtSettings.useAssembleModelGenerator || !allModelsAreLocatedInPackage) { + if (!UtSettings.useAssembleModelGenerator) { return IdentityHashMap().apply { models.forEach { put(it, it) } } } @@ -172,7 +172,7 @@ class AssembleModelGenerator(private val packageName: String) { private fun assembleModel(utModel: UtModel): UtModel { val collectedCallChain = callChain.toMutableList() - // we cannot create an assemble model for an anonymous class instance + // We cannot create an assemble model for an anonymous class instance if (utModel.classId.isAnonymous) { return utModel } @@ -257,7 +257,7 @@ class AssembleModelGenerator(private val packageName: String) { if (fieldId.isFinal) { throw AssembleException("Final field $fieldId can't be set in an object of the class $classId") } - if (!fieldId.type.isAccessibleFrom(packageName)) { + if (!fieldId.type.isAccessibleFrom(basePackageName)) { throw AssembleException( "Field $fieldId can't be set in an object of the class $classId because its type is inaccessible" ) @@ -399,10 +399,10 @@ class AssembleModelGenerator(private val packageName: String) { } private val ClassId.isVisible : Boolean - get() = this.isPublic || !this.isPrivate && this.packageName.startsWith(this@AssembleModelGenerator.packageName) + get() = this.isPublic || !this.isPrivate && this.packageName.startsWith(basePackageName) private val Constructor<*>.isVisible : Boolean - get() = this.isPublic || !this.isPrivate && this.declaringClass.packageName.startsWith(packageName) + get() = this.isPublic || !this.isPrivate && this.declaringClass.packageName.startsWith(basePackageName) /** * Creates setter or direct setter call to set a field. @@ -441,7 +441,7 @@ class AssembleModelGenerator(private val packageName: String) { * Finds setters and direct accessors for fields of particular class. */ private fun findSettersAndDirectAccessors(classId: ClassId): Map { - val allModificatorsOfClass = modificatorsSearcher.findModificators(SettersAndDirectAccessors, classId) + val allModificatorsOfClass = modificatorsSearcher.findModificators(SettersAndDirectAccessors) return allModificatorsOfClass .mapNotNull { (fieldId, possibleModificators) -> @@ -457,9 +457,12 @@ class AssembleModelGenerator(private val packageName: String) { */ private fun chooseModificator( fieldId: FieldId, - settersAndDirectAccessors: Set + settersAndDirectAccessors: Set, ): StatementId? { - val directAccessors = settersAndDirectAccessors.filterIsInstance() + val directAccessors = settersAndDirectAccessors + .filterIsInstance() + .filter {it.fieldId.isAccessibleFrom(basePackageName) } + if (directAccessors.any()) { return directAccessors.singleOrNull() ?: throw AssembleException( @@ -468,7 +471,9 @@ class AssembleModelGenerator(private val packageName: String) { } if (settersAndDirectAccessors.any()) { - return settersAndDirectAccessors.singleOrNull() + return settersAndDirectAccessors + .filterIsInstance() + .singleOrNull { it.isAccessibleFrom(basePackageName) } ?: throw AssembleException( "Field $fieldId has more than one setter: ${settersAndDirectAccessors.joinToString(" ")}" ) diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/util/FieldIdUtil.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/util/FieldIdUtil.kt index 29309d46c6..8df76d3d39 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/util/FieldIdUtil.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/model/util/FieldIdUtil.kt @@ -13,9 +13,7 @@ import org.utbot.framework.plugin.api.util.voidClassId * * @param context context in which code is generated (it is needed because the method needs to know package and language) */ -// TODO: change parameter from packageName: String to context: CgContext in ClassId.isAccessibleFrom and ExecutableId.isAccessibleFrom ? -private fun FieldId.isAccessibleFrom(context: CgContext): Boolean { - val packageName = context.testClassPackageName +fun FieldId.isAccessibleFrom(packageName: String): Boolean { val isClassAccessible = declaringClass.isAccessibleFrom(packageName) val isAccessibleByVisibility = isPublic || (declaringClass.packageName == packageName && (isPackagePrivate || isProtected)) val isAccessibleFromPackageByModifiers = isAccessibleByVisibility && !isSynthetic @@ -36,7 +34,7 @@ internal infix fun FieldId.canBeReadFrom(context: CgContext): Boolean { return true } - return isAccessibleFrom(context) + return isAccessibleFrom(context.testClassPackageName) } private fun FieldId.canBeSetViaSetterFrom(context: CgContext): Boolean = @@ -49,12 +47,12 @@ internal fun FieldId.canBeSetFrom(context: CgContext): Boolean { if (context.codegenLanguage == CodegenLanguage.KOTLIN) { // Kotlin will allow direct write access if both getter and setter is defined // !isAccessibleFrom(context) is important here because above rule applies to final fields only if they are not accessible in Java terms - if (!isAccessibleFrom(context) && !isStatic && canBeReadViaGetterFrom(context) && canBeSetViaSetterFrom(context)) { + if (!isAccessibleFrom(context.testClassPackageName) && !isStatic && canBeReadViaGetterFrom(context) && canBeSetViaSetterFrom(context)) { return true } } - return isAccessibleFrom(context) && !isFinal + return isAccessibleFrom(context.testClassPackageName) && !isFinal } /** diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/DirectAccessorsAnalyzer.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/DirectAccessorsAnalyzer.kt index dcc27e2835..2db28db575 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/DirectAccessorsAnalyzer.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/DirectAccessorsAnalyzer.kt @@ -17,21 +17,22 @@ class DirectAccessorsAnalyzer { */ fun collectDirectAccesses(classIds: Set): Set = classIds - .flatMap { classId -> collectFieldsInPackage(classId) } + .flatMap { classId -> collectFields(classId) } .map { fieldId -> DirectFieldAccessId(fieldId.declaringClass, directSetterName(fieldId), fieldId) } .toSet() /** - * Collect all fields with different non-private modifiers from class [classId]. + * Collect all fields with different non-private modifiers + * from class [classId] or it's base classes. */ - private fun collectFieldsInPackage(classId: ClassId): Set { + private fun collectFields(classId: ClassId): Set { var clazz = classId.jClass val fieldIds = mutableSetOf() fieldIds += clazz.declaredFields.filterNot { Modifier.isPrivate(it.modifiers) } while (clazz.superclass != null) { clazz = clazz.superclass - fieldIds += clazz.declaredFields.filter { Modifier.isPublic(it.modifiers) || Modifier.isProtected(it.modifiers) } + fieldIds += clazz.declaredFields.filterNot { Modifier.isPrivate(it.modifiers) } } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/UtBotFieldsModificatorsSearcher.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/UtBotFieldsModificatorsSearcher.kt index b0fb77345b..24acf93f5a 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/UtBotFieldsModificatorsSearcher.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/modifications/UtBotFieldsModificatorsSearcher.kt @@ -14,43 +14,7 @@ class UtBotFieldsModificatorsSearcher { fun delete(classIds: Set) = statementsStorage.delete(classIds) - /** - * Finds field modificators. - * - * @param analysisMode represents which type of modificators (e.g. setters) are considered. - * @param methodUnderTest describes an analyzed method an it's location. - */ - fun findModificators(analysisMode: AnalysisMode, classUnderTest: ClassId? = null): Map> { - val modificators = findModificators(analysisMode) - - if (classUnderTest == null) { - return modificators - } - - val filteredModifications = mutableMapOf>() - for ((fieldId, statements) in modificators) { - val filteredStmts = statements.filter { stmt -> fieldId.isAccessibleBy(stmt, classUnderTest!!) } - filteredModifications[fieldId] = filteredStmts.toSet() - } - - return filteredModifications - } - - /** - * Verifies that this field is accessible with [statementId] from the location of [methodUnderTest]. - */ - private fun FieldId.isAccessibleBy(statementId: StatementId, classUnderTest: ClassId): Boolean { - val basePackageName = classUnderTest.packageName - val classPackageName = statementId.classId.packageName - - if (this.isPublic) return true - if (this.isProtected) return classPackageName == basePackageName || statementId.classId.isSubtypeOf(classUnderTest) - if (this.isPackagePrivate) return classPackageName == basePackageName - if (this.isPrivate) return classUnderTest == statementId.classId - return error("Unexpected modifier for field $this") - } - - private fun findModificators(analysisMode: AnalysisMode): Map> { + fun findModificators(analysisMode: AnalysisMode): Map> { statementsStorage.updateCaches() return findModificatorsInCache(analysisMode) }