feat: support inner class contruction with outer instance (#2253)
This commit is contained in:
@@ -652,6 +652,13 @@ public class ClassGen {
|
||||
code.add(clsName);
|
||||
}
|
||||
|
||||
public void addClsShortNameForced(ICodeWriter code, ClassInfo classInfo) {
|
||||
code.add(classInfo.getAliasShortName());
|
||||
if (!isBothClassesInOneTopClass(cls.getClassInfo(), classInfo)) {
|
||||
addImport(classInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private String useClassInternal(ClassInfo useCls, ClassInfo extClsInfo) {
|
||||
String fullName = extClsInfo.getAliasFullName();
|
||||
if (fallback || !useImports) {
|
||||
|
||||
@@ -749,6 +749,7 @@ public class InsnGen {
|
||||
code.attachAnnotation(refMth);
|
||||
code.add("this");
|
||||
} else {
|
||||
boolean forceShortName = addOuterClassInstance(insn, code, callMth);
|
||||
code.add("new ");
|
||||
if (refMth == null || refMth.contains(AFlag.DONT_GENERATE)) {
|
||||
// use class reference if constructor method is missing (default constructor)
|
||||
@@ -756,7 +757,11 @@ public class InsnGen {
|
||||
} else {
|
||||
code.attachAnnotation(refMth);
|
||||
}
|
||||
mgen.getClassGen().addClsName(code, insn.getClassType());
|
||||
if (forceShortName) {
|
||||
mgen.getClassGen().addClsShortNameForced(code, insn.getClassType());
|
||||
} else {
|
||||
mgen.getClassGen().addClsName(code, insn.getClassType());
|
||||
}
|
||||
GenericInfoAttr genericInfoAttr = insn.get(AType.GENERIC_INFO);
|
||||
if (genericInfoAttr != null) {
|
||||
code.add('<');
|
||||
@@ -777,6 +782,27 @@ public class InsnGen {
|
||||
generateMethodArguments(code, insn, 0, callMth);
|
||||
}
|
||||
|
||||
private boolean addOuterClassInstance(ConstructorInsn insn, ICodeWriter code, MethodNode callMth) throws CodegenException {
|
||||
if (callMth == null || !callMth.contains(AFlag.SKIP_FIRST_ARG)) {
|
||||
return false;
|
||||
}
|
||||
ClassNode ctrCls = callMth.getDeclaringClass();
|
||||
if (!ctrCls.isInner() || insn.getArgsCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
InsnArg instArg = insn.getArg(0);
|
||||
if (instArg.isThis()) {
|
||||
return false;
|
||||
}
|
||||
// instance arg should be of an outer class type
|
||||
if (!instArg.getType().equals(ctrCls.getDeclaringClass().getType())) {
|
||||
return false;
|
||||
}
|
||||
addArgDot(code, instArg);
|
||||
// can't use another dot, force short name of class
|
||||
return true;
|
||||
}
|
||||
|
||||
private void inlineAnonymousConstructor(ICodeWriter code, ClassNode cls, ConstructorInsn insn) throws CodegenException {
|
||||
cls.ensureProcessed();
|
||||
if (this.mth.getParentClass() == cls) {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package jadx.tests.integration.inner;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestInnerConstructorCall extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
@SuppressWarnings("InnerClassMayBeStatic")
|
||||
public class A {
|
||||
public class AA {
|
||||
public void test() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void test() {
|
||||
A a = new A();
|
||||
A.AA aa = a.new AA();
|
||||
aa.test();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("A.AA aa = a.new AA();");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user