diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/access/CgCallableAccessManager.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/access/CgCallableAccessManager.kt index 898cb0037b..c30cc97bb4 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/access/CgCallableAccessManager.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/access/CgCallableAccessManager.kt @@ -494,6 +494,11 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA isAccessibleFrom(testClassPackageName) && !classId.isAbstract && args canBeArgsOf this private fun List.guardedForDirectCallOf(executable: ExecutableId): List { + if (executable is BuiltinMethodId) { + // We assume that we do not have ambiguous overloads for builtin methods + return this + } + val ambiguousOverloads = executable.classId .getAmbiguousOverloadsOf(executable) .filterNot { it == executable } diff --git a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/ConstructorUtils.kt b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/ConstructorUtils.kt index f9007a3200..0b7ec64d34 100644 --- a/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/ConstructorUtils.kt +++ b/utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/ConstructorUtils.kt @@ -1,38 +1,24 @@ package org.utbot.framework.codegen.tree +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.PersistentSet import org.utbot.framework.codegen.domain.RegularImport import org.utbot.framework.codegen.domain.StaticImport +import org.utbot.framework.codegen.domain.builtin.setArrayElement import org.utbot.framework.codegen.domain.context.CgContextOwner +import org.utbot.framework.codegen.domain.models.CgAllocateInitializedArray +import org.utbot.framework.codegen.domain.models.CgArrayInitializer import org.utbot.framework.codegen.domain.models.CgClassId import org.utbot.framework.codegen.domain.models.CgExpression import org.utbot.framework.codegen.domain.models.CgTypeCast import org.utbot.framework.codegen.domain.models.CgValue import org.utbot.framework.codegen.domain.models.CgVariable +import org.utbot.framework.codegen.services.access.CgCallableAccessManager +import org.utbot.framework.codegen.util.at import org.utbot.framework.codegen.util.isAccessibleFrom import org.utbot.framework.fields.ArrayElementAccess import org.utbot.framework.fields.FieldAccess import org.utbot.framework.fields.FieldPath -import org.utbot.framework.plugin.api.util.booleanClassId -import org.utbot.framework.plugin.api.util.byteClassId -import org.utbot.framework.plugin.api.util.charClassId -import org.utbot.framework.plugin.api.util.doubleClassId -import org.utbot.framework.plugin.api.util.enclosingClass -import org.utbot.framework.plugin.api.util.executable -import org.utbot.framework.plugin.api.util.floatClassId -import org.utbot.framework.plugin.api.util.id -import org.utbot.framework.plugin.api.util.intClassId -import org.utbot.framework.plugin.api.util.isRefType -import org.utbot.framework.plugin.api.util.isSubtypeOf -import org.utbot.framework.plugin.api.util.longClassId -import org.utbot.framework.plugin.api.util.shortClassId -import org.utbot.framework.plugin.api.util.underlyingType -import kotlinx.collections.immutable.PersistentList -import kotlinx.collections.immutable.PersistentSet -import org.utbot.framework.codegen.domain.builtin.setArrayElement -import org.utbot.framework.codegen.domain.models.CgAllocateInitializedArray -import org.utbot.framework.codegen.domain.models.CgArrayInitializer -import org.utbot.framework.codegen.services.access.CgCallableAccessManager -import org.utbot.framework.codegen.util.at import org.utbot.framework.plugin.api.BuiltinClassId import org.utbot.framework.plugin.api.BuiltinMethodId import org.utbot.framework.plugin.api.ClassId @@ -45,13 +31,32 @@ import org.utbot.framework.plugin.api.UtModel import org.utbot.framework.plugin.api.UtNullModel import org.utbot.framework.plugin.api.UtPrimitiveModel import org.utbot.framework.plugin.api.WildcardTypeParameter -import org.utbot.framework.plugin.api.util.isStatic import org.utbot.framework.plugin.api.util.arrayLikeName +import org.utbot.framework.plugin.api.util.booleanClassId import org.utbot.framework.plugin.api.util.builtinStaticMethodId +import org.utbot.framework.plugin.api.util.byteClassId +import org.utbot.framework.plugin.api.util.charClassId import org.utbot.framework.plugin.api.util.denotableType +import org.utbot.framework.plugin.api.util.doubleClassId +import org.utbot.framework.plugin.api.util.enclosingClass +import org.utbot.framework.plugin.api.util.executable +import org.utbot.framework.plugin.api.util.executableId +import org.utbot.framework.plugin.api.util.floatClassId +import org.utbot.framework.plugin.api.util.id +import org.utbot.framework.plugin.api.util.intClassId +import org.utbot.framework.plugin.api.util.isRefType +import org.utbot.framework.plugin.api.util.isStatic +import org.utbot.framework.plugin.api.util.isSubtypeOf +import org.utbot.framework.plugin.api.util.jClass +import org.utbot.framework.plugin.api.util.longClassId import org.utbot.framework.plugin.api.util.methodId import org.utbot.framework.plugin.api.util.objectArrayClassId import org.utbot.framework.plugin.api.util.objectClassId +import org.utbot.framework.plugin.api.util.shortClassId +import org.utbot.framework.plugin.api.util.signature +import org.utbot.framework.plugin.api.util.underlyingType +import java.lang.reflect.Method +import java.lang.reflect.Modifier data class EnvironmentFieldStateCache( val thisInstance: FieldStateCache, @@ -335,14 +340,62 @@ internal fun Class<*>.overridesEquals(): Boolean = else -> declaredMethods.any { it.name == "equals" && it.parameterTypes.contentEquals(arrayOf(Any::class.java)) } } +/** + * Returns all methods of [this] class (including inherited), except base methods (i.e., if any method is overridden, + * only the latest overriding will be included). + * NOTE: for the reference [see also](https://stackoverflow.com/a/28408148) + */ +private fun Class<*>.allMethodsWithoutBaseMethods(): Set { + val collectedMethods = mutableSetOf(*methods) + val types = collectedMethods.map { it.signature }.associateWithTo(mutableMapOf()) { mutableSetOf() } + val access = Modifier.PUBLIC or Modifier.PROTECTED or Modifier.PRIVATE + + var currentClass: Class<*>? = this + while (currentClass != null) { + for (method in currentClass.declaredMethods) { + val modifiers = method.modifiers + + if (!Modifier.isStatic(modifiers)) { + when (modifiers and access) { + Modifier.PUBLIC -> continue + Modifier.PROTECTED -> { + if (types.putIfAbsent(method.signature, mutableSetOf()) != null) { + continue + } + } + Modifier.PRIVATE -> {} + else -> { // package-private + val pkg = types.computeIfAbsent(method.signature) { mutableSetOf() } + + if (pkg.isNotEmpty() && pkg.add(currentClass.getPackage())) { + break + } else { + continue + } + } + } + } + + collectedMethods += method + } + + currentClass = currentClass.superclass + } + + return collectedMethods +} + // NOTE: this function does not consider executable return type because it is not important in our case internal fun ClassId.getAmbiguousOverloadsOf(executableId: ExecutableId): Sequence { val allExecutables = when (executableId) { - is MethodId -> allMethods + is MethodId -> { + // For method we should check all overloadings and inherited methods, but do not consider base methods + // in case of overriding (for example, for ArrayList#add we should not take List#add and AbstractCollection#add) + executableId.classId.jClass.allMethodsWithoutBaseMethods().map { it.executableId }.asSequence() + } is ConstructorId -> allConstructors } - // We should take here not only declared methods but also inherited return allExecutables.filter { it.name == executableId.name && it.parameters.size == executableId.executable.parameters.size }