diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java index 469230aebb37..888942e834ae 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightControlFlowUtil.java @@ -91,7 +91,7 @@ public class HighlightControlFlowUtil { String description = JavaErrorMessages.message("unreachable.statement"); PsiElement keyword = null; if (unreachableStatement instanceof PsiIfStatement || - unreachableStatement instanceof PsiSwitchStatement || + unreachableStatement instanceof PsiSwitchBlock || unreachableStatement instanceof PsiLoopStatement) { keyword = unreachableStatement.getFirstChild(); } diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java index ededb93e5cdf..7714669d42ef 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowAnalyzer.java @@ -850,8 +850,48 @@ class ControlFlowAnalyzer extends JavaElementVisitor { finishElement(statement); } + @Override + public void visitSwitchLabeledRuleStatement(PsiSwitchLabeledRuleStatement statement) { + startElement(statement); + PsiExpressionList caseValues = statement.getCaseValues(); + + if (caseValues != null) { + for (PsiExpression caseValue : caseValues.getExpressions()) { + myStartStatementStack.pushStatement(caseValue, false); + myEndStatementStack.pushStatement(caseValue, false); + caseValue.accept(this); + myStartStatementStack.popStatement(); + myEndStatementStack.popStatement(); + } + } + + PsiStatement body = statement.getBody(); + if (body != null) { + body.accept(this); + } + + PsiSwitchBlock switchBlock = statement.getEnclosingSwitchBlock(); + if (switchBlock != null) { + Instruction instruction = + new GoToInstruction(0, BranchingInstruction.Role.END, PsiTreeUtil.isAncestor(switchBlock, myCodeFragment, true)); + myCurrentFlow.addInstruction(instruction); + addElementOffsetLater(switchBlock, false); + } + + finishElement(statement); + } + @Override public void visitSwitchStatement(PsiSwitchStatement statement) { + generateSwitchBlockInstructions(statement); + } + + @Override + public void visitSwitchExpression(PsiSwitchExpression expression) { + generateSwitchBlockInstructions(expression); + } + + public void generateSwitchBlockInstructions(PsiSwitchBlock statement) { startElement(statement); PsiExpression expr = statement.getExpression(); @@ -862,12 +902,12 @@ class ControlFlowAnalyzer extends JavaElementVisitor { PsiCodeBlock body = statement.getBody(); if (body != null) { PsiStatement[] statements = body.getStatements(); - PsiSwitchLabelStatement defaultLabel = null; + PsiSwitchLabelStatementBase defaultLabel = null; for (PsiStatement aStatement : statements) { ProgressManager.checkCanceled(); - if (aStatement instanceof PsiSwitchLabelStatement) { - if (((PsiSwitchLabelStatement)aStatement).isDefaultCase()) { - defaultLabel = (PsiSwitchLabelStatement)aStatement; + if (aStatement instanceof PsiSwitchLabelStatementBase) { + if (((PsiSwitchLabelStatementBase)aStatement).isDefaultCase()) { + defaultLabel = (PsiSwitchLabelStatementBase)aStatement; } Instruction instruction = new ConditionalGoToInstruction(0, expr); myCurrentFlow.addInstruction(instruction); diff --git a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java index 4fdbab174b2a..079e00fb06a9 100644 --- a/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java +++ b/java/java-psi-impl/src/com/intellij/psi/controlFlow/ControlFlowUtil.java @@ -1157,7 +1157,7 @@ public class ControlFlowUtil { return getUnreachableStatementParent(parent); } if (parent instanceof PsiIfStatement && ((PsiIfStatement)parent).getCondition() == expression || - parent instanceof PsiSwitchStatement && ((PsiSwitchStatement)parent).getExpression() == expression || + parent instanceof PsiSwitchBlock && ((PsiSwitchBlock)parent).getExpression() == expression || parent instanceof PsiWhileStatement && ((PsiWhileStatement)parent).getCondition() == expression || parent instanceof PsiForeachStatement && ((PsiForeachStatement)parent).getIteratedValue() == expression) { return parent; diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/EnhancedSwitchDefinitelyAssigned.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/EnhancedSwitchDefinitelyAssigned.java new file mode 100644 index 000000000000..e40f0685eee6 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/EnhancedSwitchDefinitelyAssigned.java @@ -0,0 +1,108 @@ +class C { + void finalVariableAssignedInAllBranches(int k) { + final String s; + switch (k) { + case 1 -> s = "a"; + case 2 -> s = "b"; + case 3, 4 -> s = "c"; + default -> s = "d"; + } + System.out.println(s); + } + + enum EnumAB {A, B} + void finalVariableAssignedInAllEnumConstantBranches(EnumAB ab) { + final int n; + switch (ab) { + case A -> n = 1; + case B -> n = 2; + } + System.out.println(n); + } + + void assignedInSomeBranches(String s) { + int n; + switch ((int)Math.random()) { + case 1 -> n = 1; + default -> {} + } + System.out.println(n); + } + + void finalVariableReassignedAfterSwitchStatement(int n) { + final String s; + switch (n) { + case 1 -> s = "a"; + default -> {} + } + s = "b"; + System.out.println(s); + } + + void finalVariableReassignedAfterSwitchExpression(int n) { + final String s; + String t = switch (n) { + case 1 -> s = "a"; + default -> ""; + }; + s = t; + System.out.println(s); + } + + void finalVariableReassignedInSwitchStatement(int n) { + final String s = "b"; + switch (n) { + case 1 -> s = "a"; + default -> {} + }; + System.out.println(s); + } + + void finalVariableReassignedInSwitchExpression(int n) { + final String s = "b"; + String string = switch (n) { + case 1 -> s = "a"; + default -> ""; + }; + System.out.println(s); + } + + + static class FinalFieldAssignedInSomeBranches { + final int n; + { + switch ((int)Math.random()) { + case 1 -> n = 1; + default -> {} + } + } + } + + static class FinalFieldAssignedInSomeBranchesNoDefault { + final int n; + { + switch ((int)Math.random()) { + case 1 -> n = 1; + case 0 -> n = 0; + } + } + } + + static class FinalFieldAssignedInAllBranches { + final int n; + { + switch ((int)Math.random()) { + case 1 -> n = 1; + default -> n = 0; + } + } + } + + static class FinalFieldInitializedWithswitchExpression { + final int n = + switch ((int)Math.random()) { + case 1 -> 1; + default -> 0; + }; + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/EnhancedSwitchUnreachable.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/EnhancedSwitchUnreachable.java new file mode 100644 index 000000000000..8702dc655179 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/advHighlighting12/EnhancedSwitchUnreachable.java @@ -0,0 +1,146 @@ +class C { + void alwaysThrow(String s) { + switch (s) { + case "a" -> throw new IllegalArgumentException(); + default -> throw new IllegalStateException(); + } + System.out.println(); + } + + void breakFromEndlessLoop() { + EndlessLoop: + for (;;) { + switch ((int)Math.random()) { + case 1 -> {break EndlessLoop;} + default -> throw new RuntimeException(); + } + } + System.out.println(); + } + + void continueEndlessLoop() { + EndlessLoop: + for (;;) { + switch ((int)Math.random()) { + case 1 -> {continue EndlessLoop;} + default -> throw new RuntimeException(); + } + } + System.out.println(); + } + + void endlessLoopsInAllBranches(String s) { + switch (s) { + case "a" -> { while(true); } + default -> { for(;;); } + } + System.out.println(); + } + + void endlessLoopInBranch(String s) { + switch (s) { + case "a" -> { while(true); } + default -> {} + }; + System.out.println(); + } + + /* todo + void endlessLoopInBranchWithValue(String arg) { + int result = switch (arg) { + case "one" -> { while(true); break 1;} + default -> 0; + }; + System.out.println(result); + } + */ + + static class FinalFieldSwitchExpression { + final String s = switch ((int)Math.random()) { + case 1 -> "a"; + default -> "?"; + }; + { + System.out.println(s); + } + } + + void finalVariableSwitchExpression(String s) { + final int n = switch (s) { + case "a" -> 1; + default -> 0; + }; + System.out.println(n); + } + + void notDefinitelyAssigned(String s) { + int n; + switch (s) { + case "a" -> n = 1; + } + System.out.println(n); + } + + int returnBeforeEnhancedSwitchStatement(String s) { + return 2; + switch(s) { + case "a" -> {return 1;} + default -> {return 0;} + } + } + + int returnBeforeSwitchExpressionInInitializer(String s) { + return 2; + int n = switch(s) { + case "a" -> 1; + default -> 0; + }; + } + + int returnBeforeSwitchExpressionInAssignment(String s) { + int n; + return 2; + n = switch(s) { + case "a": n= 1;break; + default: n= 0; + }; + } + + int returnSwitchExpression(String s) { + return switch(s) { + case "a" -> 1; + default -> 0; + }; + System.out.println(); + } + + static class SwitchExpressionReturnedFromTry { + int foo(String s) throws Exception { + try { + return switch (s) { + case "a" -> bar(1); + default -> bar(0); + }; + } finally { + System.out.println("b"); + } + System.out.println("c"); + } + int bar(int i) throws Exception { return i; } + } + + static class SwitchStatementReturnsFromTry { + int foo(String s) throws Exception { + try { + switch (s) { + case "a" -> { return bar(1); } + default -> { return bar(0); } + } + } finally { + System.out.println("b"); + } + System.out.println("c"); + } + int bar(int i) throws Exception { return i; } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightJava12HighlightingTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightJava12HighlightingTest.kt index 1421acc8d798..b8c9daf35335 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightJava12HighlightingTest.kt +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/LightJava12HighlightingTest.kt @@ -12,6 +12,8 @@ class LightJava12HighlightingTest : LightCodeInsightFixtureTestCase() { fun testSwitchExpressions() = doTest() fun testSwitchNumericPromotion() = doTest() fun testSimpleInferenceCases() = doTest() + fun testEnhancedSwitchDefinitelyAssigned() = doTest() + fun testEnhancedSwitchUnreachable() = doTest() private fun doTest() { myFixture.configureByFile(getTestName(false) + ".java")