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 4de5cac7b..117e5a23f 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -647,6 +647,10 @@ public class InsnGen { if (arg.contains(AFlag.SKIP_ARG)) { continue; } + RegisterArg callArg = getCallMthArg(callMth, i - startArgNum); + if (callArg != null && callArg.contains(AFlag.SKIP_ARG)) { + continue; + } if (i != k) { code.add(", "); } @@ -660,6 +664,17 @@ public class InsnGen { code.add(')'); } + private static RegisterArg getCallMthArg(@Nullable MethodNode callMth, int num) { + if (callMth == null) { + return null; + } + List args = callMth.getArguments(false); + if (args != null && num < args.size()) { + return args.get(num); + } + return null; + } + /** * Add additional cast for overloaded method argument. */ diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java b/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java index 35e30f954..29bbe03ce 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/ClassModifier.java @@ -11,6 +11,7 @@ import jadx.core.dex.instructions.IndexInsnNode; import jadx.core.dex.instructions.InsnType; import jadx.core.dex.instructions.args.InsnArg; import jadx.core.dex.instructions.args.RegisterArg; +import jadx.core.dex.instructions.args.SSAVar; import jadx.core.dex.instructions.mods.ConstructorInsn; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.ClassNode; @@ -135,13 +136,24 @@ public class ClassModifier extends AbstractVisitor { mth.add(AFlag.DONT_GENERATE); continue; } - // remove synthetic constructor for inner non-static classes + // remove synthetic constructor for inner classes if (af.isSynthetic() && af.isConstructor() && mth.getBasicBlocks().size() == 2) { List insns = mth.getBasicBlocks().get(0).getInstructions(); if (insns.size() == 1 && insns.get(0).getType() == InsnType.CONSTRUCTOR) { ConstructorInsn constr = (ConstructorInsn) insns.get(0); - if (constr.isThis() && !mth.getArguments(false).isEmpty()) { - mth.removeFirstArgument(); + List args = mth.getArguments(false); + if (constr.isThis() && !args.isEmpty()) { + // remove first arg for non-static class (references to outer class) + if (args.get(0).getType().equals(cls.getParentClass().getClassInfo().getType())) { + args.get(0).add(AFlag.SKIP_ARG); + } + // remove unused args + for (RegisterArg arg : args) { + SSAVar sVar = arg.getSVar(); + if (sVar != null && sVar.getUseCount() == 0) { + arg.add(AFlag.SKIP_ARG); + } + } mth.add(AFlag.DONT_GENERATE); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvoke1.java b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvoke1.java new file mode 100644 index 000000000..f1fb564cb --- /dev/null +++ b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvoke1.java @@ -0,0 +1,69 @@ +package jadx.tests.integration.invoke; + +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 TestInvoke1 extends IntegrationTest { + + public static class TestCls { + + private A is; + + private C test(int start) throws IOException { + int id = is.readInt32(); + String name = is.readString16Fixed(128); + + long typeStringsOffset = start + is.readInt32(); + long keyStringsOffset = start + is.readInt32(); + + String[] types = null; + if (typeStringsOffset != 0) { + types = strs(); + } + String[] keys = null; + if (keyStringsOffset != 0) { + keys = strs(); + } + + C pkg = new C(id, name, types, keys); + if (id == 0x7F) { + is.readInt32(); + } + return pkg; + } + + private String[] strs() { + return new String[0]; + } + + private static final class C { + public C(int id, String name, String[] types, String[] keys) { + } + } + + private final class A { + public int readInt32() { + return 0; + } + + public String readString16Fixed(int i) { + return null; + } + } + } + + @Test + public void test() { + ClassNode cls = getClassNode(TestCls.class); + String code = cls.getCode().toString(); + + assertThat(code, containsOne("C pkg = new C(id, name, types, keys);")); + } +}