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 01cedbc36..4efa6750a 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -680,7 +680,7 @@ public class InsnGen { if (!arg.getType().equals(origType)) { code.add('('); useType(code, origType); - code.add(')'); + code.add(") "); addArg(code, arg, true); } else { addArg(code, arg, false); diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/MthParameterArg.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/MthParameterArg.java index 408858548..275486e8f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/MthParameterArg.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/MthParameterArg.java @@ -39,6 +39,7 @@ public class MthParameterArg extends RegisterArg { if (isThis) { sVar.setName("this"); } + sVar.setTypeImmutable(type); super.setSVar(sVar); } diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java index 0ec8dffc6..5bfacd201 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/RegisterArg.java @@ -80,6 +80,7 @@ public class RegisterArg extends InsnArg implements Named { setName(name); } + @Deprecated public void forceType(ArgType type) { this.type = type; } diff --git a/jadx-core/src/main/java/jadx/core/dex/instructions/args/SSAVar.java b/jadx-core/src/main/java/jadx/core/dex/instructions/args/SSAVar.java index da5ad647d..42d59127a 100644 --- a/jadx-core/src/main/java/jadx/core/dex/instructions/args/SSAVar.java +++ b/jadx-core/src/main/java/jadx/core/dex/instructions/args/SSAVar.java @@ -19,6 +19,7 @@ public class SSAVar { private PhiInsn usedInPhi; private ArgType type; + private boolean typeImmutable; public SSAVar(int regNum, int v, RegisterArg assign) { this.regNum = regNum; @@ -33,10 +34,6 @@ public class SSAVar { endUseAddr = -1; } - public int getRegNum() { - return regNum; - } - public int getStartAddr() { if (startUseAddr == -1) { calcUsageAddrRange(); @@ -48,7 +45,6 @@ public class SSAVar { if (endUseAddr == -1) { calcUsageAddrRange(); } - return endUseAddr; } @@ -78,12 +74,16 @@ public class SSAVar { } } - if ((start != Integer.MAX_VALUE) + if ((start != Integer.MAX_VALUE) && (end != Integer.MIN_VALUE)) { startUseAddr = start; endUseAddr = end; } - } + } + + public int getRegNum() { + return regNum; + } public int getVersion() { return version; @@ -141,20 +141,32 @@ public class SSAVar { return useList.size() + usedInPhi.getResult().getSVar().getUseCount(); } - public ArgType getType() { - return type; - } - public void setType(ArgType type) { - this.type = type; + ArgType acceptedType; + if (typeImmutable) { + // don't change type, just update types in useList + acceptedType = this.type; + } else { + acceptedType = type; + this.type = acceptedType; + } if (assign != null) { - assign.type = type; + assign.type = acceptedType; } for (int i = 0, useListSize = useList.size(); i < useListSize; i++) { - useList.get(i).type = type; + useList.get(i).type = acceptedType; } } + public void setTypeImmutable(ArgType type) { + setType(type); + this.typeImmutable = true; + } + + public boolean isTypeImmutable() { + return typeImmutable; + } + public void setName(String name) { if (name != null) { if (varName == null) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/PostTypeInference.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/PostTypeInference.java index b79ba81da..9276a4d68 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/PostTypeInference.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/PostTypeInference.java @@ -85,20 +85,21 @@ public class PostTypeInference { case CHECK_CAST: { ArgType castType = (ArgType) ((IndexInsnNode) insn).getIndex(); - SSAVar sVar = insn.getResult().getSVar(); + RegisterArg result = insn.getResult(); // don't override generic types of same base class - boolean skip = castType.isObject() && castType.getObject().equals(sVar.getType().getObject()); + boolean skip = castType.isObject() && castType.getObject().equals(result.getType().getObject()); if (!skip) { // workaround for compiler bug (see TestDuplicateCast) - sVar.setType(castType); + result.getSVar().setType(castType); } return true; } case PHI: { PhiInsn phi = (PhiInsn) insn; - SSAVar resultSVar = phi.getResult().getSVar(); - if (resultSVar != null && !resultSVar.getType().isTypeKnown()) { + RegisterArg result = phi.getResult(); + SSAVar resultSVar = result.getSVar(); + if (resultSVar != null && !result.getType().isTypeKnown()) { for (InsnArg arg : phi.getArguments()) { ArgType argType = arg.getType(); if (argType.isTypeKnown()) { diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInference.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInference.java index af458ba0a..a7883948f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInference.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeinference/TypeInference.java @@ -44,8 +44,7 @@ public class TypeInference extends AbstractVisitor { private static ArgType processType(SSAVar var) { RegisterArg assign = var.getAssign(); List useList = var.getUseList(); - if (assign != null - && (useList.isEmpty() || assign.isTypeImmutable())) { + if (assign != null && (useList.isEmpty() || var.isTypeImmutable())) { return assign.getType(); } ArgType type; diff --git a/jadx-core/src/test/java/jadx/tests/integration/invoke/TestOverloadedMethodInvoke.java b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestOverloadedMethodInvoke.java new file mode 100644 index 000000000..2d37a36da --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestOverloadedMethodInvoke.java @@ -0,0 +1,58 @@ +package jadx.tests.integration.invoke; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +public class TestOverloadedMethodInvoke extends IntegrationTest { + + public static class TestCls { + int c; + + public void method(Throwable th) { + c++; + if (th != null) { + c+=100; + } + } + + public void method(Exception e) { + c += 1000; + if (e != null) { + c += 10000; + } + } + + public void test(Throwable th, Exception e) { + method(e); + method(th); + method((Throwable) e); + method((Exception) th); + } + + public void check() { + test(null, new Exception()); + assertEquals(12102, c); + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsString("public void test(Throwable th, Exception e) {")); + assertThat(code, containsOne("method(e);")); + assertThat(code, containsOne("method(th);")); + assertThat(code, containsOne("method((Throwable) e);")); + assertThat(code, containsOne("method((Exception) th);")); + assertThat(code, not(containsString("(Exception) e"))); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver2.java b/jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver2.java new file mode 100644 index 000000000..9bb76c739 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/types/TestTypeResolver2.java @@ -0,0 +1,34 @@ +package jadx.tests.integration.types; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.IntegrationTest; + +import java.io.IOException; + +import org.junit.Test; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.junit.Assert.assertThat; + +public class TestTypeResolver2 extends IntegrationTest { + + public static class TestCls { + + private static boolean test(Object obj) throws IOException { + if (obj != null) { + return true; + } + throw new IOException(); + } + } + + @Test + public void test() { + noDebugInfo(); + + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("if (obj != null) {")); + } +}