[java-highlighting] Fixes for unnamed patterns in switch (IDEA-326939)

1. More uniform messages
2. Better anchor when var is defined in multiple patterns
3. Separate error messages for Java 20 and Java 21

GitOrigin-RevId: d7c6ab5b4445b7929bdcf200ac0838fc5431e803
This commit is contained in:
Tagir Valeev
2023-08-18 11:16:17 +02:00
committed by intellij-monorepo-bot
parent 3f7728ab76
commit 3dd5f3d6f0
6 changed files with 63 additions and 15 deletions

View File

@@ -1017,23 +1017,34 @@ public class SwitchBlockHighlightingModel {
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");
return getPatternConstantCombinationProblem(elements[patternIndex]);
}
else if (firstElement instanceof PsiPattern) {
if (elements[1] instanceof PsiPattern) {
if (ContainerUtil.exists(elements, JavaPsiPatternUtil::containsNamedPatternVariable)) {
String messageKey = HighlightingFeature.UNNAMED_PATTERNS_AND_VARIABLES.isAvailable(firstElement)
? "invalid.case.label.combination.several.patterns.unnamed"
: "invalid.case.label.combination.several.patterns";
return new CaseLabelCombinationProblem(elements[1], messageKey);
PsiCaseLabelElement nonPattern = ContainerUtil.find(elements, e -> !(e instanceof PsiPattern));
if (nonPattern != null) {
return getPatternConstantCombinationProblem(nonPattern);
}
if (HighlightingFeature.UNNAMED_PATTERNS_AND_VARIABLES.isAvailable(firstElement)) {
PsiCaseLabelElement patternVarElement = ContainerUtil.find(elements, JavaPsiPatternUtil::containsNamedPatternVariable);
if (patternVarElement != null) {
return new CaseLabelCombinationProblem(patternVarElement, "invalid.case.label.combination.several.patterns.unnamed");
}
} else {
return new CaseLabelCombinationProblem(elements[1], "invalid.case.label.combination.constants.and.patterns");
return new CaseLabelCombinationProblem(elements[1], "invalid.case.label.combination.several.patterns");
}
}
return null;
}
@NotNull
private static CaseLabelCombinationProblem getPatternConstantCombinationProblem(PsiCaseLabelElement anchor) {
if (HighlightingFeature.UNNAMED_PATTERNS_AND_VARIABLES.isAvailable(anchor)) {
return new CaseLabelCombinationProblem(anchor, "invalid.case.label.combination.constants.and.patterns.unnamed");
} else {
return new CaseLabelCombinationProblem(anchor, "invalid.case.label.combination.constants.and.patterns");
}
}
private static void addIllegalFallThroughError(@NotNull PsiElement element,
@NotNull @PropertyKey(resourceBundle = JavaErrorBundle.BUNDLE) String key,
@NotNull HighlightInfoHolder holder,

View File

@@ -240,8 +240,9 @@ valid.switch.1_7.selector.types=char, byte, short, int, Character, Byte, Short,
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.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.unnamed=Invalid case label combination: Multiple patterns are allowed only if none of them declare any pattern variables
invalid.case.label.combination.several.patterns=Invalid case label combination: A case label must not consist of more than one case pattern
invalid.case.label.combination.constants.and.patterns.unnamed=Invalid case label combination: a case label must consist of either a list of case constants or a list of case patterns
invalid.case.label.combination.several.patterns.unnamed=Invalid case label combination: multiple patterns are allowed only if none of them declare any pattern variables
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

View File

@@ -246,7 +246,7 @@ public class Main {
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> -> {}
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 -> {}
}
}

View File

@@ -58,4 +58,22 @@ class X {
case <error descr="Duplicate unconditional pattern">Integer i</error> -> System.out.println("An integer");
}
}
record R1() {}
record R2() {}
void testNoVars(Object obj) {
switch(obj) {
case R1(), <error descr="Invalid case label combination: a case label must not consist of more than one case pattern">R2()</error> -> {}
default -> {}
}
}
void testCombination(Integer i) {
switch (i) {
case Integer a, <error descr="Invalid case label combination: a case label must not consist of more than one case pattern">Integer b</error> when i > 0 -> System.out.println(1);
case 1, 2, 3, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a single case pattern">Integer c</error> when i > 0 -> System.out.println(1);
case Integer d, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a single case pattern">4</error> when i > 0 -> System.out.println(1);
}
}
}

View File

@@ -22,16 +22,16 @@ class Test {
void testEnum(Object obj) {
switch (obj) {
case X.A, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a single case pattern">String _</error> -> System.out.println("string or int");
case Integer _, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a single case pattern">X.B</error> -> System.out.println("string or int");
case X.A, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a list of case patterns">String _</error> -> System.out.println("string or int");
case Integer _, <error descr="Invalid case label combination: a case label must consist of either a list of case constants or a list of case patterns">X.B</error> -> System.out.println("string or int");
default -> System.out.println("other");
}
}
void test2(Object obj) {
switch (obj) {
case Integer x, <error descr="Invalid case label combination: Multiple patterns are allowed only if none of them declare any pattern variables">String _</error> -> System.out.println("string or int");
case R(_, var i), <error descr="Invalid case label combination: Multiple patterns are allowed only if none of them declare any pattern variables">R1 _</error> -> System.out.println("R or R1");
case <error descr="Invalid case label combination: multiple patterns are allowed only if none of them declare any pattern variables">Integer x</error>, String _ -> System.out.println("string or int");
case <error descr="Invalid case label combination: multiple patterns are allowed only if none of them declare any pattern variables">R(_, var i)</error>, R1 _ -> System.out.println("R or R1");
default -> System.out.println("other");
}
}
@@ -58,4 +58,14 @@ class Test {
System.out.println("other");
}
}
record RR1() {}
record RR2() {}
void testNoVars(Object obj) {
switch(obj) {
case RR1(), RR2() -> {}
default -> {}
}
}
}

View File

@@ -42,4 +42,12 @@ class Test {
private native int isInt();
private native boolean foo(boolean blag);
public static void main2(Object o) {
int x = switch (o) {
case Object _, String _ when o == o -> 4;
case Integer _ -> 2;
default -> 3;
};
}
}