[java-decompiler] IDEA-291240 Fix switch over enum for Eclipse compiled bytecode

GitOrigin-RevId: fcbbc78a08fa3c0afe7bdad129c0427007f0c3d5
This commit is contained in:
Bart van Helvert
2022-03-30 19:53:12 +02:00
committed by intellij-monorepo-bot
parent e51e3ad1ef
commit 4c219967ed
8 changed files with 189 additions and 19 deletions

View File

@@ -86,21 +86,44 @@ public final class SwitchHelper {
private static Map<Exprent, Exprent> evaluateCaseLabelsToFieldsMapping(@NotNull List<List<Exprent>> caseValues,
@NotNull ArrayExprent array) {
Map<Exprent, Exprent> mapping = new HashMap<>(caseValues.size());
FieldExprent arrayField = (FieldExprent)array.getArray();
ClassesProcessor.ClassNode classNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(arrayField.getClassname());
if (classNode == null) return mapping;
MethodWrapper wrapper = classNode.getWrapper().getMethodWrapper(CodeConstants.CLINIT_NAME, "()V");
if (wrapper != null && wrapper.root != null) {
wrapper.getOrBuildGraph().iterateExprents(exprent -> {
if (exprent instanceof AssignmentExprent) {
AssignmentExprent assignment = (AssignmentExprent)exprent;
Exprent left = assignment.getLeft();
if (left.type == Exprent.EXPRENT_ARRAY && ((ArrayExprent)left).getArray().equals(arrayField)) {
mapping.put(assignment.getRight(), ((InvocationExprent)((ArrayExprent)left).getIndex()).getInstance());
if (array.getArray().type == Exprent.EXPRENT_FIELD) { // Javac compiler
FieldExprent arrayField = (FieldExprent)array.getArray();
ClassesProcessor.ClassNode classNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(arrayField.getClassname());
if (classNode == null) return mapping;
MethodWrapper wrapper = classNode.getWrapper().getMethodWrapper(CodeConstants.CLINIT_NAME, "()V");
if (wrapper != null && wrapper.root != null) {
wrapper.getOrBuildGraph().iterateExprents(exprent -> {
if (exprent instanceof AssignmentExprent) {
AssignmentExprent assignment = (AssignmentExprent)exprent;
Exprent left = assignment.getLeft();
if (left.type == Exprent.EXPRENT_ARRAY && ((ArrayExprent)left).getArray().equals(arrayField)) {
mapping.put(assignment.getRight(), ((InvocationExprent)((ArrayExprent)left).getIndex()).getInstance());
}
}
}
return 0;
});
return 0;
});
}
} else if (array.getArray().type == Exprent.EXPRENT_INVOCATION) { // Eclipse compiler
InvocationExprent invocationExprent = (InvocationExprent) array.getArray();
ClassesProcessor.ClassNode classNode = DecompilerContext.getClassProcessor().getMapRootClasses().get(invocationExprent.getClassName());
if (classNode == null) return mapping;
MethodWrapper wrapper = classNode.getWrapper().getMethodWrapper(invocationExprent.getName(), "()[I");
if (wrapper != null && wrapper.root != null) {
wrapper.getOrBuildGraph().iterateExprents(exprent -> {
if (exprent instanceof AssignmentExprent) {
AssignmentExprent assignment = (AssignmentExprent)exprent;
Exprent left = assignment.getLeft();
if (left.type == Exprent.EXPRENT_ARRAY) {
Exprent indexExprent = ((ArrayExprent)left).getIndex();
if (indexExprent.type == Exprent.EXPRENT_INVOCATION && ((InvocationExprent) indexExprent).getName().equals("ordinal")) {
mapping.put(assignment.getRight(), ((InvocationExprent)((ArrayExprent)left).getIndex()).getInstance());
}
}
}
return 0;
});
}
}
return mapping;
}
@@ -134,9 +157,12 @@ public final class SwitchHelper {
if (!(exprent instanceof ArrayExprent)) return false;
Exprent field = ((ArrayExprent)exprent).getArray();
Exprent index = ((ArrayExprent)exprent).getIndex();
return field instanceof FieldExprent &&
(((FieldExprent)field).getName().startsWith("$SwitchMap") ||
(index instanceof InvocationExprent && ((InvocationExprent)index).getName().equals("ordinal")));
boolean isJavacEnumArray = field instanceof FieldExprent &&
(((FieldExprent)field).getName().startsWith("$SwitchMap") ||
(index instanceof InvocationExprent && ((InvocationExprent)index).getName().equals("ordinal")));
boolean isEclipseEnumArray = field instanceof InvocationExprent &&
((InvocationExprent)field).getName().startsWith("$SWITCH_TABLE");
return isJavacEnumArray || isEclipseEnumArray;
}
static void removeTempVariableDeclarations(@NotNull Map<VarExprent, Statement> tempVarAssignments) {

View File

@@ -120,6 +120,7 @@ public class SingleClassesTest {
"pkg/SharedName2", "pkg/SharedName3", "pkg/SharedName4", "pkg/NonSharedName",
"pkg/TestClashNameParent", "ext/TestClashNameParent","pkg/TestClashNameIface", "ext/TestClashNameIface"); }
@Test public void testSwitchOnEnum() { doTest("pkg/TestSwitchOnEnum");}
@Test public void testSwitchOnEnumEclipse() { doTest("pkg/TestSwitchOnEnumEclipse"); }
@Test public void testVarArgCalls() { doTest("pkg/TestVarArgCalls"); }
@Test public void testLambdaParams() { doTest("pkg/TestLambdaParams"); }
@Test public void testInterfaceMethods() { doTest("pkg/TestInterfaceMethods"); }
@@ -215,8 +216,6 @@ public class SingleClassesTest {
@Test public void testNestedType() { doTest("pkg/NestedType"); }
@Test public void testInheritanceChainCycle() { doTest("pkg/TestInheritanceChainCycle"); }
@Test public void testDynamicConstantPoolEntry() { doTest("java11/TestDynamicConstantPoolEntry"); }
@Test public void testInstanceofWithPattern() {
doTest("patterns/TestInstanceofWithPattern");
}

View File

@@ -0,0 +1,101 @@
package pkg;
import java.util.concurrent.TimeUnit;
public class TestSwitchOnEnumEclipse {
int myInt;
public int testSOE(TimeUnit t) {
switch (t) {// 11
case MICROSECONDS:
return 2;// 13
case MILLISECONDS:
default:
return 0;// 17
case SECONDS:
return 1;// 15
}
}
static class Example {
void test(A a, B b) {
switch (a) {// 27
case A1:
System.out.println("A1");// 29
break;// 30
case A2:
System.out.println("A2");// 32
}
switch (b) {// 35
case B1:
System.out.println("B1");// 37
break;// 38
case B2:
System.out.println("B2");// 40
}
}// 43
static enum A {
A1,
A2;
}
static enum B {
B1,
B2;
}
}
}
class 'pkg/TestSwitchOnEnumEclipse' {
method 'testSOE (Ljava/util/concurrent/TimeUnit;)I' {
8 8
24 10
25 10
26 15
27 15
28 13
29 13
}
}
class 'pkg/TestSwitchOnEnumEclipse$Example' {
method 'test (Lpkg/TestSwitchOnEnumEclipse$Example$A;Lpkg/TestSwitchOnEnumEclipse$Example$B;)V' {
8 21
20 23
23 23
25 23
28 24
2b 26
2e 26
30 26
3b 29
50 31
53 31
55 31
58 32
5b 34
5e 34
60 34
63 37
}
}
Lines mapping:
11 <-> 9
13 <-> 11
15 <-> 16
17 <-> 14
27 <-> 22
29 <-> 24
30 <-> 25
32 <-> 27
35 <-> 30
37 <-> 32
38 <-> 33
40 <-> 35
43 <-> 38
Not mapped:
34

View File

@@ -0,0 +1,44 @@
package pkg;
import java.util.concurrent.TimeUnit;
public class TestSwitchOnEnumEclipse {
int myInt;
public int testSOE(TimeUnit t) {
switch (t) {
case MICROSECONDS:
return 2;
case SECONDS:
return 1;
}
return 0;
}
static class Example {
enum A { A1, A2 }
enum B { B1, B2 }
void test(A a, B b) {
switch (a) {
case A1:
System.out.println("A1");
break;
case A2:
System.out.println("A2");
break;
}
switch (b) {
case B1:
System.out.println("B1");
break;
case B2:
System.out.println("B2");
break;
}
}
}
}