fix: add explicit type for non-int constants (#1336)
This commit is contained in:
@@ -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<Flags> state) throws CodegenException {
|
||||
if (insn.contains(AFlag.ARITH_ONEARG)) {
|
||||
makeArithOneArg(insn, code);
|
||||
|
||||
@@ -300,6 +300,20 @@ public class InsnNode extends LineAttrNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visit all args recursively (including inner instructions),
|
||||
* but excluding wrapped args
|
||||
*/
|
||||
public void visitArgs(Consumer<InsnArg> 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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")));
|
||||
|
||||
@@ -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);");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Integer> 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);"));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -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) {"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);"));
|
||||
|
||||
@@ -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)");
|
||||
}
|
||||
}
|
||||
@@ -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")));
|
||||
|
||||
@@ -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")));
|
||||
}
|
||||
|
||||
@@ -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;"));
|
||||
|
||||
@@ -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);");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user