Skip to content

Commit e345e30

Browse files
authored
Fixed collecting base and overridden methods in ambiguous methods (#1647)
1 parent 43042b4 commit e345e30

File tree

2 files changed

+82
-24
lines changed

2 files changed

+82
-24
lines changed

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/services/access/CgCallableAccessManager.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,11 @@ internal class CgCallableAccessManagerImpl(val context: CgContext) : CgCallableA
494494
isAccessibleFrom(testClassPackageName) && !classId.isAbstract && args canBeArgsOf this
495495

496496
private fun List<CgExpression>.guardedForDirectCallOf(executable: ExecutableId): List<CgExpression> {
497+
if (executable is BuiltinMethodId) {
498+
// We assume that we do not have ambiguous overloads for builtin methods
499+
return this
500+
}
501+
497502
val ambiguousOverloads = executable.classId
498503
.getAmbiguousOverloadsOf(executable)
499504
.filterNot { it == executable }

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/tree/ConstructorUtils.kt

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,24 @@
11
package org.utbot.framework.codegen.tree
22

3+
import kotlinx.collections.immutable.PersistentList
4+
import kotlinx.collections.immutable.PersistentSet
35
import org.utbot.framework.codegen.domain.RegularImport
46
import org.utbot.framework.codegen.domain.StaticImport
7+
import org.utbot.framework.codegen.domain.builtin.setArrayElement
58
import org.utbot.framework.codegen.domain.context.CgContextOwner
9+
import org.utbot.framework.codegen.domain.models.CgAllocateInitializedArray
10+
import org.utbot.framework.codegen.domain.models.CgArrayInitializer
611
import org.utbot.framework.codegen.domain.models.CgClassId
712
import org.utbot.framework.codegen.domain.models.CgExpression
813
import org.utbot.framework.codegen.domain.models.CgTypeCast
914
import org.utbot.framework.codegen.domain.models.CgValue
1015
import org.utbot.framework.codegen.domain.models.CgVariable
16+
import org.utbot.framework.codegen.services.access.CgCallableAccessManager
17+
import org.utbot.framework.codegen.util.at
1118
import org.utbot.framework.codegen.util.isAccessibleFrom
1219
import org.utbot.framework.fields.ArrayElementAccess
1320
import org.utbot.framework.fields.FieldAccess
1421
import org.utbot.framework.fields.FieldPath
15-
import org.utbot.framework.plugin.api.util.booleanClassId
16-
import org.utbot.framework.plugin.api.util.byteClassId
17-
import org.utbot.framework.plugin.api.util.charClassId
18-
import org.utbot.framework.plugin.api.util.doubleClassId
19-
import org.utbot.framework.plugin.api.util.enclosingClass
20-
import org.utbot.framework.plugin.api.util.executable
21-
import org.utbot.framework.plugin.api.util.floatClassId
22-
import org.utbot.framework.plugin.api.util.id
23-
import org.utbot.framework.plugin.api.util.intClassId
24-
import org.utbot.framework.plugin.api.util.isRefType
25-
import org.utbot.framework.plugin.api.util.isSubtypeOf
26-
import org.utbot.framework.plugin.api.util.longClassId
27-
import org.utbot.framework.plugin.api.util.shortClassId
28-
import org.utbot.framework.plugin.api.util.underlyingType
29-
import kotlinx.collections.immutable.PersistentList
30-
import kotlinx.collections.immutable.PersistentSet
31-
import org.utbot.framework.codegen.domain.builtin.setArrayElement
32-
import org.utbot.framework.codegen.domain.models.CgAllocateInitializedArray
33-
import org.utbot.framework.codegen.domain.models.CgArrayInitializer
34-
import org.utbot.framework.codegen.services.access.CgCallableAccessManager
35-
import org.utbot.framework.codegen.util.at
3622
import org.utbot.framework.plugin.api.BuiltinClassId
3723
import org.utbot.framework.plugin.api.BuiltinMethodId
3824
import org.utbot.framework.plugin.api.ClassId
@@ -45,13 +31,32 @@ import org.utbot.framework.plugin.api.UtModel
4531
import org.utbot.framework.plugin.api.UtNullModel
4632
import org.utbot.framework.plugin.api.UtPrimitiveModel
4733
import org.utbot.framework.plugin.api.WildcardTypeParameter
48-
import org.utbot.framework.plugin.api.util.isStatic
4934
import org.utbot.framework.plugin.api.util.arrayLikeName
35+
import org.utbot.framework.plugin.api.util.booleanClassId
5036
import org.utbot.framework.plugin.api.util.builtinStaticMethodId
37+
import org.utbot.framework.plugin.api.util.byteClassId
38+
import org.utbot.framework.plugin.api.util.charClassId
5139
import org.utbot.framework.plugin.api.util.denotableType
40+
import org.utbot.framework.plugin.api.util.doubleClassId
41+
import org.utbot.framework.plugin.api.util.enclosingClass
42+
import org.utbot.framework.plugin.api.util.executable
43+
import org.utbot.framework.plugin.api.util.executableId
44+
import org.utbot.framework.plugin.api.util.floatClassId
45+
import org.utbot.framework.plugin.api.util.id
46+
import org.utbot.framework.plugin.api.util.intClassId
47+
import org.utbot.framework.plugin.api.util.isRefType
48+
import org.utbot.framework.plugin.api.util.isStatic
49+
import org.utbot.framework.plugin.api.util.isSubtypeOf
50+
import org.utbot.framework.plugin.api.util.jClass
51+
import org.utbot.framework.plugin.api.util.longClassId
5252
import org.utbot.framework.plugin.api.util.methodId
5353
import org.utbot.framework.plugin.api.util.objectArrayClassId
5454
import org.utbot.framework.plugin.api.util.objectClassId
55+
import org.utbot.framework.plugin.api.util.shortClassId
56+
import org.utbot.framework.plugin.api.util.signature
57+
import org.utbot.framework.plugin.api.util.underlyingType
58+
import java.lang.reflect.Method
59+
import java.lang.reflect.Modifier
5560

5661
data class EnvironmentFieldStateCache(
5762
val thisInstance: FieldStateCache,
@@ -335,14 +340,62 @@ internal fun Class<*>.overridesEquals(): Boolean =
335340
else -> declaredMethods.any { it.name == "equals" && it.parameterTypes.contentEquals(arrayOf(Any::class.java)) }
336341
}
337342

343+
/**
344+
* Returns all methods of [this] class (including inherited), except base methods (i.e., if any method is overridden,
345+
* only the latest overriding will be included).
346+
* NOTE: for the reference [see also](https://stackoverflow.com/a/28408148)
347+
*/
348+
private fun Class<*>.allMethodsWithoutBaseMethods(): Set<Method> {
349+
val collectedMethods = mutableSetOf<Method>(*methods)
350+
val types = collectedMethods.map { it.signature }.associateWithTo(mutableMapOf()) { mutableSetOf<Package>() }
351+
val access = Modifier.PUBLIC or Modifier.PROTECTED or Modifier.PRIVATE
352+
353+
var currentClass: Class<*>? = this
354+
while (currentClass != null) {
355+
for (method in currentClass.declaredMethods) {
356+
val modifiers = method.modifiers
357+
358+
if (!Modifier.isStatic(modifiers)) {
359+
when (modifiers and access) {
360+
Modifier.PUBLIC -> continue
361+
Modifier.PROTECTED -> {
362+
if (types.putIfAbsent(method.signature, mutableSetOf()) != null) {
363+
continue
364+
}
365+
}
366+
Modifier.PRIVATE -> {}
367+
else -> { // package-private
368+
val pkg = types.computeIfAbsent(method.signature) { mutableSetOf() }
369+
370+
if (pkg.isNotEmpty() && pkg.add(currentClass.getPackage())) {
371+
break
372+
} else {
373+
continue
374+
}
375+
}
376+
}
377+
}
378+
379+
collectedMethods += method
380+
}
381+
382+
currentClass = currentClass.superclass
383+
}
384+
385+
return collectedMethods
386+
}
387+
338388
// NOTE: this function does not consider executable return type because it is not important in our case
339389
internal fun ClassId.getAmbiguousOverloadsOf(executableId: ExecutableId): Sequence<ExecutableId> {
340390
val allExecutables = when (executableId) {
341-
is MethodId -> allMethods
391+
is MethodId -> {
392+
// For method we should check all overloadings and inherited methods, but do not consider base methods
393+
// in case of overriding (for example, for ArrayList#add we should not take List#add and AbstractCollection#add)
394+
executableId.classId.jClass.allMethodsWithoutBaseMethods().map { it.executableId }.asSequence()
395+
}
342396
is ConstructorId -> allConstructors
343397
}
344398

345-
// We should take here not only declared methods but also inherited
346399
return allExecutables.filter {
347400
it.name == executableId.name && it.parameters.size == executableId.executable.parameters.size
348401
}

0 commit comments

Comments
 (0)