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 b43b2de444265b1d5b27a4ef1bf223856e29e950..04e37da474e8101ca46befe9a1044adfa27f0338 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -769,7 +769,7 @@ public class InsnGen { if (!firstArg) { code.add(", "); } - boolean cast = overloaded && processOverloadedArg(code, insn, callMth, arg, i - startArgNum); + boolean cast = addArgCast(code, insn, callMth, arg, i - startArgNum, overloaded); if (!cast && i == argsCount - 1 && processVarArg(code, callMth, arg)) { continue; } @@ -781,42 +781,47 @@ public class InsnGen { } /** - * Add additional cast for overloaded method argument. + * Add additional cast for method argument. */ - private boolean processOverloadedArg(CodeWriter code, InsnNode insn, MethodNode callMth, InsnArg arg, int origPos) { - List argTypes = callMth.getArgTypes(); - ArgType origType = argTypes.get(origPos); - if (origType.isGenericType() && !callMth.getParentClass().equals(mth.getParentClass())) { - // cancel cast - return false; - } + private boolean addArgCast(CodeWriter code, InsnNode insn, @Nullable MethodNode callMth, + InsnArg arg, int origPos, boolean overloaded) { ArgType castType = null; - if (insn instanceof CallMthInterface && origType.containsGenericType()) { - ArgType clsType; - CallMthInterface mthCall = (CallMthInterface) insn; - RegisterArg instanceArg = mthCall.getInstanceArg(); - if (instanceArg != null) { - clsType = instanceArg.getType(); - } else { - clsType = mthCall.getCallMth().getDeclClass().getType(); + if (callMth != null) { + List argTypes = callMth.getArgTypes(); + ArgType origType = argTypes.get(origPos); + if (origType.isGenericType() && !callMth.getParentClass().equals(mth.getParentClass())) { + // cancel cast + return false; } - ArgType replacedType = TypeUtils.replaceClassGenerics(root, clsType, origType); - if (replacedType != null) { - castType = replacedType; + if (insn instanceof CallMthInterface && origType.containsGenericType()) { + ArgType clsType; + CallMthInterface mthCall = (CallMthInterface) insn; + RegisterArg instanceArg = mthCall.getInstanceArg(); + if (instanceArg != null) { + clsType = instanceArg.getType(); + } else { + clsType = mthCall.getCallMth().getDeclClass().getType(); + } + ArgType replacedType = TypeUtils.replaceClassGenerics(root, clsType, origType); + if (replacedType != null) { + castType = replacedType; + } + if (castType == null) { + ArgType invReplType = TypeUtils.replaceMethodGenerics(root, insn, origType); + if (invReplType != null) { + castType = invReplType; + } + } } if (castType == null) { - ArgType invReplType = TypeUtils.replaceMethodGenerics(root, insn, origType); - if (invReplType != null) { - castType = invReplType; - } + castType = origType; } - } - if (castType == null) { - castType = origType; + } else { + castType = arg.getType(); } // TODO: check castType for left type variables - if (isCastNeeded(arg, castType)) { + if (isCastNeeded(arg, castType, overloaded)) { code.add('('); useType(code, castType); code.add(") "); @@ -825,7 +830,7 @@ public class InsnGen { return false; } - private boolean isCastNeeded(InsnArg arg, ArgType origType) { + private boolean isCastNeeded(InsnArg arg, ArgType origType, boolean overloaded) { ArgType argType = arg.getType(); if (arg.isLiteral() && ((LiteralArg) arg).getLiteral() == 0 && (argType.isObject() || argType.isArray())) { @@ -834,7 +839,7 @@ public class InsnGen { if (argType.equals(origType)) { return false; } - return true; + return overloaded; } /** diff --git a/jadx-core/src/test/java/jadx/tests/integration/invoke/TestCastInOverloadedInvoke2.java b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestCastInOverloadedInvoke2.java new file mode 100644 index 0000000000000000000000000000000000000000..30fa5fc00da819c40adf573d394bd6d1701ea6c1 --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestCastInOverloadedInvoke2.java @@ -0,0 +1,22 @@ +package jadx.tests.integration.invoke; + +import org.junit.jupiter.api.Test; + +import jadx.core.dex.nodes.ClassNode; +import jadx.tests.api.SmaliTest; + +import static jadx.tests.api.utils.JadxMatchers.containsOne; +import static org.hamcrest.MatcherAssert.assertThat; + +public class TestCastInOverloadedInvoke2 extends SmaliTest { + + @Test + public void test() { + disableCompilation(); + + ClassNode cls = getClassNodeFromSmali(); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("new Intent().putExtra(\"param\", (Parcelable) null);")); + } +} diff --git a/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing2.java b/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing2.java index 5a7247d56de259403be3192f8d72a849897e87cc..7bdd21745cefb12765f065b0e0e68ad5ec461c71 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing2.java +++ b/jadx-core/src/test/java/jadx/tests/integration/others/TestDeboxing2.java @@ -39,11 +39,10 @@ public class TestDeboxing2 extends IntegrationTest { assertThat(code, containsOne("l = 0L;")); // checks for 'check' method - assertThat(code, containsOne("test(null)")); + assertThat(code, containsOne("test((Long) null)")); // TODO: cast not needed assertThat(code, containsOne("test(0L)")); assertThat(code, countString(2, "is(0L)")); assertThat(code, containsOne("test(7L)")); assertThat(code, containsOne("is(7L)")); - } } diff --git a/jadx-core/src/test/smali/invoke/TestCastInOverloadedInvoke2.smali b/jadx-core/src/test/smali/invoke/TestCastInOverloadedInvoke2.smali new file mode 100644 index 0000000000000000000000000000000000000000..76c9393ea4f690dfa4283198eab3ef80fbf18ef2 --- /dev/null +++ b/jadx-core/src/test/smali/invoke/TestCastInOverloadedInvoke2.smali @@ -0,0 +1,18 @@ +.class public Linvoke/TestCastInOverloadedInvoke2; +.super Ljava/lang/Object; + +.method public test()V + .locals 3 + + new-instance v0, Landroid/content/Intent; + + invoke-direct {v0}, Landroid/content/Intent;->()V + + const-string v1, "param" + + const/4 v2, 0x0 + + invoke-virtual {v0, v1, v2}, Landroid/content/Intent;->putExtra(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent; + + return-void +.end method