diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/LiteralArg.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/LiteralArg.java index cc1697af4db3b3f725d19be0c51e10cc8fc544de..6794c76508ab099b533e9cdd34604973d6ad8fc0 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/LiteralArg.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/LiteralArg.java @@ -1,5 +1,7 @@ package jadx.core.dex.instructions.args; +import org.jetbrains.annotations.Nullable; + import jadx.core.codegen.TypeGen; import jadx.core.utils.StringUtils; import jadx.core.utils.exceptions.JadxRuntimeException; @@ -57,12 +59,48 @@ public final class LiteralArg extends InsnArg { } public boolean isInteger() { - PrimitiveType type = this.type.getPrimitiveType(); - return type == PrimitiveType.INT - || type == PrimitiveType.BYTE - || type == PrimitiveType.CHAR - || type == PrimitiveType.SHORT - || type == PrimitiveType.LONG; + switch (type.getPrimitiveType()) { + case INT: + case BYTE: + case CHAR: + case SHORT: + case LONG: + return true; + default: + return false; + } + } + + public boolean isNegative() { + if (isInteger()) { + return literal < 0; + } + if (type == ArgType.FLOAT) { + float val = Float.intBitsToFloat(((int) literal)); + return val < 0 && Float.isFinite(val); + } + if (type == ArgType.DOUBLE) { + double val = Double.longBitsToDouble(literal); + return val < 0 && Double.isFinite(val); + } + return false; + } + + @Nullable + public LiteralArg negate() { + long neg; + if (isInteger()) { + neg = -literal; + } else if (type == ArgType.FLOAT) { + float val = Float.intBitsToFloat(((int) literal)); + neg = Float.floatToIntBits(-val); + } else if (type == ArgType.DOUBLE) { + double val = Double.longBitsToDouble(literal); + neg = Double.doubleToLongBits(-val); + } else { + return null; + } + return new LiteralArg(neg, type); } @Override 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 d9e0aa03563f1c1ce26f2f1587376b1a9722535d..3dbde30ea93f48de191a8c56848344f6e828f903 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 @@ -532,32 +532,44 @@ public class SimplifyVisitor extends AbstractVisitor { if (arith.getArgsCount() != 2) { return null; } - InsnArg litArg = null; + LiteralArg litArg = null; InsnArg secondArg = arith.getArg(1); if (secondArg.isInsnWrap()) { InsnNode wr = ((InsnWrapArg) secondArg).getWrapInsn(); if (wr.getType() == InsnType.CONST) { - litArg = wr.getArg(0); + InsnArg arg = wr.getArg(0); + if (arg.isLiteral()) { + litArg = (LiteralArg) arg; + } } } else if (secondArg.isLiteral()) { - litArg = secondArg; - } - if (litArg != null) { - long lit = ((LiteralArg) litArg).getLiteral(); - // fix 'c + (-1)' => 'c - (1)' - if (arith.getOp() == ArithOp.ADD && lit < 0) { - return new ArithNode(ArithOp.SUB, - arith.getResult(), arith.getArg(0), - InsnArg.lit(-lit, litArg.getType())); - } - InsnArg firstArg = arith.getArg(0); - if (arith.getOp() == ArithOp.XOR && firstArg.getType() == ArgType.BOOLEAN - && (lit == 0 || lit == 1)) { - InsnNode node = new InsnNode(lit == 0 ? InsnType.MOVE : InsnType.NOT, 1); - node.setResult(arith.getResult()); - node.addArg(firstArg); - return node; - } + litArg = (LiteralArg) secondArg; + } + if (litArg == null) { + return null; + } + switch (arith.getOp()) { + case ADD: + // fix 'c + (-1)' to 'c - (1)' + if (litArg.isNegative()) { + LiteralArg negLitArg = litArg.negate(); + if (negLitArg != null) { + return new ArithNode(ArithOp.SUB, arith.getResult(), arith.getArg(0), negLitArg); + } + } + break; + + case XOR: + // simplify xor on boolean + InsnArg firstArg = arith.getArg(0); + long lit = litArg.getLiteral(); + if (firstArg.getType() == ArgType.BOOLEAN && (lit == 0 || lit == 1)) { + InsnNode node = new InsnNode(lit == 0 ? InsnType.MOVE : InsnType.NOT, 1); + node.setResult(arith.getResult()); + node.addArg(firstArg); + return node; + } + break; } return null; } diff --git a/jadx-core/src/test/java/jadx/tests/integration/arith/TestPrimitivesNegate.java b/jadx-core/src/test/java/jadx/tests/integration/arith/TestPrimitivesNegate.java new file mode 100644 index 0000000000000000000000000000000000000000..ccc7e12e1d2b10b4508ee75dbcf4e6a6a9aa748b --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/arith/TestPrimitivesNegate.java @@ -0,0 +1,33 @@ +package jadx.tests.integration.arith; + +import jadx.tests.api.IntegrationTest; +import jadx.tests.api.extensions.profiles.TestProfile; +import jadx.tests.api.extensions.profiles.TestWithProfiles; + +import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat; + +public class TestPrimitivesNegate extends IntegrationTest { + + @SuppressWarnings("UnnecessaryUnaryMinus") + public static class TestCls { + public double test() { + double[] arr = new double[5]; + arr[0] = -20; + arr[0] += -79; + return arr[0]; + } + + public void check() { + assertThat(test()).isEqualTo(-99); + } + } + + @TestWithProfiles({ TestProfile.DX_J8, TestProfile.JAVA8 }) + public void test() { + noDebugInfo(); + assertThat(getClassNode(TestCls.class)) + .code() + .containsOne("dArr[0] = -20.0d;") + .containsOne("dArr[0] = dArr[0] - 79.0d;"); + } +}