diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java index 3f43e7d4db7c3167eae303361d4397b74de04c69..061aa95d6e73965bf672b6109867d3b2d85ce8b4 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/ArgType.java @@ -655,7 +655,7 @@ public abstract class ArgType { if (from.equals(to)) { return false; } - TypeCompareEnum result = root.getTypeUpdate().getTypeCompare().compareTypes(from, to); + TypeCompareEnum result = root.getTypeCompare().compareTypes(from, to); return !result.isNarrow(); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java index 3dbde30ea93f48de191a8c56848344f6e828f903..4bee88c1a5e79735f2d4c8e80ea4364d7ed9f762 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/SimplifyVisitor.java @@ -38,6 +38,7 @@ import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.RootNode; import jadx.core.dex.regions.conditions.IfCondition; import jadx.core.dex.visitors.shrink.CodeShrinkVisitor; +import jadx.core.dex.visitors.typeinference.TypeCompareEnum; import jadx.core.utils.BlockUtils; import jadx.core.utils.InsnList; import jadx.core.utils.InsnRemover; @@ -82,7 +83,7 @@ public class SimplifyVisitor extends AbstractVisitor { for (int i = 0; i < list.size(); i++) { InsnNode insn = list.get(i); int insnCount = list.size(); - InsnNode modInsn = simplifyInsn(mth, insn); + InsnNode modInsn = simplifyInsn(mth, insn, null); if (modInsn != null) { modInsn.rebindArgs(); if (i < list.size() && list.get(i) == insn) { @@ -110,7 +111,7 @@ public class SimplifyVisitor extends AbstractVisitor { for (InsnArg arg : insn.getArguments()) { if (arg.isInsnWrap()) { InsnNode wrapInsn = ((InsnWrapArg) arg).getWrapInsn(); - InsnNode replaceInsn = simplifyInsn(mth, wrapInsn); + InsnNode replaceInsn = simplifyInsn(mth, wrapInsn, insn); if (replaceInsn != null) { arg.wrapInstruction(mth, replaceInsn); InsnRemover.unbindInsn(mth, wrapInsn); @@ -123,7 +124,7 @@ public class SimplifyVisitor extends AbstractVisitor { } } - private InsnNode simplifyInsn(MethodNode mth, InsnNode insn) { + private InsnNode simplifyInsn(MethodNode mth, InsnNode insn, @Nullable InsnNode parentInsn) { if (insn.contains(AFlag.DONT_GENERATE)) { return null; } @@ -146,8 +147,9 @@ public class SimplifyVisitor extends AbstractVisitor { case SPUT: return convertFieldArith(mth, insn); + case CAST: case CHECK_CAST: - return processCast(mth, (IndexInsnNode) insn); + return processCast(mth, (IndexInsnNode) insn, parentInsn); case MOVE: InsnArg firstArg = insn.getArg(0); @@ -212,7 +214,7 @@ public class SimplifyVisitor extends AbstractVisitor { return null; } - private static InsnNode processCast(MethodNode mth, IndexInsnNode castInsn) { + private static InsnNode processCast(MethodNode mth, IndexInsnNode castInsn, @Nullable InsnNode parentInsn) { if (castInsn.contains(AFlag.EXPLICIT_CAST)) { return null; } @@ -229,7 +231,8 @@ public class SimplifyVisitor extends AbstractVisitor { ArgType castToType = (ArgType) castInsn.getIndex(); if (!ArgType.isCastNeeded(mth.root(), argType, castToType) - || isCastDuplicate(castInsn)) { + || isCastDuplicate(castInsn) + || shadowedByOuterCast(mth.root(), castToType, parentInsn)) { InsnNode insnNode = new InsnNode(InsnType.MOVE, 1); insnNode.setOffset(castInsn.getOffset()); insnNode.setResult(castInsn.getResult()); @@ -254,6 +257,15 @@ public class SimplifyVisitor extends AbstractVisitor { return false; } + private static boolean shadowedByOuterCast(RootNode root, ArgType castType, @Nullable InsnNode parentInsn) { + if (parentInsn != null && parentInsn.getType() == InsnType.CAST) { + ArgType parentCastType = (ArgType) ((IndexInsnNode) parentInsn).getIndex(); + TypeCompareEnum result = root.getTypeCompare().compareTypes(parentCastType, castType); + return result.isNarrow(); + } + return false; + } + /** * Simplify 'cmp' instruction in if condition */ diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeCompare.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeCompare.java index b4001bcf1e2a7abe6ec89a8eadf233ca36b7619e..d5eea1e1e52a865da0ac7cc157bacf83f58592a1 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeCompare.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeCompare.java @@ -98,6 +98,10 @@ public class TypeCompare { || secondPrimitiveType == PrimitiveType.BOOLEAN) { return CONFLICT; } + if (swapEquals(firstPrimitiveType, secondPrimitiveType, PrimitiveType.CHAR, PrimitiveType.BYTE) + || swapEquals(firstPrimitiveType, secondPrimitiveType, PrimitiveType.CHAR, PrimitiveType.SHORT)) { + return CONFLICT; + } return firstPrimitiveType.compareTo(secondPrimitiveType) > 0 ? WIDER : NARROW; } @@ -105,6 +109,10 @@ public class TypeCompare { return TypeCompareEnum.CONFLICT; } + private boolean swapEquals(PrimitiveType first, PrimitiveType second, PrimitiveType a, PrimitiveType b) { + return (first == a && second == b) || (first == b && second == a); + } + private TypeCompareEnum compareArrayWithOtherType(ArgType array, ArgType other) { if (!other.isTypeKnown()) { if (other.contains(PrimitiveType.ARRAY)) { 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 38b9d54b4e45b87b17c1bc7962529b09e8204886..be28e60ff961835415df8ffb33378e4f590ca0aa 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 @@ -63,10 +63,15 @@ public class TypeCompareTest { public void comparePrimitives() { check(INT, UNKNOWN_OBJECT, TypeCompareEnum.CONFLICT); check(INT, OBJECT, TypeCompareEnum.CONFLICT); - check(INT, BOOLEAN, TypeCompareEnum.CONFLICT); + check(INT, CHAR, TypeCompareEnum.WIDER); check(INT, SHORT, TypeCompareEnum.WIDER); + check(BOOLEAN, INT, TypeCompareEnum.CONFLICT); + check(BOOLEAN, CHAR, TypeCompareEnum.CONFLICT); + check(CHAR, BYTE, TypeCompareEnum.CONFLICT); + check(CHAR, SHORT, TypeCompareEnum.CONFLICT); + firstIsNarrow(CHAR, NARROW_INTEGRAL); firstIsNarrow(array(CHAR), UNKNOWN_OBJECT); } diff --git a/jadx-core/src/test/java/jadx/tests/integration/inline/TestInline2.java b/jadx-core/src/test/java/jadx/tests/integration/inline/TestInline2.java index e6c4adffbf1d521c3dc35515587711e16b05255a..be42bd6d83c616896323cdcf7467cb92798aa98c 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/inline/TestInline2.java +++ b/jadx-core/src/test/java/jadx/tests/integration/inline/TestInline2.java @@ -31,6 +31,6 @@ public class TestInline2 extends IntegrationTest { assertThat(code, containsOne("int[] a = {1, 2, 4, 6, 8};")); assertThat(code, containsOne("for (int i = 0; i < a.length; i += 2) {")); - assertThat(code, containsOne("for (long i2 = (long) b; i2 > 0; i2--) {")); + assertThat(code, containsOne("for (long i2 = b; i2 > 0; i2--) {")); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/others/TestPrimitiveCasts.java b/jadx-core/src/test/java/jadx/tests/integration/others/TestPrimitiveCasts.java index 0903dd18cb8015a5b50bbdd643d6fb2fa3aae28b..33cce9ebd5ec4053d0f96ed94b1f4321bb774495 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/others/TestPrimitiveCasts.java +++ b/jadx-core/src/test/java/jadx/tests/integration/others/TestPrimitiveCasts.java @@ -17,16 +17,24 @@ public class TestPrimitiveCasts extends IntegrationTest { useByte((byte) getInt()); useChar((char) 0); useChar((char) getInt()); + useShort((short) 0L); useShort((short) getLong()); useByte((byte) 0L); useByte((byte) getLong()); useChar((char) 0L); useChar((char) getLong()); + useShort((short) ' '); useShort((short) getChar()); useByte((byte) ' '); useByte((byte) getChar()); + + useInt((byte) 7); + useInt((char) ' '); + useInt(getChar()); + useInt((int) 2L); + useInt((int) getLong()); } private long getLong() { @@ -49,6 +57,9 @@ public class TestPrimitiveCasts extends IntegrationTest { private void useShort(short s) { } + + private void useInt(int i) { + } } @TestWithProfiles({ TestProfile.DX_J8, TestProfile.JAVA8 }) @@ -56,6 +67,7 @@ public class TestPrimitiveCasts extends IntegrationTest { noDebugInfo(); assertThat(getClassNode(TestCls.class)) .code() - .doesNotContain("(0)"); + .doesNotContain("(0)") + .doesNotContain(") ((int) getLong())"); } }