mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-239116 Switch expression without any results is not highlighted as erroneous
GitOrigin-RevId: 66580d3aa4a95e1fdb32b1a3131544560c9c432a
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5d753d02bd
commit
b3ba7b6783
+52
-9
@@ -2108,31 +2108,74 @@ public class HighlightUtil {
|
||||
PsiCodeBlock switchBody = switchExpression.getBody();
|
||||
if (switchBody != null) {
|
||||
PsiStatement lastStatement = PsiTreeUtil.getPrevSiblingOfType(switchBody.getRBrace(), PsiStatement.class);
|
||||
boolean hasResult = false;
|
||||
if (lastStatement instanceof PsiSwitchLabeledRuleStatement) {
|
||||
Collection<HighlightInfo> results = new ArrayList<>();
|
||||
for (PsiSwitchLabeledRuleStatement rule = (PsiSwitchLabeledRuleStatement)lastStatement;
|
||||
rule != null;
|
||||
rule = PsiTreeUtil.getPrevSiblingOfType(rule, PsiSwitchLabeledRuleStatement.class)) {
|
||||
PsiStatement ruleBody = rule.getBody();
|
||||
if (ruleBody instanceof PsiExpressionStatement) {
|
||||
hasResult = true;
|
||||
}
|
||||
// the expression and throw statements are fine, only the block statement could be an issue
|
||||
if (ruleBody instanceof PsiBlockStatement && ControlFlowUtils.statementMayCompleteNormally(ruleBody)) {
|
||||
PsiElement target = ObjectUtils.notNull(ObjectUtils.tryCast(rule.getFirstChild(), PsiKeyword.class), rule);
|
||||
String message = JavaErrorBundle.message("switch.expr.rule.should.produce.result");
|
||||
results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(target).descriptionAndTooltip(message).create());
|
||||
if (ruleBody instanceof PsiBlockStatement) {
|
||||
if (ControlFlowUtils.statementMayCompleteNormally(ruleBody)) {
|
||||
PsiElement target = ObjectUtils.notNull(ObjectUtils.tryCast(rule.getFirstChild(), PsiKeyword.class), rule);
|
||||
String message = JavaErrorBundle.message("switch.expr.rule.should.produce.result");
|
||||
results.add(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(target).descriptionAndTooltip(message).create());
|
||||
}
|
||||
else if (!hasResult && hasYield(switchExpression, ruleBody)) {
|
||||
hasResult = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
if (!results.isEmpty()) {
|
||||
return results;
|
||||
}
|
||||
} else {
|
||||
// previous statements may have no result as well, but in that case they fall through to the last one, which needs to be checked anyway
|
||||
if (lastStatement != null && ControlFlowUtils.statementMayCompleteNormally(lastStatement)) {
|
||||
PsiElement target = ObjectUtils.notNull(ObjectUtils.tryCast(switchExpression.getFirstChild(), PsiKeyword.class), switchExpression);
|
||||
String message = JavaErrorBundle.message("switch.expr.should.produce.result");
|
||||
return Collections.singletonList(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(target).descriptionAndTooltip(message).create());
|
||||
}
|
||||
hasResult = hasYield(switchExpression, switchBody);
|
||||
}
|
||||
// previous statements may have no result as well, but in that case they fall through to the last one, which needs to be checked anyway
|
||||
if (lastStatement != null && ControlFlowUtils.statementMayCompleteNormally(lastStatement)) {
|
||||
if (!hasResult) {
|
||||
PsiElement target = ObjectUtils.notNull(ObjectUtils.tryCast(switchExpression.getFirstChild(), PsiKeyword.class), switchExpression);
|
||||
String message = JavaErrorBundle.message("switch.expr.should.produce.result");
|
||||
return Collections.singletonList(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(target).descriptionAndTooltip(message).create());
|
||||
return Collections.singletonList(HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(target)
|
||||
.descriptionAndTooltip(JavaErrorBundle.message("switch.expr.no.result")).create());
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
private static boolean hasYield(@NotNull PsiSwitchExpression switchExpression, PsiElement scope) {
|
||||
class YieldFinder extends JavaRecursiveElementWalkingVisitor {
|
||||
boolean hasYield = false;
|
||||
|
||||
@Override
|
||||
public void visitYieldStatement(PsiYieldStatement statement) {
|
||||
if (statement.findEnclosingExpression() == switchExpression) {
|
||||
hasYield = true;
|
||||
stopWalking();
|
||||
}
|
||||
}
|
||||
|
||||
// do not go inside to save time: declarations cannot contain yield that points to outer switch expression
|
||||
@Override
|
||||
public void visitDeclarationStatement(PsiDeclarationStatement statement) {}
|
||||
|
||||
// do not go inside to save time: expressions cannot contain yield that points to outer switch expression
|
||||
@Override
|
||||
public void visitExpression(PsiExpression expression) {}
|
||||
}
|
||||
YieldFinder finder = new YieldFinder();
|
||||
scope.accept(finder);
|
||||
return finder.hasYield;
|
||||
}
|
||||
|
||||
/**
|
||||
* See JLS 8.3.2.3.
|
||||
*/
|
||||
|
||||
@@ -241,6 +241,7 @@ duplicate.switch.label=Duplicate label ''{0}''
|
||||
switch.colon.expected.after.case.label=':' expected
|
||||
switch.expr.empty='switch' expression does not have any case clauses
|
||||
switch.expr.incomplete='switch' expression does not cover all possible input values
|
||||
switch.expr.no.result=Switch expression does not have any result expressions
|
||||
switch.expr.should.produce.result=Switch expression should produce result in all execution paths
|
||||
switch.expr.rule.should.produce.result=Switch expression rule should produce result in all execution paths
|
||||
|
||||
|
||||
+2
-2
@@ -28,13 +28,13 @@ class C {
|
||||
}
|
||||
|
||||
void defaultBranchAlwaysThrows(int n) {
|
||||
String s = switch (n) {
|
||||
String s = <error descr="Switch expression does not have any result expressions">switch</error> (n) {
|
||||
default: throw new RuntimeException();
|
||||
};
|
||||
}
|
||||
|
||||
void defaultRuleAlwaysThrows(int n) {
|
||||
String s = switch (n) {
|
||||
String s = <error descr="Switch expression does not have any result expressions">switch</error> (n) {
|
||||
default -> throw new RuntimeException();
|
||||
};
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
class Test {
|
||||
void test() {
|
||||
int i = <error descr="Switch expression does not have any result expressions">switch</error>(0) {
|
||||
default -> throw new NullPointerException();
|
||||
};
|
||||
}
|
||||
|
||||
void test2() {
|
||||
int i = <error descr="Switch expression does not have any result expressions">switch</error>(0) {
|
||||
case 0 -> {while(true);}
|
||||
case 1 -> {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
default -> throw new NullPointerException();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
+1
@@ -11,6 +11,7 @@ class JavaSwitchExpressionsHighlightingTest : LightJavaCodeInsightFixtureTestCas
|
||||
|
||||
fun testEnhancedSwitchStatements() = doTest()
|
||||
fun testSwitchExpressions() = doTest()
|
||||
fun testSwitchExpressionsNoResult() = doTest()
|
||||
fun testSwitchExpressionsEnumResolve() = doTest()
|
||||
fun testSwitchNumericPromotion() = doTest()
|
||||
fun testSimpleInferenceCases() = doTest()
|
||||
|
||||
Reference in New Issue
Block a user