core: fix type detection for method arguments
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -39,6 +39,7 @@ public class MthParameterArg extends RegisterArg {
|
||||
if (isThis) {
|
||||
sVar.setName("this");
|
||||
}
|
||||
sVar.setTypeImmutable(type);
|
||||
super.setSVar(sVar);
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ public class RegisterArg extends InsnArg implements Named {
|
||||
setName(name);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void forceType(ArgType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -44,8 +44,7 @@ public class TypeInference extends AbstractVisitor {
|
||||
private static ArgType processType(SSAVar var) {
|
||||
RegisterArg assign = var.getAssign();
|
||||
List<RegisterArg> useList = var.getUseList();
|
||||
if (assign != null
|
||||
&& (useList.isEmpty() || assign.isTypeImmutable())) {
|
||||
if (assign != null && (useList.isEmpty() || var.isTypeImmutable())) {
|
||||
return assign.getType();
|
||||
}
|
||||
ArgType type;
|
||||
|
||||
@@ -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")));
|
||||
}
|
||||
}
|
||||
@@ -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) {"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user