fix: simplify cascading casts (#1336)
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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--) {"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user