[java-decompiler] IDEA-326015 Support common cases of deconstruction in switch

- collapse default case with assignment into default patterns

GitOrigin-RevId: b9458df252c6cb6d1215cbbf695c510779e2816f
This commit is contained in:
Mikhail Pyltsin
2023-11-17 11:27:41 +00:00
committed by intellij-monorepo-bot
parent 68665950d5
commit 51e1cc8b49
3 changed files with 259 additions and 214 deletions
@@ -847,7 +847,9 @@ public final class SwitchPatternHelper {
return edge.getDestination() instanceof DummyExitStatement ||
(doStatement == null && edge.closure == myRootSwitchStatement) ||
(doStatement != null && edge.closure == doStatement) ||
(doStatement != null && edge.closure instanceof DoStatement upperDoStatement && upperDoStatement.containsStatement(doStatement)) ||
(doStatement != null &&
edge.closure instanceof DoStatement upperDoStatement &&
upperDoStatement.containsStatement(doStatement)) ||
outsideCatch(edge, doStatement);
}
@@ -1165,6 +1167,7 @@ public final class SwitchPatternHelper {
private final SwitchStatement myRootSwitchStatement;
@NotNull
private final InvocationExprent myPreviousSelector;
@NotNull
private final Exprent myNewSwitchSelectorVariant;
@NotNull
private final List<TempVarAssignmentItem> myTempVarAssignments;
@@ -1225,12 +1228,80 @@ public final class SwitchPatternHelper {
if (headExprent != null) {
headExprent.replaceExprent(myPreviousSelector, myNewSwitchSelectorVariant);
}
if (hasPattern) {
remapWithPatterns(myRootSwitchStatement, myPatternContainer, myUppedDoStatement, myTempVarAssignments);
cleanDefault(myRootSwitchStatement);
}
Exprent oldSelector = myPreviousSelector.getInstance();
if (oldSelector instanceof VarExprent oldSelectorVarExprent &&
myNewSwitchSelectorVariant instanceof VarExprent newSwitchSelectorVarExprent) {
changeEverywhere(oldSelectorVarExprent, newSwitchSelectorVarExprent, myRootSwitchStatement.getCaseStatements());
changeDefaultToFullCase(myRootSwitchStatement, newSwitchSelectorVarExprent);
}
}
private static void changeDefaultToFullCase(@NotNull SwitchStatement myRoot, @NotNull VarExprent newSwitch) {
List<List<StatEdge>> edges = myRoot.getCaseEdges();
for (int i = 0; i < edges.size(); i++) {
List<StatEdge> statEdges = edges.get(i);
if (statEdges.size() == 1 && statEdges.get(0) == myRoot.getDefaultEdge()) {
Statement defaultStatement = myRoot.getCaseStatements().get(i);
Statement statementWithFirstAssignment = getStatementWithFirstAssignment(defaultStatement);
if (statementWithFirstAssignment!=null &&
statementWithFirstAssignment.getExprents() != null &&
!statementWithFirstAssignment.getExprents().isEmpty() &&
statementWithFirstAssignment.getExprents().get(0) instanceof AssignmentExprent assignmentExprent &&
assignmentExprent.getRight() != null &&
assignmentExprent.getLeft() instanceof VarExprent newVarExprent &&
assignmentExprent.getLeft().getExprType() != null &&
assignmentExprent.getRight().equals(newSwitch) &&
assignmentExprent.getLeft().getExprType().equals(newSwitch.getExprType())) {
statementWithFirstAssignment.getExprents().remove(0);
List<@Nullable Exprent> defaultValues = myRoot.getCaseValues().get(i);
defaultValues.clear();
defaultValues.add(newVarExprent);
myRoot.setUseCustomDefault();
break;
}
}
}
}
@Nullable
private static Statement getStatementWithFirstAssignment(@NotNull Statement statement) {
if (statement.getExprents() != null && !statement.getExprents().isEmpty()) {
if (statement.getExprents().get(0) instanceof AssignmentExprent) {
return statement;
}
else {
return null;
}
}
if (!statement.getStats().isEmpty()) {
return getStatementWithFirstAssignment(statement.getStats().get(0));
}
return null;
}
private static void changeEverywhere(@NotNull VarExprent oldVariant,
@NotNull VarExprent newVariant,
@NotNull List<Statement> statements) {
for (Statement statement : statements) {
if (statement.getExprents() != null) {
for (Exprent exprent : statement.getExprents()) {
for (Exprent nestedExprent : exprent.getAllExprents()) {
if (nestedExprent.equals(oldVariant)) {
exprent.replaceExprent(nestedExprent, newVariant);
}
}
}
}
for (Statement nestedStat : statement.getStats()) {
changeEverywhere(oldVariant, newVariant, nestedStat.getStats());
}
}
}
@Override
public Set<SwitchStatement> usedSwitch() {
return myUsedSwitchStatements;
@@ -35,6 +35,7 @@ public final class SwitchStatement extends Statement {
private StatEdge defaultEdge;
private Exprent headExprent;
private boolean canBeRule = false;
private boolean useCustomDefault = false;
private SwitchStatement() {
super(StatementType.SWITCH);
@@ -134,6 +135,10 @@ public final class SwitchStatement extends Statement {
return caseIndex + 1;
}
public void setUseCustomDefault() {
useCustomDefault = true;
}
@Nullable
public static Statement isHead(@NotNull Statement head) {
if (head.type == StatementType.BASIC_BLOCK && head.getLastBasicType() == StatementType.SWITCH) {
@@ -172,7 +177,7 @@ public final class SwitchStatement extends Statement {
List<StatEdge> edges = caseEdges.get(i);
List<Exprent> values = caseValues.get(i);
for (int j = 0; j < edges.size(); j++) {
if (edges.get(j) == defaultEdge) {
if (edges.get(j) == defaultEdge && !useCustomDefault) {
if (!canBeRule) {
buf.appendIndent(indent + 1).append("default:").appendLineSeparator();
}
@@ -20,33 +20,19 @@ public class TestSwitchSimpleReferencesJavac {
private static void testString2(String r2) {
switch (r2) {// 21
case "first":
System.out.println("1");// 23
break;// 24
case "second":
System.out.println("2");// 26
break;// 27
default:
String s = r2;// 28
System.out.println(s);// 29
case "first" -> System.out.println("1");// 23
case "second" -> System.out.println("2");// 26
case String s -> System.out.println(s);// 29
}
}// 31
private static void testString3(String r2) {
switch (r2) {// 34
case null:
System.out.println("null");// 42
break;// 43
case "first":
System.out.println("1");// 36
break;// 37
case "second":
System.out.println("2");// 39
break;// 40
default:
String s = r2;// 44
System.out.println(s);// 45
case null -> System.out.println("null");// 42
case "first" -> System.out.println("1");// 36
case "second" -> System.out.println("2");// 39
case String s -> System.out.println(s);// 45
}
}// 47
@@ -123,17 +109,10 @@ public class TestSwitchSimpleReferencesJavac {
private static void testEnum3(Numbers r2) {
switch (r2) {// 130
case null:
System.out.println("null");// 137
break;// 138
case FIRST:
break;
case SECOND:
System.out.println("2");// 134
break;// 135
default:
Numbers n = r2;// 139
System.out.println(n);// 140
case null -> System.out.println("null");// 137
case FIRST -> { }
case SECOND -> System.out.println("2");// 134
case Numbers n -> System.out.println(n);// 140
}
}// 142
@@ -187,154 +166,144 @@ class 'pkg/TestSwitchSimpleReferencesJavac' {
method 'testString2 (Ljava/lang/String;)V' {
10 21
2c 23
2f 23
31 23
34 24
37 26
3a 26
3c 26
3f 27
43 29
44 30
48 30
4b 33
2c 22
2f 22
31 22
37 23
3a 23
3c 23
44 24
48 24
4b 27
}
method 'testString3 (Ljava/lang/String;)V' {
b 36
24 41
27 41
29 41
2c 42
2f 44
32 44
34 44
37 45
3a 38
3d 38
3f 38
42 39
46 47
47 48
4b 48
4e 51
b 30
24 32
27 32
29 32
2f 33
32 33
34 33
3a 31
3d 31
3f 31
47 34
4b 34
4e 37
}
method 'testByte (Ljava/lang/Byte;)V' {
b 54
27 58
2a 58
2c 58
2f 59
32 62
35 62
37 62
3a 65
b 40
27 44
2a 44
2c 44
2f 45
32 48
35 48
37 48
3a 51
}
method 'testChar (Ljava/lang/Character;)V' {
b 68
24 71
27 71
29 71
2c 72
2f 75
32 75
34 75
37 78
b 54
24 57
27 57
29 57
2c 58
2f 61
32 61
34 61
37 64
}
method 'testInt (Ljava/lang/Integer;)V' {
b 81
27 85
2a 85
2c 85
2f 86
32 89
35 89
37 89
3a 92
b 67
27 71
2a 71
2c 71
2f 72
32 75
35 75
37 75
3a 78
}
method 'testInt2 (Ljava/lang/Integer;)V' {
1 95
4 95
23 97
26 97
28 97
2e 98
31 98
33 98
36 101
1 81
4 81
23 83
26 83
28 83
2e 84
31 84
33 84
36 87
}
method 'testEnum (Lpkg/TestSwitchSimpleReferencesJavac$Numbers;)V' {
b 104
28 108
29 108
2d 108
31 107
34 107
36 107
3c 105
3f 105
41 105
44 111
b 90
28 94
29 94
2d 94
31 93
34 93
36 93
3c 91
3f 91
41 91
44 97
}
method 'testEnum2 (Lpkg/TestSwitchSimpleReferencesJavac$Numbers;)V' {
b 114
28 118
29 118
2d 118
31 117
34 117
36 117
3c 115
3f 115
41 115
44 121
b 100
28 104
29 104
2d 104
31 103
34 103
36 103
3c 101
3f 101
41 101
44 107
}
method 'testEnum3 (Lpkg/TestSwitchSimpleReferencesJavac$Numbers;)V' {
b 124
27 131
2a 131
2c 131
2f 132
32 126
35 126
37 126
3a 127
3e 134
3f 135
43 135
46 138
b 110
27 113
2a 113
2c 113
32 111
35 111
37 111
3f 114
43 114
46 117
}
method 'testEnum4 (Lpkg/TestSwitchSimpleReferencesJavac$Numbers;)V' {
1 141
4 141
23 143
26 143
28 143
2e 144
31 144
33 144
36 147
1 120
4 120
23 122
26 122
28 122
2e 123
31 123
33 123
36 126
}
method 'testEnum5 (Lpkg/TestSwitchSimpleReferencesJavac$Numbers;)V' {
b 150
24 152
27 152
29 152
2c 153
2f 156
32 156
34 156
37 159
b 129
24 131
27 131
29 131
2c 132
2f 135
32 135
34 135
37 138
}
}
@@ -348,68 +317,65 @@ Lines mapping:
16 <-> 16
18 <-> 19
21 <-> 22
23 <-> 24
24 <-> 25
26 <-> 27
27 <-> 28
28 <-> 30
29 <-> 31
31 <-> 34
34 <-> 37
36 <-> 42
37 <-> 43
39 <-> 45
40 <-> 46
42 <-> 39
43 <-> 40
44 <-> 48
45 <-> 49
47 <-> 52
51 <-> 55
55 <-> 59
56 <-> 60
59 <-> 63
61 <-> 66
64 <-> 69
67 <-> 72
68 <-> 73
71 <-> 76
73 <-> 79
77 <-> 82
81 <-> 86
82 <-> 87
85 <-> 90
87 <-> 93
90 <-> 96
94 <-> 98
97 <-> 99
99 <-> 102
106 <-> 109
110 <-> 108
113 <-> 106
115 <-> 112
118 <-> 119
122 <-> 118
125 <-> 116
127 <-> 122
130 <-> 125
134 <-> 132
135 <-> 133
137 <-> 127
138 <-> 128
139 <-> 135
140 <-> 136
142 <-> 139
145 <-> 142
149 <-> 144
152 <-> 145
154 <-> 148
157 <-> 151
159 <-> 153
160 <-> 154
162 <-> 157
164 <-> 160
23 <-> 23
26 <-> 24
29 <-> 25
31 <-> 28
34 <-> 31
36 <-> 33
39 <-> 34
42 <-> 32
45 <-> 35
47 <-> 38
51 <-> 41
55 <-> 45
56 <-> 46
59 <-> 49
61 <-> 52
64 <-> 55
67 <-> 58
68 <-> 59
71 <-> 62
73 <-> 65
77 <-> 68
81 <-> 72
82 <-> 73
85 <-> 76
87 <-> 79
90 <-> 82
94 <-> 84
97 <-> 85
99 <-> 88
106 <-> 95
110 <-> 94
113 <-> 92
115 <-> 98
118 <-> 105
122 <-> 104
125 <-> 102
127 <-> 108
130 <-> 111
134 <-> 114
137 <-> 112
140 <-> 115
142 <-> 118
145 <-> 121
149 <-> 123
152 <-> 124
154 <-> 127
157 <-> 130
159 <-> 132
160 <-> 133
162 <-> 136
164 <-> 139
Not mapped:
24
27
28
37
40
43
44
53
79
92
@@ -419,5 +385,8 @@ Not mapped:
120
123
132
135
138
139
147
150