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 930a869be..82eb62144 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/InsnGen.java @@ -49,6 +49,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -513,6 +514,13 @@ public class InsnGen { } private void fillArray(FillArrayNode insn, CodeWriter code) throws CodegenException { + String filledArray = makeArrayElements(insn); + code.add("new "); + useType(code, insn.getElementType()); + code.add("[]{").add(filledArray).add('}'); + } + + private String makeArrayElements(FillArrayNode insn) throws CodegenException { ArgType insnArrayType = insn.getResult().getType(); ArgType insnElementType = insnArrayType.getArrayElement(); ArgType elType = insn.getElementType(); @@ -526,6 +534,8 @@ public class InsnGen { LOG.warn("Unknown array element type: {} in mth: {}", elType, mth); elType = insnElementType.isTypeKnown() ? insnElementType : elType.selectFirst(); } + insn.mergeElementType(elType); + StringBuilder str = new StringBuilder(); Object data = insn.getData(); switch (elType.getPrimitiveType()) { @@ -567,9 +577,7 @@ public class InsnGen { } int len = str.length(); str.delete(len - 2, len); - code.add("new "); - useType(code, elType); - code.add("[]{").add(str.toString()).add('}'); + return str.toString(); } private void makeConstructor(ConstructorInsn insn, CodeWriter code) @@ -613,7 +621,7 @@ public class InsnGen { code.add("new "); useClass(code, insn.getClassType()); } - generateArguments(code, insn, 0, mth.dex().resolveMethod(insn.getCallMth())); + generateMethodArguments(code, insn, 0, mth.dex().resolveMethod(insn.getCallMth())); } private void makeInvoke(InvokeNode insn, CodeWriter code) throws CodegenException { @@ -658,47 +666,74 @@ public class InsnGen { code.attachAnnotation(callMthNode); } code.add(callMth.getName()); - generateArguments(code, insn, k, callMthNode); + generateMethodArguments(code, insn, k, callMthNode); } - private void generateArguments(CodeWriter code, InsnNode insn, int k, MethodNode callMth) throws CodegenException { + private void generateMethodArguments(CodeWriter code, InsnNode insn, int startArgNum, + @Nullable MethodNode callMth) throws CodegenException { + int k = startArgNum; if (callMth != null && callMth.contains(AFlag.SKIP_FIRST_ARG)) { k++; } int argsCount = insn.getArgsCount(); - if (callMth != null && callMth.isArgsOverload()) { - // add additional argument casts for overloaded methods - List originalType = callMth.getMethodInfo().getArgumentsTypes(); - int origPos = 0; - code.add('('); + code.add('('); + if (k < argsCount) { + boolean overloaded = callMth != null && callMth.isArgsOverload(); for (int i = k; i < argsCount; i++) { InsnArg arg = insn.getArg(i); - ArgType origType = originalType.get(origPos); - if (!arg.getType().equals(origType)) { - code.add('('); - useType(code, origType); - code.add(") "); - addArg(code, arg, true); - } else { - addArg(code, arg, false); + boolean cast = overloaded && processOverloadedArg(code, callMth, arg, i - startArgNum); + if (!cast && i == argsCount - 1 && processVarArg(code, callMth, arg)) { + continue; } + addArg(code, arg, false); if (i < argsCount - 1) { code.add(", "); } - origPos++; } - code.add(')'); - } else { + } + code.add(')'); + } + + /** + * Add additional cast for overloaded method argument. + */ + private boolean processOverloadedArg(CodeWriter code, MethodNode callMth, InsnArg arg, int origPos) { + ArgType origType = callMth.getMethodInfo().getArgumentsTypes().get(origPos); + if (!arg.getType().equals(origType)) { code.add('('); - if (k < argsCount) { - addArg(code, insn.getArg(k), false); - for (int i = k + 1; i < argsCount; i++) { + useType(code, origType); + code.add(") "); + return true; + } + return false; + } + + /** + * Expand varArgs from filled array. + */ + private boolean processVarArg(CodeWriter code, MethodNode callMth, InsnArg lastArg) throws CodegenException { + if (callMth == null || !callMth.getAccessFlags().isVarArgs()) { + return false; + } + if (!lastArg.getType().isArray() || !lastArg.isInsnWrap()) { + return false; + } + InsnNode insn = ((InsnWrapArg) lastArg).getWrapInsn(); + if (insn.getType() == InsnType.FILLED_NEW_ARRAY) { + int count = insn.getArgsCount(); + for (int i = 0; i < count; i++) { + InsnArg elemArg = insn.getArg(i); + addArg(code, elemArg, false); + if (i < count - 1) { code.add(", "); - addArg(code, insn.getArg(i), false); } } - code.add(')'); + return true; + } else if (insn.getType() == InsnType.FILL_ARRAY) { + code.add(makeArrayElements((FillArrayNode) insn)); + return true; } + return false; } private boolean inlineMethod(MethodNode callMthNode, InvokeNode insn, CodeWriter code) throws CodegenException { diff --git a/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java b/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java index 6fce65c49..24db0a39f 100644 --- a/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java +++ b/jadx-core/src/main/java/jadx/core/dex/nodes/DexNode.java @@ -13,6 +13,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.jetbrains.annotations.Nullable; + import com.android.dex.ClassData; import com.android.dex.ClassData.Method; import com.android.dex.ClassDef; @@ -49,10 +51,12 @@ public class DexNode { return classes; } + @Nullable public ClassNode resolveClass(ClassInfo clsInfo) { return root.resolveClass(clsInfo); } + @Nullable public MethodNode resolveMethod(MethodInfo mth) { ClassNode cls = resolveClass(mth.getDeclClass()); if (cls != null) { @@ -61,6 +65,7 @@ public class DexNode { return null; } + @Nullable public FieldNode resolveField(FieldInfo field) { ClassNode cls = resolveClass(field.getDeclClass()); if (cls != null) { diff --git a/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvokeInCatch.java b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvokeInCatch.java index a167e1f23..2d130af24 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvokeInCatch.java +++ b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestInvokeInCatch.java @@ -45,7 +45,6 @@ public class TestInvokeInCatch extends IntegrationTest { assertThat(code, not(containsString("return;"))); assertThat(code, containsOne("} catch (IOException e) {")); assertThat(code, containsOne("if (b == 1) {")); -// assertThat(code, containsOne("log(TAG, \"Error: {}\", e.getMessage());")); - assertThat(code, containsOne("log(TAG, \"Error: {}\", new String[]{e.getMessage()});")); + assertThat(code, containsOne("log(TAG, \"Error: {}\", e.getMessage());")); } } diff --git a/jadx-core/src/test/java/jadx/tests/integration/annotations/TestVarArgAnnotation.java b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestVarArg.java similarity index 75% rename from jadx-core/src/test/java/jadx/tests/integration/annotations/TestVarArgAnnotation.java rename to jadx-core/src/test/java/jadx/tests/integration/invoke/TestVarArg.java index e1a79c100..4d871a3b2 100644 --- a/jadx-core/src/test/java/jadx/tests/integration/annotations/TestVarArgAnnotation.java +++ b/jadx-core/src/test/java/jadx/tests/integration/invoke/TestVarArg.java @@ -1,4 +1,4 @@ -package jadx.tests.integration.annotations; +package jadx.tests.integration.invoke; import jadx.core.dex.nodes.ClassNode; import jadx.tests.api.IntegrationTest; @@ -8,7 +8,7 @@ import org.junit.Test; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertThat; -public class TestVarArgAnnotation extends IntegrationTest { +public class TestVarArg extends IntegrationTest { public static class TestCls { @@ -36,9 +36,8 @@ public class TestVarArgAnnotation extends IntegrationTest { assertThat(code, containsString("void test1(int... a) {")); assertThat(code, containsString("void test2(int i, Object... a) {")); - // TODO: - assertThat(code, containsString("test1(new int[]{1, 2});")); - assertThat(code, containsString("test2(3, new Object[]{\"1\", Integer.valueOf(7)});")); + assertThat(code, containsString("test1(1, 2);")); + assertThat(code, containsString("test2(3, \"1\", Integer.valueOf(7));")); // negative case assertThat(code, containsString("void test3(int[] a) {"));