diff --git a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java index c2492030c..a5a9cdc0d 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -15,7 +15,6 @@ import jadx.api.data.annotations.InsnCodeOffset; import jadx.api.data.annotations.VarDeclareRef; import jadx.api.data.annotations.VarRef; import jadx.api.plugins.input.data.MethodHandleType; -import jadx.core.deobf.NameMapper; import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; import jadx.core.dex.attributes.nodes.FieldReplaceAttr; @@ -1039,7 +1038,6 @@ public class InsnGen { } else { condGen.wrap(code, insn.getCondition()); code.add(" ? "); - addCastIfNeeded(code, first, second); addArg(code, first, false); code.add(" : "); addArg(code, second, false); @@ -1049,33 +1047,6 @@ public class InsnGen { } } - private void addCastIfNeeded(ICodeWriter code, InsnArg first, InsnArg second) { - if (first.isLiteral() && second.isLiteral()) { - if (first.getType() == ArgType.BYTE) { - long lit1 = ((LiteralArg) first).getLiteral(); - long lit2 = ((LiteralArg) second).getLiteral(); - if (lit1 != Byte.MAX_VALUE && lit1 != Byte.MIN_VALUE - && lit2 != Byte.MAX_VALUE && lit2 != Byte.MIN_VALUE) { - code.add("(byte) "); - } - } else if (first.getType() == ArgType.SHORT) { - long lit1 = ((LiteralArg) first).getLiteral(); - long lit2 = ((LiteralArg) second).getLiteral(); - if (lit1 != Short.MAX_VALUE && lit1 != Short.MIN_VALUE - && lit2 != Short.MAX_VALUE && lit2 != Short.MIN_VALUE) { - code.add("(short) "); - } - } else if (first.getType() == ArgType.CHAR) { - long lit1 = ((LiteralArg) first).getLiteral(); - long lit2 = ((LiteralArg) second).getLiteral(); - if (!NameMapper.isPrintableChar((char) (lit1)) - && !NameMapper.isPrintableChar((char) (lit2))) { - code.add("(char) "); - } - } - } - } - private void makeArith(ArithNode insn, ICodeWriter code, Set state) throws CodegenException { if (insn.contains(AFlag.ARITH_ONEARG)) { makeArithOneArg(insn, code); diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java index 1c4f12c92..e4fe605f7 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/InsnNode.java @@ -300,6 +300,20 @@ public class InsnNode extends LineAttrNode { } } + /** + * Visit all args recursively (including inner instructions), + * but excluding wrapped args + */ + public void visitArgs(Consumer visitor) { + for (InsnArg arg : getArguments()) { + if (arg.isInsnWrap()) { + ((InsnWrapArg) arg).getWrapInsn().visitArgs(visitor); + } else { + visitor.accept(arg); + } + } + } + /** * Visit this instruction and all inner (wrapped) instructions * To terminate visiting return non-null value diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java b/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java index 2a7bf7d5a..27af49ad0 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/PrepareForCodeGen.java @@ -17,6 +17,7 @@ import jadx.core.dex.attributes.nodes.LineAttrNode; import jadx.core.dex.instructions.ArithNode; import jadx.core.dex.instructions.ArithOp; import jadx.core.dex.instructions.InsnType; +import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.InsnWrapArg; import jadx.core.dex.instructions.args.RegisterArg; @@ -69,6 +70,7 @@ public class PrepareForCodeGen extends AbstractVisitor { checkInline(block); removeParenthesis(block); modifyArith(block); + checkConstUsage(block); } moveConstructorInConstructor(mth); } @@ -122,6 +124,38 @@ public class PrepareForCodeGen extends AbstractVisitor { } } + /** + * Add explicit type for non int constants + */ + private static void checkConstUsage(BlockNode block) { + for (InsnNode blockInsn : block.getInstructions()) { + blockInsn.visitInsns(insn -> { + if (forbidExplicitType(insn.getType())) { + return; + } + for (InsnArg arg : insn.getArguments()) { + if (arg.isLiteral() && arg.getType() != ArgType.INT) { + arg.add(AFlag.EXPLICIT_PRIMITIVE_TYPE); + } + } + }); + } + } + + private static boolean forbidExplicitType(InsnType type) { + switch (type) { + case CONST: + case CAST: + case IF: + case FILLED_NEW_ARRAY: + case APUT: + case ARITH: + return true; + default: + return false; + } + } + private static void removeParenthesis(BlockNode block) { for (InsnNode insn : block.getInstructions()) { removeParenthesis(insn); diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToByte.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToByte.java index dd2602b81..91230631c 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToByte.java +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToByte.java @@ -24,6 +24,6 @@ public class TestBooleanToByte extends SmaliTest { public void test() { assertThat(getClassNodeFromSmali()) .code() - .containsOne("write(this.showConsent ? (byte) 1 : 0);"); + .containsOne("write(this.showConsent ? (byte) 1 : (byte) 0);"); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToChar.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToChar.java index f13060e59..b3455e4a1 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToChar.java +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToChar.java @@ -24,6 +24,6 @@ public class TestBooleanToChar extends SmaliTest { public void test() { assertThat(getClassNodeFromSmali()) .code() - .containsOne("write(this.showConsent ? (char) 1 : 0);"); + .containsOne("write(this.showConsent ? (char) 1 : (char) 0);"); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToLong.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToLong.java index 263db0aff..eba02aa77 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToLong.java +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToLong.java @@ -24,6 +24,6 @@ public class TestBooleanToLong extends SmaliTest { public void test() { assertThat(getClassNodeFromSmali()) .code() - .containsOne("write(this.showConsent ? 1 : 0);"); + .containsOne("write(this.showConsent ? 1L : 0L);"); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToShort.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToShort.java index a330c196c..25888dfde 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToShort.java +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestBooleanToShort.java @@ -24,6 +24,6 @@ public class TestBooleanToShort extends SmaliTest { public void test() { assertThat(getClassNodeFromSmali()) .code() - .containsOne("write(this.showConsent ? (short) 1 : 0);"); + .containsOne("write(this.showConsent ? (short) 1 : (short) 0);"); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestCast.java b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestCast.java index af1a9ddfb..b221b6992 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/conditions/TestCast.java +++ b/jadx-core/src/test/java/jadx/tests/integration/conditions/TestCast.java @@ -51,12 +51,12 @@ public class TestCast extends IntegrationTest { ClassNode cls = getClassNode(TestCls.class); String code = cls.getCode().toString(); - assertThat(code, containsString("write(a ? (byte) 0 : 1);")); - assertThat(code, containsString("write(a ? 0 : this.myByte);")); - assertThat(code, containsString("write(a ? 0 : Byte.MAX_VALUE);")); + assertThat(code, containsString("write(a ? (byte) 0 : (byte) 1);")); + assertThat(code, containsString("write(a ? (byte) 0 : this.myByte);")); + assertThat(code, containsString("write(a ? (byte) 0 : Byte.MAX_VALUE);")); - assertThat(code, containsString("write(a ? (short) 0 : 1);")); - assertThat(code, containsString("write(a ? this.myShort : 0);")); - assertThat(code, containsString("write(a ? Short.MIN_VALUE : 0);")); + assertThat(code, containsString("write(a ? (short) 0 : (short) 1);")); + assertThat(code, containsString("write(a ? this.myShort : (short) 0);")); + assertThat(code, containsString("write(a ? Short.MIN_VALUE : (short) 0);")); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass2.java b/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass2.java index 67d4404c8..889d0eb06 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass2.java +++ b/jadx-core/src/test/java/jadx/tests/integration/inner/TestInnerClass2.java @@ -23,7 +23,7 @@ public class TestInnerClass2 extends IntegrationTest { } public void test() { - new Timer().schedule(new TerminateTask(), 1000); + new Timer().schedule(new TerminateTask(), 1000L); } } @@ -32,7 +32,7 @@ public class TestInnerClass2 extends IntegrationTest { ClassNode cls = getClassNode(TestCls.class); String code = cls.getCode().toString(); - assertThat(code, containsString("new Timer().schedule(new TerminateTask(), 1000);")); + assertThat(code, containsString("new Timer().schedule(new TerminateTask(), 1000L);")); assertThat(code, not(containsString("synthetic"))); assertThat(code, not(containsString("this"))); assertThat(code, not(containsString("null"))); diff --git a/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvokeWithWideVars.java b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvokeWithWideVars.java index 8a442b54c..8cccaa183 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvokeWithWideVars.java +++ b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvokeWithWideVars.java @@ -12,11 +12,11 @@ public class TestInvokeWithWideVars extends IntegrationTest { public static class TestCls { public long test1() { - return call(1, 2); + return call(1, 2L); } public long test2() { - return rangeCall(1, 2, 3.0d, (byte) 4); + return rangeCall(1L, 2, 3.0d, (byte) 4); } private long call(int a, long b) { @@ -32,7 +32,7 @@ public class TestInvokeWithWideVars extends IntegrationTest { public void test() { assertThat(getClassNode(TestCls.class)) .code() - .containsOne("return call(1, 2);") - .containsOne("return rangeCall(1, 2, 3.0d, (byte) 4);"); + .containsOne("return call(1, 2L);") + .containsOne("return rangeCall(1L, 2, 3.0d, (byte) 4);"); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/loops/TestBreakInLoop2.java b/jadx-core/src/test/java/jadx/tests/integration/loops/TestBreakInLoop2.java index e14eda6b8..bafe022cb 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/loops/TestBreakInLoop2.java +++ b/jadx-core/src/test/java/jadx/tests/integration/loops/TestBreakInLoop2.java @@ -13,6 +13,7 @@ import static org.hamcrest.Matchers.anyOf; public class TestBreakInLoop2 extends IntegrationTest { + @SuppressWarnings({ "BusyWait", "ResultOfMethodCallIgnored" }) public static class TestCls { public void test(List data) throws Exception { for (;;) { @@ -25,7 +26,7 @@ public class TestBreakInLoop2 extends IntegrationTest { } data.clear(); } - Thread.sleep(100); + Thread.sleep(100L); } } @@ -47,6 +48,6 @@ public class TestBreakInLoop2 extends IntegrationTest { assertThat(code, anyOf(containsOne("break;"), containsOne("return;"))); assertThat(code, containsOne("throw ex;")); assertThat(code, containsOne("data.clear();")); - assertThat(code, containsOne("Thread.sleep(100);")); + assertThat(code, containsOne("Thread.sleep(100L);")); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/loops/TestSynchronizedInEndlessLoop.java b/jadx-core/src/test/java/jadx/tests/integration/loops/TestSynchronizedInEndlessLoop.java index 5135b8716..631d8d71f 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/loops/TestSynchronizedInEndlessLoop.java +++ b/jadx-core/src/test/java/jadx/tests/integration/loops/TestSynchronizedInEndlessLoop.java @@ -26,7 +26,7 @@ public class TestSynchronizedInEndlessLoop extends IntegrationTest { } try { f++; - Thread.sleep(100); + Thread.sleep(100L); } catch (Exception e) { throw new RuntimeException(e); } @@ -42,7 +42,7 @@ public class TestSynchronizedInEndlessLoop extends IntegrationTest { assertThat(code, containsOne("synchronized (this) {")); assertThat(code, containsOne("try {")); assertThat(code, containsOne("f++;")); - assertThat(code, containsOne("Thread.sleep(100);")); + assertThat(code, containsOne("Thread.sleep(100L);")); assertThat(code, containsOne("} catch (Exception e) {")); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing.java b/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing.java index efac96999..0423441f0 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing.java +++ b/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing.java @@ -69,7 +69,7 @@ public class TestDeboxing extends IntegrationTest { assertThat(code, containsOne("return 1;")); assertThat(code, containsOne("return true;")); assertThat(code, containsOne("return (byte) 2;")); - assertThat(code, containsOne("return 3;")); + assertThat(code, containsOne("return (short) 3;")); assertThat(code, containsOne("return 'c';")); assertThat(code, containsOne("return 4L;")); assertThat(code, countString(2, "use(true);")); 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 new file mode 100644 index 000000000..0903dd18c --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/others/TestPrimitiveCasts.java @@ -0,0 +1,61 @@ +package jadx.tests.integration.others; + +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 TestPrimitiveCasts extends IntegrationTest { + + public static class TestCls { + + public void test() { + useShort((short) 0); + useShort((short) getInt()); + useByte((byte) 0); + 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()); + } + + private long getLong() { + return 1L; + } + + private char getChar() { + return ' '; + } + + private int getInt() { + return 1; + } + + private void useChar(char c) { + } + + private void useByte(byte b) { + } + + private void useShort(short s) { + } + } + + @TestWithProfiles({ TestProfile.DX_J8, TestProfile.JAVA8 }) + public void test() { + noDebugInfo(); + assertThat(getClassNode(TestCls.class)) + .code() + .doesNotContain("(0)"); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestNestedTryCatch.java b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestNestedTryCatch.java index 8e28f0576..3345498b2 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestNestedTryCatch.java +++ b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestNestedTryCatch.java @@ -14,9 +14,9 @@ public class TestNestedTryCatch extends IntegrationTest { public static class TestCls { public void test() { try { - Thread.sleep(1); + Thread.sleep(1L); try { - Thread.sleep(2); + Thread.sleep(2L); } catch (InterruptedException ignored) { System.out.println(2); } @@ -32,8 +32,8 @@ public class TestNestedTryCatch extends IntegrationTest { String code = cls.getCode().toString(); assertThat(code, containsString("try {")); - assertThat(code, containsString("Thread.sleep(1);")); - assertThat(code, containsString("Thread.sleep(2);")); + assertThat(code, containsString("Thread.sleep(1L);")); + assertThat(code, containsString("Thread.sleep(2L);")); assertThat(code, containsString("} catch (InterruptedException e) {")); assertThat(code, containsString("} catch (Exception e2) {")); assertThat(code, not(containsString("return"))); diff --git a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch.java b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch.java index df3c1516f..5a765c017 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch.java +++ b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch.java @@ -14,7 +14,7 @@ public class TestTryCatch extends IntegrationTest { public static class TestCls { public void f() { try { - Thread.sleep(50); + Thread.sleep(50L); } catch (InterruptedException e) { // ignore } @@ -27,7 +27,7 @@ public class TestTryCatch extends IntegrationTest { String code = cls.getCode().toString(); assertThat(code, containsString("try {")); - assertThat(code, containsString("Thread.sleep(50);")); + assertThat(code, containsString("Thread.sleep(50L);")); assertThat(code, containsString("} catch (InterruptedException e) {")); assertThat(code, not(containsString("return"))); } diff --git a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch2.java b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch2.java index be76966cb..9f00fd482 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch2.java +++ b/jadx-core/src/test/java/jadx/tests/integration/trycatch/TestTryCatch2.java @@ -16,7 +16,7 @@ public class TestTryCatch2 extends IntegrationTest { public static boolean test() { try { synchronized (OBJ) { - OBJ.wait(5); + OBJ.wait(5L); } return true; } catch (InterruptedException e) { @@ -32,7 +32,7 @@ public class TestTryCatch2 extends IntegrationTest { assertThat(code, containsString("try {")); assertThat(code, containsString("synchronized (OBJ) {")); - assertThat(code, containsString("OBJ.wait(5);")); + assertThat(code, containsString("OBJ.wait(5L);")); assertThat(code, containsString("return true;")); assertThat(code, containsString("} catch (InterruptedException e) {")); assertThat(code, containsString("return false;")); diff --git a/jadx-core/src/test/java/jadx/tests/integration/types/TestPrimitiveConversion.java b/jadx-core/src/test/java/jadx/tests/integration/types/TestPrimitiveConversion.java index 67dd9a723..73671a11d 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/types/TestPrimitiveConversion.java +++ b/jadx-core/src/test/java/jadx/tests/integration/types/TestPrimitiveConversion.java @@ -23,6 +23,6 @@ public class TestPrimitiveConversion extends SmaliTest { assertThat(getClassNodeFromSmali()) .code() .doesNotContain("putByte(j, z);") - .containsOne("putByte(j, z ? (byte) 1 : 0);"); + .containsOne("putByte(j, z ? (byte) 1 : (byte) 0);"); } }