feat: support inner class contruction with outer instance (#2253)

This commit is contained in:
Skylot
2024-09-21 20:27:16 +01:00
parent 1d34328dd3
commit 109dea0857
3 changed files with 67 additions and 1 deletions
@@ -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();");
}
}