diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java index 50ea547da0fa..5996d82a33ad 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/DataFlowInspectionBase.java @@ -325,6 +325,7 @@ public abstract class DataFlowInspectionBase extends AbstractBaseJavaLocalInspec private void reportUnreachableSwitchBranches(Map labelReachability, ProblemsHolder holder) { if (labelReachability.isEmpty()) return; Set coveredSwitches = new HashSet<>(); + Map unreachableLabels = new HashMap<>(); for (Map.Entry entry : labelReachability.entrySet()) { if (entry.getValue() != ThreeState.YES) continue; @@ -338,6 +339,14 @@ public abstract class DataFlowInspectionBase extends AbstractBaseJavaLocalInspec .nonNull().flatArray(PsiCaseLabelElementList::getElements) .append(StreamEx.iterate(label, Objects::nonNull, l -> PsiTreeUtil.getPrevSiblingOfType(l, PsiCaseLabelElement.class)).skip(1)) .allMatch(l -> labelReachability.get(l) == ThreeState.NO)) { + + // Add all labels after always-reachable one as unreachable + StreamEx.iterate(labelStatement, Objects::nonNull, l -> PsiTreeUtil.getNextSiblingOfType(l, PsiSwitchLabelStatementBase.class)) + .remove(SwitchUtils::isDefaultLabel) + .skip(1).map(PsiSwitchLabelStatementBase::getCaseLabelElementList) + .nonNull().flatArray(PsiCaseLabelElementList::getElements) + .append(StreamEx.iterate(label, Objects::nonNull, l -> PsiTreeUtil.getNextSiblingOfType(l, PsiCaseLabelElement.class)).skip(1)) + .forEach(l -> unreachableLabels.put(l, switchBlock)); continue; } coveredSwitches.add(switchBlock); @@ -357,13 +366,16 @@ public abstract class DataFlowInspectionBase extends AbstractBaseJavaLocalInspec PsiSwitchLabelStatementBase labelStatement = Objects.requireNonNull(PsiImplUtil.getSwitchLabel(label)); PsiSwitchBlock switchBlock = labelStatement.getEnclosingSwitchBlock(); if (switchBlock == null || coveredSwitches.contains(switchBlock)) continue; + unreachableLabels.put(label, switchBlock); + } + unreachableLabels.forEach((label, switchBlock) -> { // duplicate case label is a compilation error so no need to highlight by the inspection Set suspiciousElements = SwitchBlockHighlightingModel.findSuspiciousLabelElements(switchBlock); if (!suspiciousElements.contains(label)) { holder.registerProblem(label, JavaAnalysisBundle.message("dataflow.message.unreachable.switch.label"), new DeleteSwitchLabelFix(label)); } - } + }); } private static boolean canRemoveUnreachableBranches(PsiSwitchLabelStatementBase labelStatement, PsiSwitchBlock statement) { diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/SwitchExpressions.java b/java/java-tests/testData/inspection/dataFlow/fixture/SwitchExpressions.java index 674033e73b42..de06fc7d05f3 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/SwitchExpressions.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/SwitchExpressions.java @@ -30,7 +30,7 @@ public class SwitchExpressionsJava12 { int i1 = switch(x) { case A -> 1; case B -> 2; - case C -> 3; + case C -> 3; }; if (i1 == 0) {} // exhaustive diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/SwitchStatementUnreachableBranches.java b/java/java-tests/testData/inspection/dataFlow/fixture/SwitchStatementUnreachableBranches.java new file mode 100644 index 000000000000..7b4642a4185b --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/SwitchStatementUnreachableBranches.java @@ -0,0 +1,18 @@ +class Test { + enum Colors { + RED, + GREEN, + BLUE, + YELLOW, + } + public Test(Colors color) { + if (color == Colors.RED || color == Colors.GREEN) { + switch (color) { + case RED -> System.out.println("Red"); + case BLUE -> System.out.println("Blue"); + case GREEN -> System.out.println("Green"); + case YELLOW -> System.out.println("Yellow"); + } + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection16Test.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection16Test.java index dda2d423f71b..ca4fc5f69861 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection16Test.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspection16Test.java @@ -19,6 +19,7 @@ public class DataFlowInspection16Test extends DataFlowInspectionTestCase { public void testInstanceOfPattern() { doTest(); } public void testSwitchStatements() { doTest(); } + public void testSwitchStatementUnreachableBranches() { doTest(); } public void testSwitchExpressions() { doTest(); } public void testSwitchExpressionsNullability() { doTest(); } public void testConstantDescAsWrapperSupertype() {