From 519a74e8d27ae8e738a9f5b7fb940f91a91d3f9f Mon Sep 17 00:00:00 2001 From: Skylot Date: Sun, 16 Feb 2020 14:04:42 +0000 Subject: [PATCH] fix: improve type inference for arrays (#837) --- .../visitors/typeinference/TypeUpdate.java | 14 ++++----- .../typeinference/TypeCompareTest.java | 4 +++ .../integration/types/TestTypeResolver11.java | 29 ++++++++++++++----- 3 files changed, 32 insertions(+), 15 deletions(-) diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeUpdate.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeUpdate.java index 94149629b..35f6ccb51 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeUpdate.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeUpdate.java @@ -96,13 +96,13 @@ public final class TypeUpdate { TypeCompareEnum compareResult = comparator.compareTypes(candidateType, currentType); if (arg.isTypeImmutable() && currentType != ArgType.UNKNOWN) { // don't changed type - if (compareResult == TypeCompareEnum.CONFLICT) { - if (Consts.DEBUG) { - LOG.debug("Type rejected for {} due to conflict: candidate={}, current={}", arg, candidateType, currentType); - } - return REJECT; + if (compareResult == TypeCompareEnum.EQUAL) { + return SAME; } - return SAME; + if (Consts.DEBUG) { + LOG.debug("Type rejected for {} due to conflict: candidate={}, current={}", arg, candidateType, currentType); + } + return REJECT; } if (compareResult.isWider() && !updateInfo.getFlags().isAllowWider()) { if (Consts.DEBUG) { @@ -412,7 +412,7 @@ public final class TypeUpdate { TypeUpdateResult result = updateTypeChecked(updateInfo, putArg, arrayElement); if (result == REJECT) { ArgType putType = putArg.getType(); - if (putType.isTypeKnown() && putType.isObject()) { + if (putType.isTypeKnown() && !putType.isPrimitive()) { TypeCompareEnum compResult = comparator.compareTypes(arrayElement, putType); if (compResult == TypeCompareEnum.WIDER || compResult == TypeCompareEnum.WIDER_BY_GENERIC) { // allow wider result (i.e allow put in Object[] any objects) diff --git a/jadx-core/src/test/java/jadx/core/dex/visitors/typeinference/TypeCompareTest.java b/jadx-core/src/test/java/jadx/core/dex/visitors/typeinference/TypeCompareTest.java index 7465b6742..356a46544 100644 --- a/jadx-core/src/test/java/jadx/core/dex/visitors/typeinference/TypeCompareTest.java +++ b/jadx-core/src/test/java/jadx/core/dex/visitors/typeinference/TypeCompareTest.java @@ -15,6 +15,7 @@ import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.nodes.RootNode; import static jadx.core.dex.instructions.args.ArgType.BOOLEAN; +import static jadx.core.dex.instructions.args.ArgType.BYTE; import static jadx.core.dex.instructions.args.ArgType.CHAR; import static jadx.core.dex.instructions.args.ArgType.CLASS; import static jadx.core.dex.instructions.args.ArgType.INT; @@ -77,6 +78,9 @@ public class TypeCompareTest { firstIsNarrow(UNKNOWN_ARRAY, OBJECT); + firstIsNarrow(array(BYTE), OBJECT); + firstIsNarrow(array(array(BYTE)), array(OBJECT)); + check(array(OBJECT), array(INT), TypeCompareEnum.CONFLICT); ArgType integerType = ArgType.object("java.lang.Integer"); diff --git a/jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver11.java b/jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver11.java index 584dd3127..be491dda7 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver11.java +++ b/jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver11.java @@ -1,16 +1,19 @@ package jadx.tests.integration.types; +import java.util.Arrays; + import org.junit.jupiter.api.Test; -import jadx.NotYetImplemented; import jadx.tests.api.IntegrationTest; +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + public class TestTypeResolver11 extends IntegrationTest { public static class TestCls { - public Void test(Object... objArr) { - int val = (Integer) objArr[0]; - String str = (String) objArr[1]; + public Void test(Object... objects) { + int val = (Integer) objects[0]; + String str = (String) objects[1]; call(str, str, val, val); return null; } @@ -18,21 +21,31 @@ public class TestTypeResolver11 extends IntegrationTest { private void call(String a, String b, int... val) { } + private boolean test2(String s1, String... args) { + String str = Arrays.toString(args); + return s1.length() + str.length() > 0; + } + public void check() { test(1, "str"); + assertThat(test2("1", "2", "34")).isTrue(); } } - @NotYetImplemented("Missing cast") @Test public void test() { - getClassNode(TestCls.class); + assertThat(getClassNode(TestCls.class)) + .code() + .containsOne("(Integer) objects[0]") + .containsOne("String str = (String) objects[1];"); } - @NotYetImplemented("Missing cast") @Test public void testNoDebug() { noDebugInfo(); - getClassNode(TestCls.class); + assertThat(getClassNode(TestCls.class)) + .code() + .containsOne("(Integer) objArr[0]") + .containsOne("String str = (String) objArr[1];"); } }