From c508e72c19efc504cfddc64d36cd8e75c11d8167 Mon Sep 17 00:00:00 2001 From: Skylot Date: Fri, 2 Aug 2013 14:00:55 +0400 Subject: [PATCH] core: fixed types for arguments from overloaded methods --- .../main/java/jadx/core/codegen/InsnGen.java | 33 ++++++++-- .../java/jadx/core/dex/nodes/MethodNode.java | 19 +++++- .../typeresolver/FinishTypeResolver.java | 6 +- .../typeresolver/finish/PostTypeResolver.java | 61 +++++++++++++------ .../java/jadx/samples/TestTypeResolver2.java | 50 +++++++++++++++ 5 files changed, 143 insertions(+), 26 deletions(-) create mode 100644 jadx-samples/src/main/java/jadx/samples/TestTypeResolver2.java 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 899dfa5e6..eea2c63d0 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -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 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(')'); } diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java index 74f87b992..6b8254229 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/MethodNode.java @@ -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 methods = parentClass.getMethods(); + for (MethodNode method : methods) { + if (this != method + && method.getName().equals(name) + && method.mthInfo.getArgumentsTypes().size() == argsCount) + return true; + } return false; } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeresolver/FinishTypeResolver.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeresolver/FinishTypeResolver.java index 2b7a934c5..3c7f1693a 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeresolver/FinishTypeResolver.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeresolver/FinishTypeResolver.java @@ -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; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/typeresolver/finish/PostTypeResolver.java b/jadx-core/src/main/java/jadx/core/dex/visitors/typeresolver/finish/PostTypeResolver.java index 0b92a8b71..f6192f5c1 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/typeresolver/finish/PostTypeResolver.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/typeresolver/finish/PostTypeResolver.java @@ -1,35 +1,41 @@ 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 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; } diff --git a/jadx-samples/src/main/java/jadx/samples/TestTypeResolver2.java b/jadx-samples/src/main/java/jadx/samples/TestTypeResolver2.java new file mode 100644 index 000000000..2d027771d --- /dev/null +++ b/jadx-samples/src/main/java/jadx/samples/TestTypeResolver2.java @@ -0,0 +1,50 @@ +package jadx.samples; + +/** + * Code example from + * + * stackoverflow question + */ +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(); + } +}