fix: improve class search for super call (#1512)
This commit is contained in:
@@ -203,6 +203,9 @@ public class ClspGraph {
|
||||
if (isNew) {
|
||||
addSuperTypes(parentCls, result);
|
||||
}
|
||||
} else {
|
||||
// parent type is unknown
|
||||
result.add(parentType.getObject());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -807,14 +807,9 @@ public class InsnGen {
|
||||
break;
|
||||
|
||||
case SUPER:
|
||||
ClassInfo superCallCls = getClassForSuperCall(code, callMth);
|
||||
if (superCallCls != null) {
|
||||
useClass(code, superCallCls);
|
||||
code.add('.');
|
||||
}
|
||||
// use 'super' instead 'this' in 0 arg
|
||||
code.add("super").add('.');
|
||||
k++;
|
||||
callSuper(code, callMth);
|
||||
k++; // use 'super' instead 'this' in 0 arg
|
||||
code.add('.');
|
||||
break;
|
||||
|
||||
case STATIC:
|
||||
@@ -965,34 +960,43 @@ public class InsnGen {
|
||||
code.startLine('}');
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ClassInfo getClassForSuperCall(ICodeWriter code, MethodInfo callMth) {
|
||||
ClassNode useCls = mth.getParentClass();
|
||||
ClassInfo insnCls = useCls.getClassInfo();
|
||||
ClassInfo declClass = callMth.getDeclClass();
|
||||
if (insnCls.equals(declClass)) {
|
||||
return null;
|
||||
private void callSuper(ICodeWriter code, MethodInfo callMth) {
|
||||
ClassInfo superCallCls = getClassForSuperCall(callMth);
|
||||
if (superCallCls == null) {
|
||||
// unknown class, add comment to keep that info
|
||||
code.add("super/*").add(callMth.getDeclClass().getFullName()).add("*/");
|
||||
return;
|
||||
}
|
||||
ClassNode topClass = useCls.getTopParentClass();
|
||||
if (topClass.getClassInfo().equals(declClass)) {
|
||||
return declClass;
|
||||
ClassInfo curClass = mth.getParentClass().getClassInfo();
|
||||
if (superCallCls.equals(curClass)) {
|
||||
code.add("super");
|
||||
return;
|
||||
}
|
||||
// search call class
|
||||
ClassNode nextParent = useCls;
|
||||
do {
|
||||
ClassInfo nextClsInfo = nextParent.getClassInfo();
|
||||
if (nextClsInfo.equals(declClass)
|
||||
|| ArgType.isInstanceOf(mth.root(), nextClsInfo.getType(), declClass.getType())) {
|
||||
if (nextParent == useCls) {
|
||||
return null;
|
||||
}
|
||||
return nextClsInfo;
|
||||
}
|
||||
nextParent = nextParent.getParentClass();
|
||||
} while (nextParent != null && nextParent != topClass);
|
||||
// use custom class
|
||||
useClass(code, superCallCls);
|
||||
code.add(".super");
|
||||
}
|
||||
|
||||
// search failed, just return parent class
|
||||
return useCls.getParentClass().getClassInfo();
|
||||
/**
|
||||
* Search call class in super types of this
|
||||
* and all parent classes (needed for inlined synthetic calls)
|
||||
*/
|
||||
@Nullable
|
||||
private ClassInfo getClassForSuperCall(MethodInfo callMth) {
|
||||
ArgType declClsType = callMth.getDeclClass().getType();
|
||||
ClassNode parentNode = mth.getParentClass();
|
||||
while (true) {
|
||||
ClassInfo parentCls = parentNode.getClassInfo();
|
||||
if (ArgType.isInstanceOf(root, parentCls.getType(), declClsType)) {
|
||||
return parentCls;
|
||||
}
|
||||
ClassNode nextParent = parentNode.getParentClass();
|
||||
if (nextParent == parentNode) {
|
||||
// no parent, class not found
|
||||
return null;
|
||||
}
|
||||
parentNode = nextParent;
|
||||
}
|
||||
}
|
||||
|
||||
void generateMethodArguments(ICodeWriter code, BaseInvokeNode insn, int startArgNum,
|
||||
|
||||
@@ -11,7 +11,6 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import javax.tools.DiagnosticListener;
|
||||
import javax.tools.JavaCompiler;
|
||||
@@ -82,7 +81,7 @@ public class TestCompiler implements Closeable {
|
||||
arguments.addAll(options.getArguments());
|
||||
|
||||
DiagnosticListener<? super JavaFileObject> diagnostic =
|
||||
diagObj -> System.out.println("Compiler diagnostic: " + diagObj.getMessage(Locale.ROOT));
|
||||
diagObj -> System.out.println("Compiler diagnostic: " + diagObj);
|
||||
Writer out = new PrintWriter(System.out);
|
||||
CompilationTask compilerTask = compiler.getTask(out, fileManager, diagnostic, arguments, null, jfObjects);
|
||||
if (Boolean.FALSE.equals(compilerTask.call())) {
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package jadx.tests.integration.invoke;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jadx.tests.api.IntegrationTest;
|
||||
|
||||
import static jadx.tests.api.utils.assertj.JadxAssertions.assertThat;
|
||||
|
||||
public class TestSuperInvokeUnknown extends IntegrationTest {
|
||||
|
||||
public static class TestCls {
|
||||
public static class BaseClass {
|
||||
public int doSomething() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NestedClass extends BaseClass {
|
||||
@Override
|
||||
public int doSomething() {
|
||||
return super.doSomething();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
disableCompilation();
|
||||
noDebugInfo();
|
||||
assertThat(getClassNode(TestCls.NestedClass.class)) // BaseClass unknown
|
||||
.code()
|
||||
.containsOne("return super.doSomething();");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTopCls() {
|
||||
noDebugInfo();
|
||||
assertThat(getClassNode(TestCls.class))
|
||||
.code()
|
||||
.containsOne("return super.doSomething();");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user