IDEA-203119 Unwrap switch statement: support expressions

This commit is contained in:
Tagir Valeev
2018-11-28 18:57:40 +07:00
parent 81c9810bde
commit 0d96d61986
21 changed files with 158 additions and 36 deletions

View File

@@ -316,9 +316,18 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool
PsiSwitchBlock statement = labelStatement.getEnclosingSwitchBlock();
if (statement == null) continue;
if (PsiTreeUtil.getChildrenOfTypeAsList(statement.getBody(), PsiSwitchLabelStatementBase.class).size() == 1 &&
Objects.requireNonNull(labelStatement.getCaseValues()).getExpressionCount() == 1 &&
(!(statement instanceof PsiSwitchStatement) || BreakConverter.from((PsiSwitchStatement)statement) == null)) {
continue;
Objects.requireNonNull(labelStatement.getCaseValues()).getExpressionCount() == 1) {
boolean canUnwrap;
if (statement instanceof PsiSwitchStatement) {
canUnwrap = BreakConverter.from(statement) != null;
}
else {
canUnwrap = labelStatement instanceof PsiSwitchLabeledRuleStatement &&
((PsiSwitchLabeledRuleStatement)labelStatement).getBody() instanceof PsiExpressionStatement;
}
if (!canUnwrap) {
continue;
}
}
if (!StreamEx.iterate(labelStatement, Objects::nonNull, l -> PsiTreeUtil.getPrevSiblingOfType(l, PsiSwitchLabelStatementBase.class))
.skip(1).map(PsiSwitchLabelStatementBase::getCaseValues)

View File

@@ -2,7 +2,6 @@
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.BlockUtils;
import com.intellij.codeInspection.CommonQuickFixBundle;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.dataFlow.fix.DeleteSwitchLabelFix;
@@ -24,7 +23,7 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix {
@NotNull
@Override
public String getFamilyName() {
return CommonQuickFixBundle.message("fix.unwrap.statement", PsiKeyword.SWITCH);
return "Remove unreachable branches";
}
@Override
@@ -33,21 +32,39 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix {
if (label == null) return;
PsiSwitchLabelStatementBase labelStatement = PsiImplUtil.getSwitchLabel(label);
if (labelStatement == null) return;
PsiSwitchStatement statement = labelStatement.getEnclosingSwitchStatement();
if (statement == null) return;
List<PsiSwitchLabelStatementBase> labels = PsiTreeUtil.getChildrenOfTypeAsList(statement.getBody(), PsiSwitchLabelStatementBase.class);
PsiSwitchBlock block = labelStatement.getEnclosingSwitchBlock();
if (block == null) return;
List<PsiSwitchLabelStatementBase> labels = PsiTreeUtil.getChildrenOfTypeAsList(block.getBody(), PsiSwitchLabelStatementBase.class);
for (PsiSwitchLabelStatementBase otherLabel : labels) {
if (otherLabel != labelStatement) {
DeleteSwitchLabelFix.deleteLabel(otherLabel);
}
}
BreakConverter converter = BreakConverter.from(statement);
if (converter == null) return;
converter.process();
unwrap(labelStatement, statement);
for (PsiExpression expression : Objects.requireNonNull(labelStatement.getCaseValues()).getExpressions()) {
if (expression != label) {
new CommentTracker().deleteAndRestoreComments(expression);
}
}
tryUnwrap(labelStatement, block);
}
private static void unwrap(PsiSwitchLabelStatementBase labelStatement, PsiSwitchStatement statement) {
public void tryUnwrap(PsiSwitchLabelStatementBase labelStatement, PsiSwitchBlock block) {
if (block instanceof PsiSwitchStatement) {
BreakConverter converter = BreakConverter.from(block);
if (converter == null) return;
converter.process();
unwrapStatement(labelStatement, (PsiSwitchStatement)block);
} else {
if (labelStatement instanceof PsiSwitchLabeledRuleStatement) {
PsiSwitchLabeledRuleStatement ruleStatement = (PsiSwitchLabeledRuleStatement)labelStatement;
if (ruleStatement.getBody() instanceof PsiExpressionStatement) {
new CommentTracker().replaceAndRestoreComments(block, ((PsiExpressionStatement)ruleStatement.getBody()).getExpression());
}
}
}
}
private static void unwrapStatement(PsiSwitchLabelStatementBase labelStatement, PsiSwitchStatement statement) {
PsiCodeBlock block = statement.getBody();
PsiStatement body =
labelStatement instanceof PsiSwitchLabeledRuleStatement ? ((PsiSwitchLabeledRuleStatement)labelStatement).getBody() : null;

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff() {
System.out.println("one");

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -0,0 +1,20 @@
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {
//1
//2
//3
//4
//5
//6
//7
//other
System.out.println("five-ten-fifteen");
}
}
public static void main(String[] args) {
fff();
}
}

View File

@@ -0,0 +1,24 @@
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {
System.out.println(switch (x) {
//1
//2
//3
//4
case 5 -> {
System.out.println("something");
break "five-ten-fifteen"; //5
}
//6
//7
//other
});
}
}
public static void main(String[] args) {
fff();
}
}

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff() {
switch ("one") {

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -0,0 +1,21 @@
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {
System.out.println(switch (x) {
case 1 -> "one"; //1
case 2 -> "two"; //2
case 3 -> "three"; //3
case 4 -> "four"; //4
case 0, <caret>5, 10 -> "five-ten-fifteen"; //5
case 6 -> "six"; //6
case 7 -> "seven"; //7
default -> "and more"; //other
});
}
}
public static void main(String[] args) {
fff();
}
}

View File

@@ -0,0 +1,24 @@
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {
System.out.println(switch (x) {
case 1 -> "one"; //1
case 2 -> "two"; //2
case 3 -> "three"; //3
case 4 -> "four"; //4
case 0, <caret>5, 10 -> {
System.out.println("something");
break "five-ten-fifteen"; //5
}
case 6 -> "six"; //6
case 7 -> "seven"; //7
default -> "and more"; //other
});
}
}
public static void main(String[] args) {
fff();
}
}

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -1,4 +1,4 @@
// "Unwrap 'switch' statement" "true"
// "Remove unreachable branches" "true"
class Main {
static void fff(int x) {
if (x == 5) {

View File

@@ -15,10 +15,10 @@ import java.util.List;
* is unwrapped.
*/
public class BreakConverter {
private final PsiSwitchStatement mySwitchStatement;
private final PsiSwitchBlock mySwitchStatement;
private final String myReplacement;
public BreakConverter(PsiSwitchStatement switchStatement, String replacement) {
public BreakConverter(PsiSwitchBlock switchStatement, String replacement) {
mySwitchStatement = switchStatement;
myReplacement = replacement;
}
@@ -42,7 +42,7 @@ public class BreakConverter {
@Override
public void visitBreakStatement(PsiBreakStatement statement) {
super.visitBreakStatement(statement);
if (statement.findExitedStatement() == mySwitchStatement) {
if (statement.findExitedElement() == mySwitchStatement) {
breaks.add(statement);
}
}
@@ -92,8 +92,15 @@ public class BreakConverter {
return null;
}
private static boolean isRemovable(PsiSwitchStatement switchStatement, PsiStatement statement) {
private static boolean isRemovable(PsiSwitchBlock switchStatement, PsiStatement statement) {
if (switchStatement instanceof PsiSwitchExpression) {
// any breaks inside switch expressions are not convertible
return false;
}
PsiElement parent = statement.getParent();
if (parent instanceof PsiSwitchLabeledRuleStatement) {
return true;
}
if (parent instanceof PsiIfStatement || parent instanceof PsiLabeledStatement) {
return isRemovable(switchStatement, (PsiStatement)parent);
}
@@ -106,18 +113,18 @@ public class BreakConverter {
}
}
if (nextStatement instanceof PsiSwitchLabelStatement) {
return (((PsiSwitchLabelStatement)nextStatement).getEnclosingSwitchStatement() == switchStatement &&
return (((PsiSwitchLabelStatement)nextStatement).getEnclosingSwitchBlock() == switchStatement &&
!ControlFlowUtils.statementMayCompleteNormally(statement));
}
if (nextStatement instanceof PsiBreakStatement) {
return ((PsiBreakStatement)nextStatement).findExitedStatement() == switchStatement;
return ((PsiBreakStatement)nextStatement).findExitedElement() == switchStatement;
}
return false;
}
@Nullable
public static BreakConverter from(PsiSwitchStatement switchStatement) {
String replacement = getReplacement(switchStatement);
public static BreakConverter from(PsiSwitchBlock switchStatement) {
String replacement = switchStatement instanceof PsiSwitchStatement ? getReplacement((PsiStatement)switchStatement) : null;
if (replacement == null) {
class Visitor extends JavaRecursiveElementWalkingVisitor {
boolean hasNonRemovableBreak;
@@ -125,7 +132,7 @@ public class BreakConverter {
@Override
public void visitBreakStatement(PsiBreakStatement statement) {
super.visitBreakStatement(statement);
if (statement.findExitedStatement() == switchStatement && !isRemovable(switchStatement, statement)) {
if (statement.findExitedElement() == switchStatement && !isRemovable(switchStatement, statement)) {
hasNonRemovableBreak = true;
stopWalking();
}