core: replace removed synthetic constructor
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
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++) {
|
||||
@@ -157,6 +162,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'
|
||||
*/
|
||||
|
||||
@@ -121,6 +121,11 @@ public abstract class IntegrationTest extends TestUtils {
|
||||
public boolean isShowInconsistentCode() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getThreadsCount() {
|
||||
return 1;
|
||||
}
|
||||
}, new File(outDir));
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
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;"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user