mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java-highlighting] Illegal case label combination
— Improve message errors — Highlighting for default label not allowed here IDEA-309572 IDEA-311508 IJ-CR-100879 GitOrigin-RevId: ec31413e87c30697c58ae0444425a68d838c7210
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a6c25ebd9c
commit
3f67f5fe7e
+76
-37
@@ -504,6 +504,7 @@ public class SwitchBlockHighlightingModel {
|
||||
void checkSwitchLabelValues(@NotNull HighlightInfoHolder holder) {
|
||||
PsiCodeBlock body = myBlock.getBody();
|
||||
if (body == null) return;
|
||||
boolean java20plus = PsiUtil.getLanguageLevel(holder.getProject()).isAtLeast(LanguageLevel.JDK_20_PREVIEW);
|
||||
MultiMap<Object, PsiElement> elementsToCheckDuplicates = new MultiMap<>();
|
||||
List<List<PsiSwitchLabelStatementBase>> elementsToCheckFallThroughLegality = new SmartList<>();
|
||||
List<PsiElement> elementsToCheckDominance = new ArrayList<>();
|
||||
@@ -537,8 +538,10 @@ public class SwitchBlockHighlightingModel {
|
||||
checkDuplicates(elementsToCheckDuplicates, holder);
|
||||
if (holder.hasErrorResults()) return;
|
||||
|
||||
if (PsiUtil.getLanguageLevel(holder.getProject()).isAtLeast(LanguageLevel.JDK_20_PREVIEW)) {
|
||||
checkFallThroughFromToPatternJava20(elementsToCheckFallThroughLegality, holder);
|
||||
if (java20plus) {
|
||||
HashSet<PsiElement> alreadyFallThroughElements = new HashSet<>();
|
||||
checkFallThroughFromToPatternJava20(elementsToCheckFallThroughLegality, holder, alreadyFallThroughElements);
|
||||
checkFallThroughInSwitchLabels(elementsToCheckFallThroughLegality, holder, alreadyFallThroughElements);
|
||||
}
|
||||
else {
|
||||
checkFallThroughFromToPattern(elementsToCheckFallThroughLegality, holder);
|
||||
@@ -817,51 +820,87 @@ public class SwitchBlockHighlightingModel {
|
||||
checkFallThroughInSwitchLabels(switchBlockGroup, holder, alreadyFallThroughElements);
|
||||
}
|
||||
|
||||
private static void checkFallThroughFromToPatternJava20(@NotNull List<? extends List<PsiSwitchLabelStatementBase>> switchBlockGroup,
|
||||
@NotNull HighlightInfoHolder holder) {
|
||||
private static void checkFallThroughFromToPatternJava20(@NotNull List<List<PsiSwitchLabelStatementBase>> switchBlockGroup,
|
||||
@NotNull HighlightInfoHolder holder,
|
||||
@NotNull Set<PsiElement> alreadyFallThroughElements) {
|
||||
if (switchBlockGroup.isEmpty()) return;
|
||||
Set<PsiElement> alreadyFallThroughElements = new HashSet<>();
|
||||
for (var switchLabel : switchBlockGroup) {
|
||||
boolean canPrecedingStatementCompleteNormally = false;
|
||||
for (PsiSwitchLabelStatementBase switchLabelElement : switchLabel) {
|
||||
PsiCaseLabelElementList labelElementList = switchLabelElement.getCaseLabelElementList();
|
||||
if (labelElementList == null) continue;
|
||||
boolean existPattern = false;
|
||||
boolean existsConst = false;
|
||||
boolean existsNull = false;
|
||||
if (labelElementList == null || labelElementList.getElementCount() == 0) continue;
|
||||
PsiCaseLabelElement[] elements = labelElementList.getElements();
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
PsiCaseLabelElement currentElement = elements[i];
|
||||
if (isInCaseNullDefaultLabel(currentElement)) continue;
|
||||
if (ExpressionUtils.isNullLiteral(currentElement) && i != 0 && !existPattern ||
|
||||
existsConst && !isConstantLabelElement(currentElement) ||
|
||||
existsNull) {
|
||||
addIllegalFallThroughError(currentElement, "invalid.case.label.combination", holder, alreadyFallThroughElements);
|
||||
break;
|
||||
final PsiCaseLabelElement first = elements[0];
|
||||
CaseLabelCombinationProblem problem = checkCaseLabelCombination(elements);
|
||||
if (problem != null) {
|
||||
addIllegalFallThroughError(problem.element(), problem.message(), holder, alreadyFallThroughElements);
|
||||
}
|
||||
else if (JavaPsiPatternUtil.containsPatternVariable(first)) {
|
||||
if (PsiTreeUtil.skipWhitespacesAndCommentsForward(switchLabelElement) instanceof PsiSwitchLabelStatement) {
|
||||
addIllegalFallThroughError(first, "multiple.switch.labels", holder, alreadyFallThroughElements);
|
||||
}
|
||||
if (JavaPsiPatternUtil.containsPatternVariable(currentElement)) {
|
||||
if (existPattern || PsiTreeUtil.skipWhitespacesAndCommentsForward(switchLabelElement) instanceof PsiSwitchLabelStatement) {
|
||||
addIllegalFallThroughError(currentElement, "switch.illegal.fall.through.from", holder, alreadyFallThroughElements);
|
||||
break;
|
||||
}
|
||||
else if (canPrecedingStatementCompleteNormally ||
|
||||
PsiTreeUtil.skipWhitespacesAndCommentsBackward(switchLabelElement) instanceof PsiSwitchLabelStatement) {
|
||||
addIllegalFallThroughError(currentElement, "switch.illegal.fall.through.to", holder, alreadyFallThroughElements);
|
||||
break;
|
||||
}
|
||||
else if (PsiTreeUtil.skipWhitespacesAndCommentsBackward(switchLabelElement) instanceof PsiSwitchLabelStatement) {
|
||||
addIllegalFallThroughError(first, "multiple.switch.labels", holder, alreadyFallThroughElements);
|
||||
}
|
||||
if (existPattern) {
|
||||
addIllegalFallThroughError(currentElement, "switch.illegal.fall.through.from", holder, alreadyFallThroughElements);
|
||||
break;
|
||||
}
|
||||
existPattern = currentElement instanceof PsiPattern || currentElement instanceof PsiPatternGuard;
|
||||
existsConst |= isConstantLabelElement(currentElement);
|
||||
existsNull = ExpressionUtils.isNullLiteral(currentElement);
|
||||
}
|
||||
canPrecedingStatementCompleteNormally = true;
|
||||
}
|
||||
}
|
||||
checkFallThroughInSwitchLabels(switchBlockGroup, holder, alreadyFallThroughElements);
|
||||
}
|
||||
|
||||
private record CaseLabelCombinationProblem(@NotNull PsiCaseLabelElement element,
|
||||
@NotNull @PropertyKey(resourceBundle = JavaErrorBundle.BUNDLE) String message) {
|
||||
}
|
||||
|
||||
private static @Nullable CaseLabelCombinationProblem checkCaseLabelCombination(PsiCaseLabelElement[] elements) {
|
||||
PsiCaseLabelElement firstElement = elements[0];
|
||||
if (elements.length == 1) {
|
||||
if (firstElement instanceof PsiDefaultCaseLabelElement) {
|
||||
return new CaseLabelCombinationProblem(firstElement, "default.label.must.not.contains.case.keyword");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (elements.length == 2) {
|
||||
if (firstElement instanceof PsiDefaultCaseLabelElement && ExpressionUtils.isNullLiteral(elements[1])) {
|
||||
return new CaseLabelCombinationProblem(firstElement, "invalid.default.and.null.order");
|
||||
}
|
||||
if (ExpressionUtils.isNullLiteral(firstElement) && elements[1] instanceof PsiDefaultCaseLabelElement) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
int defaultIndex = -1;
|
||||
int nullIndex = -1;
|
||||
int patternIndex = -1;
|
||||
|
||||
for (int i = 0; i < elements.length; i++) {
|
||||
if (elements[i] instanceof PsiDefaultCaseLabelElement) {
|
||||
defaultIndex = i;
|
||||
break;
|
||||
}
|
||||
else if (ExpressionUtils.isNullLiteral(elements[i])) {
|
||||
nullIndex = i;
|
||||
break;
|
||||
}
|
||||
else if (elements[i] instanceof PsiPattern || elements[i] instanceof PsiPatternGuard) {
|
||||
patternIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (defaultIndex != -1) {
|
||||
return new CaseLabelCombinationProblem(elements[defaultIndex], "default.label.not.allowed.here");
|
||||
}
|
||||
if (nullIndex != -1) {
|
||||
return new CaseLabelCombinationProblem(elements[nullIndex], "null.label.not.allowed.here");
|
||||
}
|
||||
if (firstElement instanceof PsiExpression && patternIndex != -1) {
|
||||
return new CaseLabelCombinationProblem(elements[patternIndex], "invalid.case.label.combination.constants.and.patterns");
|
||||
}
|
||||
else if (firstElement instanceof PsiPattern || firstElement instanceof PsiPatternGuard) {
|
||||
if (elements[1] instanceof PsiPattern || elements[1] instanceof PsiPatternGuard) {
|
||||
return new CaseLabelCombinationProblem(elements[1], "invalid.case.label.combination.several.patterns");
|
||||
}
|
||||
return new CaseLabelCombinationProblem(elements[1], "invalid.case.label.combination.constants.and.patterns");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void addIllegalFallThroughError(@NotNull PsiElement element,
|
||||
|
||||
@@ -236,8 +236,13 @@ valid.switch.selector.types=byte, char, short or int
|
||||
valid.switch.17.selector.types=char, byte, short, int, Character, Byte, Short, Integer, String, or an enum
|
||||
switch.illegal.fall.through.from=Illegal fall-through from a pattern
|
||||
switch.illegal.fall.through.to=Illegal fall-through to a pattern
|
||||
invalid.case.label.combination=Invalid case label combination
|
||||
default.label.not.allowed.here=Default label is not allowed here
|
||||
invalid.case.label.combination.constants.and.patterns=Invalid case label combination: A case label must consist of either a list of case constants or a single case pattern
|
||||
invalid.case.label.combination.several.patterns=Invalid case label combination: A case label must not consist of more than one case pattern
|
||||
null.label.not.allowed.here=Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'
|
||||
default.label.must.not.contains.case.keyword=The label for the default case must only use the 'default' keyword, without 'case'
|
||||
invalid.default.and.null.order=Invalid case label order: 'null' must be first and 'default' must be second
|
||||
default.label.not.allowed.here=Default label not allowed here: 'default' can only be used as a single case label or paired only with 'null'
|
||||
multiple.switch.labels=Multiple switch labels are permitted for a switch labeled statement group only if none of them declare any pattern variables
|
||||
switch.dominance.of.preceding.label=Label is dominated by a preceding case label ''{0}''
|
||||
switch.unconditional.pattern.and.default.exist='switch' has both an unconditional pattern and a default label
|
||||
switch.class.or.array.type.expected=class or array
|
||||
|
||||
+63
-20
@@ -4,8 +4,8 @@ public class Main {
|
||||
|
||||
void test0(Object obj) {
|
||||
switch (obj) {
|
||||
case <error descr="Illegal fall-through from a pattern">String s</error>:
|
||||
case <error descr="Illegal fall-through to a pattern">Integer i</error>:
|
||||
case <error descr="Multiple switch labels are permitted for a switch labeled statement group only if none of them declare any pattern variables">String s</error>:
|
||||
case <error descr="Multiple switch labels are permitted for a switch labeled statement group only if none of them declare any pattern variables">Integer i</error>:
|
||||
System.out.println(i + 1);
|
||||
default:
|
||||
}
|
||||
@@ -26,7 +26,7 @@ public class Main {
|
||||
|
||||
void test2(Object obj) {
|
||||
switch (obj) {
|
||||
case <error descr="Illegal fall-through from a pattern">String s</error>:
|
||||
case <error descr="Multiple switch labels are permitted for a switch labeled statement group only if none of them declare any pattern variables">String s</error>:
|
||||
case R():
|
||||
case S():
|
||||
System.out.println(42);
|
||||
@@ -37,7 +37,7 @@ public class Main {
|
||||
|
||||
void test3(Object obj) {
|
||||
switch (obj) {
|
||||
case <error descr="Illegal fall-through from a pattern">String s</error>:
|
||||
case <error descr="Multiple switch labels are permitted for a switch labeled statement group only if none of them declare any pattern variables">String s</error>:
|
||||
default:
|
||||
System.out.println(42);
|
||||
}
|
||||
@@ -46,7 +46,7 @@ public class Main {
|
||||
void test4(Object obj) {
|
||||
switch (obj) {
|
||||
case null:
|
||||
case <error descr="Illegal fall-through to a pattern">String s</error>:
|
||||
case <error descr="Multiple switch labels are permitted for a switch labeled statement group only if none of them declare any pattern variables">String s</error>:
|
||||
System.out.println(s);
|
||||
default:
|
||||
}
|
||||
@@ -118,7 +118,7 @@ public class Main {
|
||||
void test11(Integer integer) {
|
||||
switch (integer) {
|
||||
case 1, 2:
|
||||
case null, <error descr="Invalid case label combination">Integer i when i == 42</error>:
|
||||
case <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error>, Integer i when i == 42:
|
||||
System.out.println("blah blah blah");
|
||||
break;
|
||||
default: System.out.println("null");
|
||||
@@ -127,7 +127,7 @@ public class Main {
|
||||
|
||||
void test12(Integer integer) {
|
||||
switch (integer) {
|
||||
case 1, 2, <error descr="Invalid case label combination">Integer i1 when i1 > 5</error>:
|
||||
case 1, 2, <error descr="Invalid case label combination: A case label must consist of either a list of case constants or a single case pattern">Integer i1 when i1 > 5</error>:
|
||||
case null:
|
||||
System.out.println("blah blah blah");
|
||||
break;
|
||||
@@ -137,89 +137,89 @@ public class Main {
|
||||
|
||||
void test13(Object obj) {
|
||||
switch (obj) {
|
||||
case String s, <error descr="Illegal fall-through from a pattern">null</error> -> {}
|
||||
case String s, <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error> -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test14(Object obj) {
|
||||
switch (obj) {
|
||||
case null, <error descr="Invalid case label combination">String s when s.isEmpty()</error>, Integer i when i == 42 -> {}
|
||||
case <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error>, String s when s.isEmpty(), Integer i when i == 42 -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test15(Object obj) {
|
||||
switch (obj) {
|
||||
case String s when s.isEmpty(), <error descr="Illegal fall-through from a pattern">null</error>, Integer i -> {}
|
||||
case String s when s.isEmpty(), <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error>, Integer i -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test16(Object obj) {
|
||||
switch (obj) {
|
||||
case String s, <error descr="Illegal fall-through from a pattern">Integer i</error>, null -> {}
|
||||
case String s, Integer i, <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error> -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test17(String s) {
|
||||
switch (s) {
|
||||
case null, <error descr="Invalid case label combination">"hello"</error>, "world" -> {}
|
||||
case <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error>, "hello", "world" -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test18(String s) {
|
||||
switch (s) {
|
||||
case "hello", "world", <error descr="Invalid case label combination">null</error>, String str when str.isEmpty() -> {}
|
||||
case "hello", "world", <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error>, String str when str.isEmpty() -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test19(String s) {
|
||||
switch (s) {
|
||||
case "hello", "world", <error descr="Invalid case label combination">null</error>, String str -> {}
|
||||
case "hello", "world", <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error>, String str -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test20(Object obj) {
|
||||
switch (obj) {
|
||||
case null, <error descr="Invalid case label combination">S()</error>, R() -> {}
|
||||
case <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error>, S(), R() -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test21(Object obj) {
|
||||
switch (obj) {
|
||||
case S(), <error descr="Illegal fall-through from a pattern">null</error>, R() -> {}
|
||||
case S(), <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error>, R() -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test22(Object obj) {
|
||||
switch (obj) {
|
||||
case String s when s.isEmpty(), <error descr="Illegal fall-through from a pattern">null</error>, Integer i -> {}
|
||||
case String s when s.isEmpty(), <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error>, Integer i -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test23(Object obj) {
|
||||
switch (obj) {
|
||||
case String s, <error descr="Illegal fall-through from a pattern">Integer i</error>, null -> {}
|
||||
case String s, Integer i, <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error> -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test24(String s) {
|
||||
switch (s) {
|
||||
case "hello", "world", <error descr="Invalid case label combination">null</error>, String str -> {}
|
||||
case "hello", "world", <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error>, String str -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test25(String s) {
|
||||
switch (s) {
|
||||
case "hello", "world", <error descr="Invalid case label combination">String str</error>, null -> {}
|
||||
case "hello", "world", String str, <error descr="Invalid case label combination: 'null' can only be used as a single case label or paired only with 'default'">null</error> -> {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,4 +243,47 @@ public class Main {
|
||||
throw new IllegalStateException("Unexpected value: " + obj);
|
||||
}
|
||||
}
|
||||
|
||||
void test28(Object obj) {
|
||||
switch (obj) {
|
||||
case Integer i, <error descr="Invalid case label combination: A case label must not consist of more than one case pattern">String str</error> -> {}
|
||||
default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test28(String s) {
|
||||
switch (s) {
|
||||
case String str, <error descr="Invalid case label combination: A case label must consist of either a list of case constants or a single case pattern">"hello"</error>, "world" -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test29(Object obj) {
|
||||
switch (obj) {
|
||||
case null, default -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test30(Object obj) {
|
||||
switch (obj) {
|
||||
case <error descr="Invalid case label order: 'null' must be first and 'default' must be second">default</error>, null -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test31(Object obj) {
|
||||
switch (obj) {
|
||||
case String s, <error descr="Default label not allowed here: 'default' can only be used as a single case label or paired only with 'null'">default</error> -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test32(String s) {
|
||||
switch (s) {
|
||||
case "hello", "world", <error descr="Default label not allowed here: 'default' can only be used as a single case label or paired only with 'null'">default</error> -> {}
|
||||
}
|
||||
}
|
||||
|
||||
void test33(String s) {
|
||||
switch (s) {
|
||||
case <error descr="The label for the default case must only use the 'default' keyword, without 'case'">default</error> -> {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user