Commit 03f03f85 authored by Skylot's avatar Skylot

core: replace removed synthetic constructor

parent 2b00a8a4
......@@ -52,6 +52,13 @@ public class ConstructorInsn extends InsnNode {
setSourceLine(invoke.getSourceLine());
}
public ConstructorInsn(MethodInfo callMth, CallType callType, RegisterArg instanceArg) {
super(InsnType.CONSTRUCTOR, callMth.getArgsCount());
this.callMth = callMth;
this.callType = callType;
this.instanceArg = instanceArg;
}
public MethodInfo getCallMth() {
return callMth;
}
......@@ -64,6 +71,10 @@ public class ConstructorInsn extends InsnNode {
return callMth.getDeclClass();
}
public CallType getCallType() {
return callType;
}
public boolean isNewInstance() {
return callType == CallType.CONSTRUCTOR;
}
......
package jadx.core.dex.visitors;
import jadx.core.codegen.TypeGen;
import jadx.core.deobf.NameMapper;
import jadx.core.dex.attributes.AType;
import jadx.core.dex.info.MethodInfo;
......@@ -143,6 +144,10 @@ public class ModVisitor extends AbstractVisitor {
if (co.isNewInstance()) {
removeAssignChain(instArgAssignInsn, remover, InsnType.NEW_INSTANCE);
}
ConstructorInsn replace = processConstructor(mth, co);
if (replace != null) {
replaceInsn(block, insnNumber, replace);
}
}
} else if (inv.getArgsCount() > 0) {
for (int j = 0; j < inv.getArgsCount(); j++) {
......@@ -158,6 +163,42 @@ public class ModVisitor extends AbstractVisitor {
}
/**
* Replace call of synthetic constructor
*/
private static ConstructorInsn processConstructor(MethodNode mth, ConstructorInsn co) {
MethodNode callMth = mth.dex().resolveMethod(co.getCallMth());
if (callMth != null
&& callMth.getAccessFlags().isSynthetic()
&& allArgsNull(co)) {
// if all arguments is null => replace with default constructor
ClassNode classNode = mth.dex().resolveClass(callMth.getParentClass().getClassInfo());
boolean passThis = co.getArgsCount() >= 1 && co.getArg(0).isThis();
String ctrId = "<init>(" + (passThis ? TypeGen.signature(co.getArg(0).getType()) : "") + ")V";
MethodNode defCtr = classNode.searchMethodByName(ctrId);
if (defCtr != null) {
ConstructorInsn newInsn = new ConstructorInsn(defCtr.getMethodInfo(), co.getCallType(), co.getInstanceArg());
newInsn.setResult(co.getResult());
return newInsn;
}
}
return null;
}
private static boolean allArgsNull(InsnNode insn) {
for (InsnArg insnArg : insn.getArguments()) {
if (insnArg.isLiteral()) {
LiteralArg lit = (LiteralArg) insnArg;
if (lit.getLiteral() != 0) {
return false;
}
} else if (!insnArg.isThis()) {
return false;
}
}
return true;
}
/**
* Remove instructions on 'move' chain until instruction with type 'insnType'
*/
private static void removeAssignChain(InsnNode insn, InstructionRemover remover, InsnType insnType) {
......
......@@ -121,6 +121,11 @@ public abstract class IntegrationTest extends TestUtils {
public boolean isShowInconsistentCode() {
return true;
}
@Override
public int getThreadsCount() {
return 1;
}
}, new File(outDir));
}
......
package jadx.tests.integration.inner;
import jadx.core.dex.nodes.ClassNode;
import jadx.tests.api.IntegrationTest;
import org.junit.Test;
import static jadx.tests.api.utils.JadxMatchers.containsOne;
import static org.junit.Assert.assertThat;
public class TestInnerClass4 extends IntegrationTest {
public static class TestCls {
public class C {
public String c;
private C() {
this.c = "c";
}
}
private String test() {
return new C().c;
}
}
@Test
public void test() {
ClassNode cls = getClassNode(TestCls.class);
String code = cls.getCode().toString();
assertThat(code, containsOne("return new C().c;"));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment