core: expand arrays for vararg arguments
This commit is contained in:
@@ -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<ArgType> 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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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());"));
|
||||
}
|
||||
}
|
||||
|
||||
+4
-5
@@ -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) {"));
|
||||
Reference in New Issue
Block a user