Fix for IDEABKL-8006 IDE hangs when decompiling class which

is its own superclass

GitOrigin-RevId: 1fe14694ce69b135f2e3fe4cde84ce3d42997228
master
Maxim Degtyarev 4 years ago committed by intellij-monorepo-bot
parent e16fb8ef1d
commit 31cff62c94
  1. 15
      src/org/jetbrains/java/decompiler/main/collectors/ImportCollector.java
  2. 11
      test/org/jetbrains/java/decompiler/SingleClassesTest.java
  3. BIN
      testData/classes/pkg/TestInheritanceChainCycle.class
  4. 22
      testData/results/TestInheritanceChainCycle.dec
  5. 27
      testData/src/pkg/TestInheritanceChainCycle.jasm

@ -39,8 +39,10 @@ public class ImportCollector {
Map<String, StructClass> classes = DecompilerContext.getStructContext().getClasses(); Map<String, StructClass> classes = DecompilerContext.getStructContext().getClasses();
LinkedList<String> queue = new LinkedList<>(); LinkedList<String> queue = new LinkedList<>();
Set<StructClass> processedClasses = new HashSet<>();
StructClass currentClass = root.classStruct; StructClass currentClass = root.classStruct;
while (currentClass != null) { while (currentClass != null) {
processedClasses.add(currentClass);
if (currentClass.superClass != null) { if (currentClass.superClass != null) {
queue.add(currentClass.superClass.getString()); queue.add(currentClass.superClass.getString());
} }
@ -63,10 +65,17 @@ public class ImportCollector {
} }
// .. and traverse through parent. // .. and traverse through parent.
currentClass = !queue.isEmpty() ? classes.get(queue.removeFirst()) : null; do {
while (currentClass == null && !queue.isEmpty()) { currentClass = queue.isEmpty() ? null : classes.get(queue.removeFirst());
currentClass = classes.get(queue.removeFirst());
if (currentClass != null && processedClasses.contains(currentClass)) {
// Class already processed, skipping.
// This may be sign of circularity in the class hierarchy but in most cases this mean that same interface
// are listed as implemented several times in the class hierarchy.
currentClass = null;
} }
} while (currentClass == null && !queue.isEmpty());
} }
} }

@ -5,7 +5,9 @@ import org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler;
import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.Timeout;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -19,6 +21,13 @@ import static org.junit.Assert.assertTrue;
public class SingleClassesTest { public class SingleClassesTest {
private DecompilerTestFixture fixture; private DecompilerTestFixture fixture;
/*
* Set individual test duration time limit to 60 seconds.
* This will help us to test bugs hanging decompiler.
*/
@Rule
public Timeout globalTimeout = Timeout.seconds(60);
@Before @Before
public void setUp() throws IOException { public void setUp() throws IOException {
fixture = new DecompilerTestFixture(); fixture = new DecompilerTestFixture();
@ -135,6 +144,8 @@ public class SingleClassesTest {
@Test public void testRecordGenericVararg() { doTest("records/TestRecordGenericVararg"); } @Test public void testRecordGenericVararg() { doTest("records/TestRecordGenericVararg"); }
@Test public void testRecordAnno() { doTest("records/TestRecordAnno"); } @Test public void testRecordAnno() { doTest("records/TestRecordAnno"); }
@Test public void testInheritanceChainCycle() { doTest("pkg/TestInheritanceChainCycle"); }
private void doTest(String testFile, String... companionFiles) { private void doTest(String testFile, String... companionFiles) {
ConsoleDecompiler decompiler = fixture.getDecompiler(); ConsoleDecompiler decompiler = fixture.getDecompiler();

@ -0,0 +1,22 @@
package pkg;
public class TestInheritanceChainCycle extends TestInheritanceChainCycle {
public void printMessage() {
System.out.println("Hello, bug!");// 21 22 23
}// 24
}
class 'pkg/TestInheritanceChainCycle' {
method 'printMessage ()V' {
0 4
3 4
5 4
8 5
}
}
Lines mapping:
21 <-> 5
22 <-> 5
23 <-> 5
24 <-> 6

@ -0,0 +1,27 @@
/**
* This code can be assembled with <a href="https://wiki.openjdk.java.net/display/CodeTools/asmtools">asmtools</a>
* using <code>asmtools jasm -g *.jasm</code> command line.
*/
package pkg;
super public class TestInheritanceChainCycle
extends TestInheritanceChainCycle
version 52:0
{
public Method "<init>":"()V"
stack 1 locals 1
{
aload_0;
invokespecial Method java/lang/Object."<init>":"()V";
return;
}
public Method printMessage:"()V"
stack 2 locals 1
{
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
ldc String "Hello, bug!";
invokevirtual Method java/io/PrintStream.println:"(Ljava/lang/String;)V";
return;
}
} // end Class TestInheritanceChainCycle
Loading…
Cancel
Save