mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Support of enhanced Java 12 switch statements in DFA (IDEA-202132, no expressions yet)
This commit is contained in:
+38
-21
@@ -401,9 +401,11 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
|
||||
@Override public void visitBreakStatement(PsiBreakStatement statement) {
|
||||
startElement(statement);
|
||||
jumpOut(statement.findExitedStatement());
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
PsiStatement exitedStatement = statement.findExitedStatement();
|
||||
|
||||
private void jumpOut(PsiElement exitedStatement) {
|
||||
if (exitedStatement != null && PsiTreeUtil.isAncestor(myCodeFragment, exitedStatement, false)) {
|
||||
controlTransfer(new InstructionTransfer(getEndOffset(exitedStatement), getVariablesInside(exitedStatement)),
|
||||
getTrapsInsideElement(exitedStatement));
|
||||
@@ -411,8 +413,6 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
// Jumping out of analyzed code fragment
|
||||
controlTransfer(ReturnTransfer.INSTANCE, getTrapsInsideElement(myCodeFragment));
|
||||
}
|
||||
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
private void controlTransfer(@NotNull TransferTarget target, FList<Trap> traps) {
|
||||
@@ -844,6 +844,19 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSwitchLabeledRuleStatement(PsiSwitchLabeledRuleStatement statement) {
|
||||
startElement(statement);
|
||||
PsiStatement body = statement.getBody();
|
||||
if (body != null) {
|
||||
body.accept(this);
|
||||
if (!(body instanceof PsiThrowStatement)) {
|
||||
jumpOut(statement.getEnclosingSwitchBlock());
|
||||
}
|
||||
}
|
||||
finishElement(statement);
|
||||
}
|
||||
|
||||
@Override public void visitSwitchStatement(PsiSwitchStatement switchStmt) {
|
||||
startElement(switchStmt);
|
||||
PsiExpression caseExpression = switchStmt.getExpression();
|
||||
@@ -889,34 +902,38 @@ public class ControlFlowAnalyzer extends JavaElementVisitor {
|
||||
|
||||
if (body != null) {
|
||||
PsiStatement[] statements = body.getStatements();
|
||||
PsiSwitchLabelStatement defaultLabel = null;
|
||||
ControlFlowOffset offset = null;
|
||||
PsiSwitchLabelStatementBase defaultLabel = null;
|
||||
for (PsiStatement statement : statements) {
|
||||
if (statement instanceof PsiSwitchLabelStatement) {
|
||||
PsiSwitchLabelStatement psiLabelStatement = (PsiSwitchLabelStatement)statement;
|
||||
if (statement instanceof PsiSwitchLabelStatementBase) {
|
||||
PsiSwitchLabelStatementBase psiLabelStatement = (PsiSwitchLabelStatementBase)statement;
|
||||
if (psiLabelStatement.isDefaultCase()) {
|
||||
defaultLabel = psiLabelStatement;
|
||||
}
|
||||
else {
|
||||
try {
|
||||
offset = getStartOffset(statement);
|
||||
PsiExpression caseValue = psiLabelStatement.getCaseValue();
|
||||
PsiExpressionList values = psiLabelStatement.getCaseValues();
|
||||
if (values != null) {
|
||||
for (PsiExpression caseValue : values.getExpressions()) {
|
||||
|
||||
if (enumValues != null && caseValue instanceof PsiReferenceExpression) {
|
||||
//noinspection SuspiciousMethodCalls
|
||||
enumValues.remove(((PsiReferenceExpression)caseValue).resolve());
|
||||
}
|
||||
if (enumValues != null && caseValue instanceof PsiReferenceExpression) {
|
||||
//noinspection SuspiciousMethodCalls
|
||||
enumValues.remove(((PsiReferenceExpression)caseValue).resolve());
|
||||
}
|
||||
|
||||
if (caseValue != null && expressionValue != null) {
|
||||
addInstruction(new PushInstruction(expressionValue, null));
|
||||
caseValue.accept(this);
|
||||
addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, PsiType.BOOLEAN));
|
||||
}
|
||||
else {
|
||||
pushUnknown();
|
||||
}
|
||||
if (caseValue != null && expressionValue != null) {
|
||||
addInstruction(new PushInstruction(expressionValue, null));
|
||||
caseValue.accept(this);
|
||||
addInstruction(new BinopInstruction(JavaTokenType.EQEQ, null, PsiType.BOOLEAN));
|
||||
}
|
||||
else {
|
||||
pushUnknown();
|
||||
}
|
||||
|
||||
addInstruction(new ConditionalGotoInstruction(offset, false, statement));
|
||||
addInstruction(new ConditionalGotoInstruction(offset, false, caseValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
|
||||
+19
-12
@@ -305,25 +305,30 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool
|
||||
}
|
||||
|
||||
private void reportUnreachableSwitchBranches(Set<Instruction> trueSet, Set<Instruction> falseSet, ProblemsHolder holder) {
|
||||
Set<PsiSwitchStatement> coveredSwitches = new HashSet<>();
|
||||
Set<PsiSwitchLabelStatement> trueLabels = StreamEx.of(trueSet).select(BranchingInstruction.class)
|
||||
.map(BranchingInstruction::getPsiAnchor).select(PsiSwitchLabelStatement.class).toSet();
|
||||
Set<PsiSwitchLabelStatement> falseLabels = StreamEx.of(falseSet).select(BranchingInstruction.class)
|
||||
.map(BranchingInstruction::getPsiAnchor).select(PsiSwitchLabelStatement.class).toSet();
|
||||
Set<PsiSwitchBlock> coveredSwitches = new HashSet<>();
|
||||
Set<PsiExpression> trueLabels = StreamEx.of(trueSet).select(ConditionalGotoInstruction.class)
|
||||
.map(ConditionalGotoInstruction::getPsiAnchor).select(PsiExpression.class)
|
||||
.filter(e -> SwitchUtils.getLabelStatementForLabel(e) != null).toSet();
|
||||
Set<PsiExpression> falseLabels = StreamEx.of(falseSet).select(ConditionalGotoInstruction.class)
|
||||
.map(ConditionalGotoInstruction::getPsiAnchor).select(PsiExpression.class)
|
||||
.filter(e -> SwitchUtils.getLabelStatementForLabel(e) != null).toSet();
|
||||
|
||||
for (PsiSwitchLabelStatement label : trueLabels) {
|
||||
PsiSwitchStatement statement = label.getEnclosingSwitchStatement();
|
||||
for (PsiExpression label : trueLabels) {
|
||||
PsiSwitchLabelStatementBase labelStatement = Objects.requireNonNull(SwitchUtils.getLabelStatementForLabel(label));
|
||||
PsiSwitchBlock statement = labelStatement.getEnclosingSwitchBlock();
|
||||
if (statement == null) continue;
|
||||
if (!StreamEx.iterate(label, Objects::nonNull, l -> PsiTreeUtil.getPrevSiblingOfType(l, PsiSwitchLabelStatement.class))
|
||||
.skip(1).allMatch(falseLabels::contains)) {
|
||||
if (!StreamEx.iterate(labelStatement, Objects::nonNull, l -> PsiTreeUtil.getPrevSiblingOfType(l, PsiSwitchLabelStatement.class))
|
||||
.skip(1).map(PsiSwitchLabelStatementBase::getCaseValues)
|
||||
.nonNull().flatArray(PsiExpressionList::getExpressions).allMatch(falseLabels::contains)) {
|
||||
continue;
|
||||
}
|
||||
coveredSwitches.add(statement);
|
||||
holder.registerProblem(label, InspectionsBundle.message("dataflow.message.only.switch.label"),
|
||||
createUnwrapSwitchLabelFix());
|
||||
}
|
||||
for (PsiSwitchLabelStatement label : falseLabels) {
|
||||
if (!coveredSwitches.contains(label.getEnclosingSwitchStatement())) {
|
||||
for (PsiExpression label : falseLabels) {
|
||||
PsiSwitchLabelStatementBase labelStatement = Objects.requireNonNull(SwitchUtils.getLabelStatementForLabel(label));
|
||||
if (!coveredSwitches.contains(labelStatement.getEnclosingSwitchBlock())) {
|
||||
holder.registerProblem(label, InspectionsBundle.message("dataflow.message.unreachable.switch.label"),
|
||||
new DeleteSwitchLabelFix(label));
|
||||
}
|
||||
@@ -724,7 +729,9 @@ public class DataFlowInspectionBase extends AbstractBaseJavaLocalInspectionTool
|
||||
reportConstantBoolean(holder, psiAnchor, reportedAnchors, true);
|
||||
}
|
||||
}
|
||||
else if (psiAnchor != null && !(psiAnchor instanceof PsiSwitchLabelStatement) && !isFlagCheck(psiAnchor)) {
|
||||
else if (psiAnchor != null &&
|
||||
(!(psiAnchor instanceof PsiExpression) || SwitchUtils.getLabelStatementForLabel((PsiExpression)psiAnchor) == null) &&
|
||||
!isFlagCheck(psiAnchor)) {
|
||||
boolean evaluatesToTrue = trueSet.contains(instruction);
|
||||
final PsiElement parent = psiAnchor.getParent();
|
||||
if (parent instanceof PsiAssignmentExpression &&
|
||||
|
||||
+20
-8
@@ -11,6 +11,7 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.ControlFlowUtils;
|
||||
import com.siyeh.ig.psiutils.SwitchUtils;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -24,12 +25,16 @@ public class DeleteSwitchLabelFix implements LocalQuickFix {
|
||||
private final String myName;
|
||||
private final boolean myBranch;
|
||||
|
||||
public DeleteSwitchLabelFix(PsiSwitchLabelStatement label) {
|
||||
myName = Objects.requireNonNull(label.getCaseValue()).getText();
|
||||
myBranch = shouldRemoveBranch(label);
|
||||
public DeleteSwitchLabelFix(@NotNull PsiExpression label) {
|
||||
myName = label.getText();
|
||||
PsiSwitchLabelStatementBase labelStatement = Objects.requireNonNull(SwitchUtils.getLabelStatementForLabel(label));
|
||||
PsiExpressionList values = labelStatement.getCaseValues();
|
||||
boolean multiple = values != null && values.getExpressionCount() > 1;
|
||||
myBranch = !multiple && shouldRemoveBranch(labelStatement);
|
||||
}
|
||||
|
||||
private static boolean shouldRemoveBranch(PsiSwitchLabelStatement label) {
|
||||
private static boolean shouldRemoveBranch(PsiSwitchLabelStatementBase label) {
|
||||
if (label instanceof PsiSwitchLabeledRuleStatement) return true;
|
||||
PsiStatement nextStatement = PsiTreeUtil.getNextSiblingOfType(label, PsiStatement.class);
|
||||
if (nextStatement instanceof PsiSwitchLabelStatement) {
|
||||
return false;
|
||||
@@ -56,16 +61,23 @@ public class DeleteSwitchLabelFix implements LocalQuickFix {
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiSwitchLabelStatement label = PsiTreeUtil.getNonStrictParentOfType(descriptor.getStartElement(), PsiSwitchLabelStatement.class);
|
||||
PsiExpression expression = ObjectUtils.tryCast(descriptor.getStartElement(), PsiExpression.class);
|
||||
if (expression == null) return;
|
||||
PsiSwitchLabelStatementBase label = SwitchUtils.getLabelStatementForLabel(expression);
|
||||
if (label == null) return;
|
||||
deleteLabel(label);
|
||||
PsiExpressionList values = label.getCaseValues();
|
||||
if (values != null && values.getExpressionCount() == 1) {
|
||||
deleteLabel(label);
|
||||
} else {
|
||||
new CommentTracker().deleteAndRestoreComments(expression);
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteLabel(PsiSwitchLabelStatement label) {
|
||||
public static void deleteLabel(PsiSwitchLabelStatementBase label) {
|
||||
if (shouldRemoveBranch(label)) {
|
||||
PsiCodeBlock scope = ObjectUtils.tryCast(label.getParent(), PsiCodeBlock.class);
|
||||
if (scope == null) return;
|
||||
PsiSwitchLabelStatement nextLabel = PsiTreeUtil.getNextSiblingOfType(label, PsiSwitchLabelStatement.class);
|
||||
PsiSwitchLabelStatementBase nextLabel = PsiTreeUtil.getNextSiblingOfType(label, PsiSwitchLabelStatementBase.class);
|
||||
PsiElement stopAt = nextLabel == null ? scope.getRBrace() : nextLabel;
|
||||
while(true) {
|
||||
PsiStatement next = PsiTreeUtil.getNextSiblingOfType(nextLabel, PsiStatement.class);
|
||||
|
||||
+8
-7
@@ -6,12 +6,11 @@ import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.dataFlow.fix.DeleteSwitchLabelFix;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiKeyword;
|
||||
import com.intellij.psi.PsiSwitchLabelStatement;
|
||||
import com.intellij.psi.PsiSwitchStatement;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.SwitchUtils;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -27,17 +26,19 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix {
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
PsiSwitchLabelStatement label = ObjectUtils.tryCast(descriptor.getStartElement(), PsiSwitchLabelStatement.class);
|
||||
PsiExpression label = ObjectUtils.tryCast(descriptor.getStartElement(), PsiExpression.class);
|
||||
if (label == null) return;
|
||||
PsiSwitchStatement statement = label.getEnclosingSwitchStatement();
|
||||
PsiSwitchLabelStatementBase labelStatement = SwitchUtils.getLabelStatementForLabel(label);
|
||||
if (labelStatement == null) return;
|
||||
PsiSwitchStatement statement = labelStatement.getEnclosingSwitchStatement();
|
||||
if (statement == null) return;
|
||||
List<PsiSwitchLabelStatement> labels = PsiTreeUtil.getChildrenOfTypeAsList(statement.getBody(), PsiSwitchLabelStatement.class);
|
||||
for (PsiSwitchLabelStatement otherLabel : labels) {
|
||||
if (otherLabel != label) {
|
||||
if (otherLabel != labelStatement) {
|
||||
DeleteSwitchLabelFix.deleteLabel(otherLabel);
|
||||
}
|
||||
}
|
||||
new CommentTracker().replaceAndRestoreComments(label, "default:");
|
||||
new CommentTracker().replaceAndRestoreComments(labelStatement, "default:");
|
||||
ConvertSwitchToIfIntention.doProcessIntention(statement); // will not create 'if', just unwrap, because only default label is left
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Remove switch label '0-/*x*/1'" "true"
|
||||
class Main {
|
||||
static void fff(int x) {
|
||||
if (x > 0) {
|
||||
switch (x) {
|
||||
case 1, 3 /*x*/: System.out.println("one"); //1
|
||||
case 2: System.out.println("two"); //2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
// "Remove switch branch '-/*x*/1'" "true"
|
||||
class Main {
|
||||
static void fff(int x) {
|
||||
if (x > 0) {
|
||||
switch (x) {
|
||||
case 2 -> System.out.println("two"); //2
|
||||
//1
|
||||
/*x*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// "Unwrap 'switch' statement" "true"
|
||||
class Main {
|
||||
static void fff(int x) {
|
||||
if (x == 5) {
|
||||
//1
|
||||
//2
|
||||
//3
|
||||
//4
|
||||
System.out.println("five-ten-fifteen"); //5
|
||||
System.out.println("six"); //6
|
||||
System.out.println("seven"); //7
|
||||
//other
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
fff();
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Remove switch label '0-/*x*/1'" "true"
|
||||
class Main {
|
||||
static void fff(int x) {
|
||||
if (x > 0) {
|
||||
switch (x) {
|
||||
case 1, 3, 0-<caret>/*x*/1: System.out.println("one"); //1
|
||||
case 2: System.out.println("two"); //2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// "Remove switch branch '-/*x*/1'" "true"
|
||||
class Main {
|
||||
static void fff(int x) {
|
||||
if (x > 0) {
|
||||
switch (x) {
|
||||
case 2 -> System.out.println("two"); //2
|
||||
case -<caret>/*x*/1 -> System.out.println("one"); //1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ class Main {
|
||||
void t() {
|
||||
int i = 5;
|
||||
switch(i) {
|
||||
c<caret>ase 1: case 3: // Apply 'Fix all problems in the file'
|
||||
case <caret>1: case 3: // Apply 'Fix all problems in the file'
|
||||
System.out.println("odd");
|
||||
break;
|
||||
}
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// "Unwrap 'switch' statement" "true"
|
||||
class Main {
|
||||
static void fff(int x) {
|
||||
if (x == 5) {
|
||||
switch (x) {
|
||||
case 1: System.out.println("one"); //1
|
||||
case 2: System.out.println("two"); //2
|
||||
case 3: System.out.println("three"); //3
|
||||
case 4: System.out.println("four"); //4
|
||||
case 0, <caret>5, 10: System.out.println("five-ten-fifteen"); //5
|
||||
case 6: System.out.println("six"); //6
|
||||
case 7: System.out.println("seven"); //7
|
||||
break;
|
||||
default: System.out.println("and more"); //other
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
fff();
|
||||
}
|
||||
}
|
||||
@@ -37,8 +37,8 @@ public class aaa {
|
||||
//System.exit(0);
|
||||
|
||||
switch(i) {
|
||||
<warning descr="Switch label 'case 1:' is unreachable">case 1:</warning> System.out.println("1 not reachable"); break;
|
||||
<warning descr="Switch label 'case 2:' is unreachable">case 2:</warning> System.out.println("2 not reachable"); break;
|
||||
case <warning descr="Switch label '1' is unreachable">1</warning>: System.out.println("1 not reachable"); break;
|
||||
case <warning descr="Switch label '2' is unreachable">2</warning>: System.out.println("2 not reachable"); break;
|
||||
case 6: System.out.println("6 reachable"); break;
|
||||
case 5: System.out.println("5 reachable"); break;
|
||||
default: System.out.println("Default not reachable"); break;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
class Scratch {
|
||||
public static void main(String[] args) {
|
||||
switch("ping") {
|
||||
<warning descr="Switch label 'case \"ping\":' is the only reachable in the whole switch">case "ping":</warning>
|
||||
case <warning descr="Switch label '\"ping\"' is the only reachable in the whole switch">"ping"</warning>:
|
||||
System.out.println("ping");
|
||||
break;
|
||||
case "pong":
|
||||
@@ -17,7 +17,7 @@ class Scratch {
|
||||
case "pong":
|
||||
System.out.println("pong");
|
||||
break;
|
||||
<warning descr="Switch label 'case \"ping\":' is the only reachable in the whole switch">case "ping":</warning>
|
||||
case <warning descr="Switch label '\"ping\"' is the only reachable in the whole switch">"ping"</warning>:
|
||||
System.out.println("ping");
|
||||
break;
|
||||
case "simple":
|
||||
@@ -33,7 +33,7 @@ class Scratch {
|
||||
case "simple":
|
||||
System.out.println("simple");
|
||||
break;
|
||||
<warning descr="Switch label 'case \"ping\":' is the only reachable in the whole switch">case "ping":</warning>
|
||||
case <warning descr="Switch label '\"ping\"' is the only reachable in the whole switch">"ping"</warning>:
|
||||
System.out.println("ping");
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -160,7 +160,7 @@ public class LongRangeBasics {
|
||||
public void testBitwiseAnd() {
|
||||
int state = getState() & 0xF;
|
||||
switch (state) {
|
||||
<warning descr="Switch label 'case 24:' is unreachable">case 24:</warning>
|
||||
case <warning descr="Switch label '24' is unreachable">24</warning>:
|
||||
System.out.println("Impossible");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ class StringEquality {
|
||||
switch(s) {
|
||||
case "bar":
|
||||
case "baz":
|
||||
<warning descr="Switch label 'case \"foo\":' is unreachable">case "foo":</warning>
|
||||
case <warning descr="Switch label '\"foo\"' is unreachable">"foo"</warning>:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ class InspectionTest {
|
||||
System.out.println("It's b");break;
|
||||
case C:
|
||||
System.out.println("It's c");break;
|
||||
<warning descr="Switch label 'case A:' is unreachable">case A:</warning>
|
||||
case <warning descr="Switch label 'A' is unreachable">A</warning>:
|
||||
System.out.println("It's a again");break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
public class SwitchStatementsJava12 {
|
||||
void testMultiLabel(int x) {
|
||||
if(x > 0) {
|
||||
switch (x) {
|
||||
case 1, 2, <warning descr="Switch label '-1' is unreachable">-1</warning>:
|
||||
System.out.println("oops");
|
||||
break;
|
||||
}
|
||||
switch (x) {
|
||||
case 1, 2, <warning descr="Switch label '-1' is unreachable">-1</warning> -> {
|
||||
System.out.println("oops");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testThrowRule(int x) {
|
||||
switch (x) {
|
||||
case 0 -> throw new IllegalArgumentException();
|
||||
default -> System.out.println(<warning descr="Condition 'x == 0' is always 'false'">x == 0</warning>);
|
||||
}
|
||||
if (<warning descr="Condition 'x == 0' is always 'false'">x == 0</warning>) System.out.println("impossible");
|
||||
}
|
||||
|
||||
void testFallthrough(int x) {
|
||||
switch (x) {
|
||||
case 0 -> System.out.println(x);
|
||||
case 1 -> {
|
||||
System.out.println(<warning descr="Condition 'x == 0' is always 'false'">x == 0</warning>);
|
||||
System.out.println(<warning descr="Condition 'x == 1' is always 'true'">x == 1</warning>);
|
||||
}
|
||||
}
|
||||
switch (x) {
|
||||
case 0: System.out.println(x);
|
||||
case 1: {
|
||||
System.out.println(x == 0);
|
||||
System.out.println(x == 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.java.codeInspection;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.roots.ContentEntry;
|
||||
import com.intellij.openapi.roots.LanguageLevelModuleExtension;
|
||||
import com.intellij.openapi.roots.ModifiableRootModel;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.testFramework.IdeaTestUtil;
|
||||
import com.intellij.testFramework.LightProjectDescriptor;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
import com.intellij.testFramework.fixtures.DefaultLightProjectDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class DataFlowInspection12Test extends DataFlowInspectionTestCase {
|
||||
private static final DefaultLightProjectDescriptor PROJECT_DESCRIPTOR = new DefaultLightProjectDescriptor() {
|
||||
@Override
|
||||
public Sdk getSdk() {
|
||||
return PsiTestUtil.addJdkAnnotations(IdeaTestUtil.getMockJdk(LanguageLevel.JDK_12_PREVIEW.toJavaVersion()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureModule(@NotNull Module module, @NotNull ModifiableRootModel model, @NotNull ContentEntry contentEntry) {
|
||||
model.getModuleExtension(LanguageLevelModuleExtension.class).setLanguageLevel(LanguageLevel.JDK_12_PREVIEW);
|
||||
}
|
||||
};
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected LightProjectDescriptor getProjectDescriptor() {
|
||||
return PROJECT_DESCRIPTOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return JavaTestUtil.getJavaTestDataPath() + "/inspection/dataFlow/fixture/";
|
||||
}
|
||||
|
||||
public void testSwitchStatementsJava12() { doTest(); }
|
||||
}
|
||||
@@ -16,7 +16,7 @@ import java.util.regex.Pattern;
|
||||
* A TestCase for single PsiFile being opened in Editor conversion. See configureXXX and checkResultXXX method docs.
|
||||
*/
|
||||
public abstract class LightCodeInsightTestCase extends LightPlatformCodeInsightTestCase {
|
||||
private static final Pattern JDK_SELECT_PATTERN = Pattern.compile("Java([\\d.]+)(\\.java)?$");
|
||||
private static final Pattern JDK_SELECT_PATTERN = Pattern.compile("Java([\\d.]+)(Preview)?(\\.java)?$");
|
||||
|
||||
public static JavaPsiFacadeEx getJavaFacade() {
|
||||
return JavaPsiFacadeEx.getInstanceEx(ourProject);
|
||||
@@ -42,6 +42,9 @@ public abstract class LightCodeInsightTestCase extends LightPlatformCodeInsightT
|
||||
if (matcher.find()) {
|
||||
LanguageLevel level = LanguageLevel.parse(matcher.group(1));
|
||||
if (level != null) {
|
||||
if (!matcher.group(2).isEmpty()) {
|
||||
level = LanguageLevel.valueOf(level + "_PREVIEW");
|
||||
}
|
||||
return level;
|
||||
}
|
||||
}
|
||||
|
||||
+17
@@ -23,6 +23,8 @@ import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -239,6 +241,21 @@ public class SwitchUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns enclosing label statement for given label expression
|
||||
*
|
||||
* @param expression switch label expression
|
||||
* @return enclosing label statement or null if given expression is not a label statement
|
||||
*/
|
||||
@Contract("null -> null")
|
||||
@Nullable
|
||||
public static PsiSwitchLabelStatementBase getLabelStatementForLabel(PsiExpression expression) {
|
||||
if (expression == null) return null;
|
||||
PsiElement parent = expression.getParent();
|
||||
if (!(parent instanceof PsiExpressionList)) return null;
|
||||
return ObjectUtils.tryCast(parent.getParent(), PsiSwitchLabelStatementBase.class);
|
||||
}
|
||||
|
||||
private static boolean checkForLabel(String name, PsiElement ancestor) {
|
||||
final LabelSearchVisitor visitor = new LabelSearchVisitor(name);
|
||||
ancestor.accept(visitor);
|
||||
|
||||
Reference in New Issue
Block a user