Skip to content

Commit bf2e0e7

Browse files
committed
Squashed commit of the following:
commit 31fbc83 Author: Andrey Tarbeev <[email protected]> Date: Fri Jul 8 10:50:52 2022 +0300 Minimize exceptions in signature (#418) * Minimize exceptions in test methods signatures commit 63eb9b0 Author: Yury Kamenev <[email protected]> Date: Thu Jul 7 15:13:45 2022 +0300 Removed always used coverage-based minimization strategy (#450) commit fe0f7f8 Author: Yury Kamenev <[email protected]> Date: Thu Jul 7 14:19:53 2022 +0300 Disabled NPE checks for non-public library fields by default (#353) commit d1b51fe Author: Yury Kamenev <[email protected]> Date: Thu Jul 7 13:44:46 2022 +0300 Fixed NPE for processing static field as first statement in MUT (#433) commit acc2fff Author: Nikita Vlaev <[email protected]> Date: Wed Jul 6 15:37:28 2022 +0300 Added ForceStaticMockListener to run "configure mockito-inline" action. Refactored url listener in notifications. commit 80c2328 Author: Nikita Stroganov <[email protected]> Date: Thu Jul 7 11:21:13 2022 +0300 Support -P parameters in the utbot-gradle (#377) commit a92e289 Author: Sergey Pospelov <[email protected]> Date: Tue Jul 5 10:29:45 2022 +0300 Fix searching of modifiers field for JDK 8-17 commit 9a3acb6 Author: Amandel Pie <[email protected]> Date: Wed Jul 6 14:16:09 2022 +0300 Disabled clustering of tests generated by Fuzzer (#431) * Disabled clustering of tests generated by Fuzzer * Refactored the multiple calls commit c09568f Author: Vassiliy Kudryashov <[email protected]> Date: Wed Jul 6 10:21:52 2022 +0300 Existing test file without test class obstruct generation #160 (#425) commit 2ec8fb3 Author: Denis Fokin <[email protected]> Date: Tue Jul 5 16:52:42 2022 +0300 Better naming commit 68c66ef Author: Vassiliy Kudryashov <[email protected]> Date: Tue Jul 5 19:51:55 2022 +0300 SVG logo contains 'inaccurate' holes #330 (#411) commit 1d48789 Author: Dmitrii Timofeev <[email protected]> Date: Tue Jul 5 17:08:38 2022 +0300 Workaround: run concrete execution for invokedynamic commit 65d95c1 Author: Vassiliy Kudryashov <[email protected]> Date: Tue Jul 5 19:42:55 2022 +0300 Plugin fails with an exception if no SDK is configured for the test module #399 (#424) commit 6f9f2d8 Author: Maksim Pelevin <[email protected]> Date: Tue Jul 5 17:49:58 2022 +0300 Fix CNFE: kotlin.collections.ArrayDeque in ContestEstimator (#419) commit 67cc7d9 Author: Denis Fokin <[email protected]> Date: Tue Jul 5 11:58:40 2022 +0300 Put concrete executor jar in resources for contest estimator commit 63e2252 Author: Alena Lisevych <[email protected]> Date: Tue Jul 5 15:48:29 2022 +0300 Tooltips correction for #343 (#410) Co-authored-by: Alena Lisevych <> commit 8b3defa Author: Vassiliy Kudryashov <[email protected]> Date: Tue Jul 5 13:22:31 2022 +0300 Write access exception on test generating in Idea project with JDK 11 #350 (#409) commit c02883c Author: Amandel Pie <[email protected]> Date: Tue Jul 5 11:21:21 2022 +0300 Enables 40 tests for utbot-summary module (#389) * Repair testPow * Repaired ReturnExampleTest tests * Restored SummaryCycleTest.kt * Restored all the tests commit 65c07f8 Author: Victoria <[email protected]> Date: Tue Jul 5 09:51:44 2022 +0300 Update Dockerfile_java_cli (#396) commit 3b21112 Author: Alexey Menshutin <[email protected]> Date: Mon Jul 4 21:16:53 2022 +0300 ToString support for abstract collection using makeSymbolic #391 commit c2673df Author: Vassiliy Kudryashov <[email protected]> Date: Mon Jul 4 21:56:43 2022 +0300 IDE fatal error during tests generation #68 (#379) commit 43693fb Author: Nikita Vlaev <[email protected]> Date: Mon Jul 4 18:59:57 2022 +0300 Bring back test class generation (#403) commit 1c01193 Author: Yury Kamenev <[email protected]> Date: Mon Jul 4 20:24:03 2022 +0300 Added the wrapper for static methods of java.util.List (#400) commit a805f31 Author: Nikita Vlaev <[email protected]> Date: Fri Jul 1 20:16:28 2022 +0300 Add title pane with unsupported jdk notification (#373) commit 16c13fb Author: Dmitrii Timofeev <[email protected]> Date: Mon Jul 4 18:35:36 2022 +0300 Initiate concrete execution if a wrapper method is missing (#392) If a JVM class is overridden but a method is missing from the wrapper, the engine will discard the path and fall back to concrete execution instead of analysing the real JVM code graph. This approach fixes the problem with methods that have been introduced in newer JDKs. Now wrappers are mostly limited to Java 1.8 interfaces and fail to analyze methods like `String::isBlank` or `String::lines` when the code runs under JDK 11. Building graphs from the real JDK code fails because the wrapper does not have private fields that the original code uses. TODO: to allow symbolic analysis of the code, missing methods should be actually implemented in corresponding wrappers.
1 parent 1b52bdc commit bf2e0e7

File tree

70 files changed

+3360
-1580
lines changed

Some content is hidden

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

70 files changed

+3360
-1580
lines changed

docker/Dockerfile_java_cli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ RUN curl -H "Authorization: Bearer ${ACCESS_TOKEN}" \
2222
&& unzip "${JAVA_CLI_ZIP_NAME}" \
2323
&& rm "${JAVA_CLI_ZIP_NAME}"
2424

25-
ENV JAVA_CLI_PATH="$(find $pwd -type f -name "utbot-cli*")"
25+
ENV JAVA_CLI_PATH="$(find /usr/src -type f -name utbot-cli*)"
2626
RUN ln -s "${JAVA_CLI_PATH}" $pwd/utbot-cli.jar

docs/SpeculativeFieldNonNullability.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ most of generated branches would be `NPE` branches, while useful paths could be
1717

1818
Beyond that, in many cases the `null` value of a field can't be generated using the public API
1919
of the class. This is particularly true for final fields, especially in system classes.
20-
Automatically generated tests assign `null` values to fields in questions using reflection,
20+
it is also often true for non-public fields from standard library and third-party libraries (even setters often do not
21+
allow `null` values). Automatically generated tests assign `null` values to fields using reflection,
2122
but these tests may be uninformative as the corresponding `NPE` branches would never occur
2223
in the real code that limits itself to the public API.
2324

2425
## The solution
2526

2627
To discard irrelevant `NPE` branches, we can speculatively mark fields we as non-nullable even they
27-
do not have an explicit `@NotNull` annotation. In particular, we can use this approach to final
28+
do not have an explicit `@NotNull` annotation. In particular, we can use this approach to final and non-public
2829
fields of system classes, as they are usually correctly initialized and are not equal `null`.
2930

3031
At the same time, we can't always add the "not null" hard constraint for the field: it would break
@@ -38,18 +39,18 @@ no way to check whether the address corresponds to a final field, as the corresp
3839
of the global graph would refer to a local variable. The only place where we have the complete
3940
information about the field is this method.
4041

41-
We use the following approach. If the field is final and belongs to a system class,
42-
we mark it as a speculatively non-nullable in the memory
42+
We use the following approach. If the field belongs to a library class (according to `soot.SootClass.isLibraryClass`)
43+
and is final or non-public, we mark it as a speculatively non-nullable in the memory
4344
(see `org.utbot.engine.Memory.speculativelyNotNullAddresses`). During the NPE check
4445
we will add the `!isSpeculativelyNotNull(addr(field))` constraint
4546
to the `NPE` branch together with the usual `addr(field) == null` constraint.
4647

47-
For final fields, these two conditions can't be satisfied at the same time, as we speculatively
48-
mark final fields as non-nullable. As a result, the NPE branch would be discarded. If a field
49-
is not final, the condition is satisfiable, so the NPE branch would stay alive.
48+
For final/non-public fields, these two conditions can't be satisfied at the same time, as we speculatively
49+
mark such fields as non-nullable. As a result, the NPE branch would be discarded. If a field
50+
is public or not final, the condition is satisfiable, so the NPE branch would stay alive.
5051

51-
We limit this approach to the system classes only, because it is hard to speculatively assume
52-
something about non-nullability of final fields in the user code.
52+
We limit this approach to the library classes only, because it is hard to speculatively assume
53+
something about non-nullability of final/non-public fields in the user code.
5354

5455
The same approach can be extended for other cases where we want to speculatively consider some
5556
fields as non-nullable to prevent `NPE` branch generation.

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,15 @@ object Reflection {
1515
unsafe = f.get(null) as Unsafe
1616
}
1717

18-
private val modifiersField: Field = Field::class.java.getDeclaredField("modifiers")
18+
19+
// TODO: works on JDK 8-17. Doesn't work on JDK 18
20+
private val modifiersField: Field = run {
21+
val getDeclaredFields0 = Class::class.java.getDeclaredMethod("getDeclaredFields0", Boolean::class.java)
22+
getDeclaredFields0.isAccessible = true
23+
@Suppress("UNCHECKED_CAST")
24+
val fields = getDeclaredFields0.invoke(Field::class.java, false) as Array<Field>
25+
fields.first { it.name == "modifiers" }
26+
}
1927

2028
init {
2129
modifiersField.isAccessible = true
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package org.utbot.framework
2+
3+
import mu.KotlinLogging
4+
import org.utbot.common.PathUtil.toPath
5+
import java.io.IOException
6+
7+
private val logger = KotlinLogging.logger {}
8+
9+
private val defaultUserTrustedLibrariesPath: String = "${utbotHomePath}/trustedLibraries.txt"
10+
private const val userTrustedLibrariesKey: String = "utbot.settings.trusted.libraries.path"
11+
12+
object TrustedLibraries {
13+
/**
14+
* Always "trust" JDK.
15+
*/
16+
private val defaultTrustedLibraries: List<String> = listOf(
17+
"java",
18+
"sun",
19+
"javax",
20+
"com.sun",
21+
"org.omg",
22+
"org.xml",
23+
"org.w3c.dom",
24+
)
25+
26+
private val userTrustedLibraries: List<String>
27+
get() {
28+
val userTrustedLibrariesPath = System.getProperty(userTrustedLibrariesKey) ?: defaultUserTrustedLibrariesPath
29+
val userTrustedLibrariesFile = userTrustedLibrariesPath.toPath().toFile()
30+
31+
if (!userTrustedLibrariesFile.exists()) {
32+
return emptyList()
33+
}
34+
35+
return try {
36+
userTrustedLibrariesFile.readLines()
37+
} catch (e: IOException) {
38+
logger.info { e.message }
39+
40+
emptyList()
41+
}
42+
}
43+
44+
/**
45+
* Represents prefixes of packages for trusted libraries -
46+
* as the union of [defaultTrustedLibraries] and [userTrustedLibraries].
47+
*/
48+
val trustedLibraries: Set<String> by lazy { (defaultTrustedLibraries + userTrustedLibraries).toSet() }
49+
}

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

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@ import kotlin.reflect.KProperty
1010

1111
private val logger = KotlinLogging.logger {}
1212

13+
/**
14+
* Path to the utbot home folder.
15+
*/
16+
internal val utbotHomePath = "${System.getProperty("user.home")}/.utbot"
17+
1318
/**
1419
* Default path for properties file
1520
*/
16-
internal val defaultSettingsPath = "${System.getProperty("user.home")}/.utbot/settings.properties"
17-
internal const val defaultKeyForSettingsPath = "utbot.settings.path"
21+
private val defaultSettingsPath = "$utbotHomePath/settings.properties"
22+
private const val defaultKeyForSettingsPath = "utbot.settings.path"
1823

1924
internal class SettingDelegate<T>(val initializer: () -> T) {
2025
private var value = initializer()
@@ -176,13 +181,22 @@ object UtSettings {
176181
var enableMachineLearningModule by getBooleanProperty(true)
177182

178183
/**
179-
* Options below regulate which NullPointerExceptions check should be performed.
184+
* Options below regulate which [NullPointerException] check should be performed.
180185
*
181186
* Set an option in true if you want to perform NPE check in the corresponding situations, otherwise set false.
182187
*/
183188
var checkNpeInNestedMethods by getBooleanProperty(true)
184189
var checkNpeInNestedNotPrivateMethods by getBooleanProperty(false)
185-
var checkNpeForFinalFields by getBooleanProperty(false)
190+
191+
/**
192+
* This option determines whether we should generate [NullPointerException] checks for final or non-public fields
193+
* in non-application classes. Set by true, this option highly decreases test's readability in some cases
194+
* because of using reflection API for setting final/non-public fields in non-application classes.
195+
*
196+
* NOTE: default false value loses some executions with NPE in system classes, but often most of these executions
197+
* are not expected by user.
198+
*/
199+
var maximizeCoverageUsingReflection by getBooleanProperty(false)
186200

187201
/**
188202
* Activate or deactivate substituting static fields values set in static initializer

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,7 +1044,7 @@ enum class MockStrategyApi(
10441044
override val displayName: String,
10451045
override val description: String
10461046
) : CodeGenerationSettingItem {
1047-
NO_MOCKS("No mocks", "Do not use Mock frameworks at all"),
1047+
NO_MOCKS("No mocks", "Do not use mock frameworks at all"),
10481048
OTHER_PACKAGES(
10491049
"Other packages: $MOCKITO",
10501050
"Mock all classes outside the current package except system ones"
@@ -1105,7 +1105,7 @@ enum class MockFramework(
11051105

11061106
enum class CodegenLanguage(
11071107
override val displayName: String,
1108-
@Suppress("unused") override val description: String = "Generating unit tests in $displayName"
1108+
@Suppress("unused") override val description: String = "Generate unit tests in $displayName"
11091109
) : CodeGenerationSettingItem {
11101110
JAVA(displayName = "Java"),
11111111
KOTLIN(displayName = "Kotlin");

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ data class UtExecutionSuccess(val model: UtModel) : UtExecutionResult() {
1111

1212
sealed class UtExecutionFailure : UtExecutionResult() {
1313
abstract val exception: Throwable
14-
val isCheckedException get() = !(exception is RuntimeException || exception is Error)
1514
}
1615

1716
data class UtOverflowFailure(
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package org.utbot.framework.plugin.api.util
2+
3+
val Throwable.description
4+
get() = message?.replace('\n', '\t') ?: "<Throwable with empty message>"
5+
6+
val Throwable.isCheckedException
7+
get() = !(this is RuntimeException || this is Error)
8+
9+
val Class<*>.isCheckedException
10+
get() = !(RuntimeException::class.java.isAssignableFrom(this) || Error::class.java.isAssignableFrom(this))
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.utbot.engine.overrides.collections;
2+
3+
import org.utbot.api.annotation.UtClassMock;
4+
5+
import static org.utbot.api.mock.UtMock.makeSymbolic;
6+
7+
@UtClassMock(target = java.util.AbstractCollection.class, internalUsage = true)
8+
public abstract class AbstractCollection<E> implements java.util.Collection<E> {
9+
@Override
10+
public String toString() {
11+
return makeSymbolic();
12+
}
13+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package org.utbot.engine.overrides.collections;
2+
3+
import org.utbot.api.annotation.UtClassMock;
4+
5+
import java.util.Collection;
6+
7+
@UtClassMock(target = java.util.List.class, internalUsage = true)
8+
public interface List<E> extends java.util.List<E> {
9+
static <E> java.util.List<E> of() {
10+
return new UtArrayList<>();
11+
}
12+
13+
@SuppressWarnings("unchecked")
14+
static <E> java.util.List<E> of(E e1) {
15+
return new UtArrayList<>((E[]) new Object[]{e1});
16+
}
17+
18+
@SuppressWarnings("unchecked")
19+
static <E> java.util.List<E> of(E e1, E e2) {
20+
return new UtArrayList<>((E[]) new Object[]{e1, e2});
21+
}
22+
23+
@SuppressWarnings("unchecked")
24+
static <E> java.util.List<E> of(E e1, E e2, E e3) {
25+
return new UtArrayList<>((E[]) new Object[]{e1, e2, e3});
26+
}
27+
28+
@SuppressWarnings("unchecked")
29+
static <E> java.util.List<E> of(E e1, E e2, E e3, E e4) {
30+
return new UtArrayList<>((E[]) new Object[]{e1, e2, e3, e4});
31+
}
32+
33+
@SuppressWarnings("unchecked")
34+
static <E> java.util.List<E> of(E e1, E e2, E e3, E e4, E e5) {
35+
return new UtArrayList<>((E[]) new Object[]{e1, e2, e3, e4, e5});
36+
}
37+
38+
@SuppressWarnings("unchecked")
39+
static <E> java.util.List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
40+
return new UtArrayList<>((E[]) new Object[]{e1, e2, e3, e4, e5, e6});
41+
}
42+
43+
@SuppressWarnings("unchecked")
44+
static <E> java.util.List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
45+
return new UtArrayList<>((E[]) new Object[]{e1, e2, e3, e4, e5, e6, e7});
46+
}
47+
48+
@SuppressWarnings("unchecked")
49+
static <E> java.util.List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
50+
return new UtArrayList<>((E[]) new Object[]{e1, e2, e3, e4, e5, e6, e7, e8});
51+
}
52+
53+
@SuppressWarnings("unchecked")
54+
static <E> java.util.List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
55+
return new UtArrayList<>((E[]) new Object[]{e1, e2, e3, e4, e5, e6, e7, e8, e9});
56+
}
57+
58+
@SuppressWarnings("unchecked")
59+
static <E> java.util.List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
60+
return new UtArrayList<>((E[]) new Object[]{e1, e2, e3, e4, e5, e6, e7, e8, e9, e10});
61+
}
62+
63+
@SafeVarargs
64+
@SuppressWarnings("varargs")
65+
static <E> java.util.List<E> of(E... elements) {
66+
return new UtArrayList<>(elements);
67+
}
68+
69+
static <E> java.util.List<E> copyOf(Collection<? extends E> collection) {
70+
return new UtArrayList<>(collection);
71+
}
72+
}

utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtArrayList.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
import org.utbot.engine.overrides.stream.UtStream;
2020

2121
import static org.utbot.api.mock.UtMock.assume;
22+
import static org.utbot.api.mock.UtMock.assumeOrExecuteConcretely;
2223
import static org.utbot.engine.ResolverKt.MAX_LIST_SIZE;
2324
import static org.utbot.engine.overrides.UtOverrideMock.alreadyVisited;
24-
import static org.utbot.api.mock.UtMock.assumeOrExecuteConcretely;
2525
import static org.utbot.engine.overrides.UtOverrideMock.executeConcretely;
2626
import static org.utbot.engine.overrides.UtOverrideMock.parameter;
2727
import static org.utbot.engine.overrides.UtOverrideMock.visit;
@@ -63,6 +63,14 @@ public UtArrayList(Collection<? extends E> c) {
6363
addAll(c);
6464
}
6565

66+
public UtArrayList(E[] data) {
67+
visit(this);
68+
int length = data.length;
69+
elementData = new RangeModifiableUnlimitedArray<>();
70+
elementData.setRange(0, data, 0, length);
71+
elementData.end = length;
72+
}
73+
6674
/**
6775
* Precondition check is called only once by object,
6876
* if it was passed as parameter to method under test.

utbot-framework/src/main/java/org/utbot/engine/overrides/collections/UtHashMap.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
import org.jetbrains.annotations.Nullable;
1616

1717
import static org.utbot.api.mock.UtMock.assume;
18+
import static org.utbot.api.mock.UtMock.makeSymbolic;
1819
import static org.utbot.engine.overrides.UtOverrideMock.alreadyVisited;
1920
import static org.utbot.engine.overrides.UtOverrideMock.doesntThrow;
20-
import static org.utbot.engine.overrides.UtOverrideMock.executeConcretely;
2121
import static org.utbot.engine.overrides.UtOverrideMock.parameter;
2222
import static org.utbot.engine.overrides.UtOverrideMock.visit;
2323

@@ -556,8 +556,7 @@ public final boolean remove(Object o) {
556556
// TODO rewrite it JIRA:1604
557557
@Override
558558
public String toString() {
559-
executeConcretely();
560-
return super.toString();
559+
return makeSymbolic();
561560
}
562561

563562
public final class Entry implements Map.Entry<K, V> {

utbot-framework/src/main/java/org/utbot/engine/overrides/stream/Arrays.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package org.utbot.engine.overrides.stream;
22

33
import org.utbot.api.annotation.UtClassMock;
4+
import org.utbot.engine.overrides.collections.UtArrayList;
45

6+
import java.util.List;
57
import java.util.stream.Stream;
68

79
@UtClassMock(target = java.util.Arrays.class, internalUsage = true)
@@ -16,5 +18,12 @@ public static <T> Stream<T> stream(T[] array, int startInclusive, int endExclusi
1618
return new UtStream<>(array, startInclusive, endExclusive);
1719
}
1820

21+
@SuppressWarnings({"unused", "varargs"})
22+
@SafeVarargs
23+
public static <T> List<T> asList(T... a) {
24+
// TODO immutable collection https://github.com/UnitTestBot/UTBotJava/issues/398
25+
return new UtArrayList<>(a);
26+
}
27+
1928
// TODO primitive arrays https://github.com/UnitTestBot/UTBotJava/issues/146
2029
}

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import org.utbot.engine.overrides.collections.UtHashSet
1010
import org.utbot.engine.overrides.collections.UtLinkedList
1111
import org.utbot.engine.pc.UtAddrExpression
1212
import org.utbot.engine.pc.UtExpression
13+
import org.utbot.engine.pc.UtFalse
1314
import org.utbot.engine.pc.select
1415
import org.utbot.engine.symbolic.asHardConstraint
1516
import org.utbot.engine.z3.intValue
@@ -82,12 +83,24 @@ abstract class BaseOverriddenWrapper(protected val overriddenClassName: String)
8283
return listOf(GraphResult(method.jimpleBody().graph()))
8384
}
8485

85-
val overriddenMethod = overriddenClass.findMethodOrNull(method.subSignature)
86-
87-
val jimpleBody = overriddenMethod?.jimpleBody() ?: method.jimpleBody()
88-
val graphResult = GraphResult(jimpleBody.graph())
89-
90-
return listOf(graphResult)
86+
// We need to find either an override from the class (for example, implementation
87+
// of the method from the wrapper) or a method from its ancestors.
88+
// Note that the method from the ancestor might have substitutions as well.
89+
// I.e., it is `toString` method for `UtArrayList` that is defined in
90+
// `AbstractCollection` and has its own overridden implementation.
91+
val overriddenMethod = overriddenClass
92+
.findMethodOrNull(method.subSignature)
93+
?.let { typeRegistry.findSubstitutionOrNull(it) ?: it }
94+
95+
return if (overriddenMethod == null) {
96+
// No overridden method has been found, switch to concrete execution
97+
pathLogger.warn("Method ${overriddenClass.name}::${method.subSignature} not found, executing concretely")
98+
emptyList()
99+
} else {
100+
val jimpleBody = overriddenMethod.jimpleBody()
101+
val graphResult = GraphResult(jimpleBody.graph())
102+
listOf(graphResult)
103+
}
91104
}
92105
}
93106

0 commit comments

Comments
 (0)