Commit c508e72c authored by Skylot's avatar Skylot

core: fixed types for arguments from overloaded methods

parent 940de240
......@@ -523,7 +523,29 @@ public class InsnGen {
break;
}
code.add(callMth.getName());
addArgs(code, insn, k);
if (callMthNode != null && callMthNode.isArgsOverload()) {
int argsCount = insn.getArgsCount();
List<ArgType> originalType = callMth.getArgumentsTypes();
int origPos = 0;
code.add('(');
for (int i = k; i < argsCount; i++) {
InsnArg arg = insn.getArg(i);
ArgType origType = originalType.get(origPos);
if (!arg.getType().equals(origType)) {
code.add('(').add(useType(origType)).add(')').add(arg(arg));
} else {
code.add(arg(arg));
}
if (i < argsCount - 1) {
code.add(", ");
}
origPos++;
}
code.add(')');
} else {
addArgs(code, insn, k);
}
}
private void inlineMethod(MethodNode callMthNode, InvokeNode insn, CodeWriter code) throws CodegenException {
......@@ -566,11 +588,14 @@ public class InsnGen {
}
private void addArgs(CodeWriter code, InsnNode insn, int k) throws CodegenException {
int argsCount = insn.getArgsCount();
code.add('(');
for (int i = k; i < insn.getArgsCount(); i++) {
code.add(arg(insn, i));
if (i < insn.getArgsCount() - 1)
if (k < argsCount) {
code.add(arg(insn, k));
for (int i = k + 1; i < argsCount; i++) {
code.add(", ");
code.add(arg(insn, i));
}
}
code.add(')');
}
......
......@@ -455,8 +455,23 @@ public class MethodNode extends LineAttrNode implements ILoadable {
return exceptionHandlers;
}
public boolean isMethodOverloaded() {
// TODO
/**
* Return true if exists method with same name and arguments count
*/
public boolean isArgsOverload() {
int argsCount = mthInfo.getArgumentsTypes().size();
if (argsCount == 0) {
return false;
}
String name = getName();
List<MethodNode> methods = parentClass.getMethods();
for (MethodNode method : methods) {
if (this != method
&& method.getName().equals(name)
&& method.mthInfo.getArgumentsTypes().size() == argsCount)
return true;
}
return false;
}
......
......@@ -19,11 +19,11 @@ public class FinishTypeResolver extends AbstractVisitor {
int i = 0;
do {
change = false;
for (BlockNode block : mth.getBasicBlocks())
for (BlockNode block : mth.getBasicBlocks()) {
for (InsnNode insn : block.getInstructions())
if (PostTypeResolver.visit(insn))
if (PostTypeResolver.visit(mth, insn))
change = true;
}
i++;
if (i > 1000)
break;
......
package jadx.core.dex.visitors.typeresolver.finish;
import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.IfNode;
import jadx.core.dex.instructions.InvokeNode;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.instructions.args.InsnArg;
import jadx.core.dex.instructions.args.LiteralArg;
import jadx.core.dex.instructions.args.RegisterArg;
import jadx.core.dex.nodes.InsnNode;
import jadx.core.dex.nodes.MethodNode;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PostTypeResolver {
private static final Logger LOG = LoggerFactory.getLogger(PostTypeResolver.class);
public static boolean visit(InsnNode insn) {
public static boolean visit(MethodNode mth, InsnNode insn) {
switch (insn.getType()) {
case CONST:
if (insn.getArgsCount() > 0) {
RegisterArg res = insn.getResult();
LiteralArg litArg = (LiteralArg) insn.getArg(0);
if (res.getType().isObject()) {
long lit = litArg.getLiteral();
if (lit != 0) {
// incorrect literal value for object
ArgType type = (lit == 1 ? ArgType.BOOLEAN : ArgType.INT);
// can't merge with object -> force it
litArg.getTypedVar().forceSetType(type);
res.getTypedVar().forceSetType(type);
return true;
}
RegisterArg res = insn.getResult();
LiteralArg litArg = (LiteralArg) insn.getArg(0);
if (res.getType().isObject()) {
long lit = litArg.getLiteral();
if (lit != 0) {
// incorrect literal value for object
ArgType type = (lit == 1 ? ArgType.BOOLEAN : ArgType.INT);
// can't merge with object -> force it
litArg.getTypedVar().forceSetType(type);
res.getTypedVar().forceSetType(type);
return true;
}
// return litArg.getTypedVar().forceSetType(res.getType());
return litArg.merge(res);
}
break;
// return litArg.getTypedVar().forceSetType(res.getType());
return litArg.merge(res);
case MOVE: {
boolean change = false;
......@@ -58,6 +64,27 @@ public class PostTypeResolver {
return change;
}
// check argument types for overloaded methods
case INVOKE: {
boolean change = false;
InvokeNode inv = (InvokeNode) insn;
MethodInfo callMth = inv.getCallMth();
MethodNode node = mth.dex().resolveMethod(callMth);
if (node != null && node.isArgsOverload()) {
List<ArgType> args = callMth.getArgumentsTypes();
int j = inv.getArgsCount() - 1;
for (int i = args.size() - 1; i >= 0; i--) {
ArgType argType = args.get(i);
InsnArg insnArg = inv.getArg(j--);
if (insnArg.isRegister() && !argType.equals(insnArg.getType())) {
insnArg.getTypedVar().forceSetType(argType);
change = true;
}
}
}
return change;
}
default:
break;
}
......
package jadx.samples;
/**
* Code example from
* <a href="http://stackoverflow.com/questions/2840183/is-there-any-java-decompiler-that-can-correctly-decompile-calls-to-overloaded-me">
* stackoverflow question</a>
*/
public class TestTypeResolver2 extends AbstractTest {
private static String result = "";
public void testOverloadedMethods() {
Object s1 = "The";
Object s2 = "answer";
doPrint((Object) "You should know:");
for (int i = 0; i < 2; i++) {
doPrint(s1);
doPrint(s2);
s1 = "is";
s2 = new Integer(42);
}
}
private static void doPrint(String s1) {
// incorrect call
assertTrue(false);
}
private static void doPrint(Integer s1) {
// incorrect call
assertTrue(false);
}
private static void doPrint(Object s1) {
// correct call
result += s1 + " ";
}
@Override
public boolean testRun() throws Exception {
testOverloadedMethods();
assertEquals(result, "You should know: The answer is 42 ");
return true;
}
public static void main(String[] args) throws Exception {
(new TestTypeResolver2()).testRun();
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment