[java-highlighting] IDEA-357866 Spurious "Different case kinds used in the switch" error on incomplete code

- fixes
- not double error messages

GitOrigin-RevId: 8f789243ee4e09d3eb8de6a2db7dcbe25ee517db
This commit is contained in:
Mikhail Pyltsin
2024-08-22 15:19:45 +02:00
committed by intellij-monorepo-bot
parent cd14483af8
commit e01d24d5c8
9 changed files with 173 additions and 4 deletions

View File

@@ -7,6 +7,7 @@ import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInsight.intention.impl.PriorityIntentionActionWrapper;
import com.intellij.core.JavaPsiBundle;
import com.intellij.modcommand.ModCommandAction;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.NlsContexts;
@@ -111,6 +112,13 @@ public class SwitchBlockHighlightingModel {
}
else if (element instanceof PsiStatement statement) {
if (enhancedLabels) {
//let's not highlight twice
if (statement instanceof PsiSwitchLabelStatement labelStatement &&
labelStatement.getChildren().length != 0 &&
labelStatement.getChildren()[labelStatement.getChildren().length - 1] instanceof PsiErrorElement errorElement &&
errorElement.getErrorDescription().startsWith(JavaPsiBundle.message("expected.colon.or.arrow"))) {
break;
}
alien = statement;
break;
}

View File

@@ -11,6 +11,7 @@ import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.core.JavaPsiBundle;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
@@ -31,6 +32,27 @@ public final class JavaErrorQuickFixProvider implements ErrorQuickFixProvider {
registrar.add(new AddExceptionToCatchFix(false).asIntention());
registrar.add(new AddFinallyFix((PsiTryStatement)parent).asIntention());
}
if (parent instanceof PsiSwitchLabelStatementBase && description.equals(JavaPsiBundle.message("expected.colon.or.arrow"))) {
PsiSwitchBlock switchBlock = PsiTreeUtil.getParentOfType(parent, PsiSwitchBlock.class);
if (switchBlock != null && switchBlock.getBody() != null) {
boolean isOld = false;
boolean isRule = false;
for (@NotNull PsiElement child : switchBlock.getBody().getChildren()) {
if (child instanceof PsiSwitchLabeledRuleStatement) {
isRule = true;
}
if (child instanceof PsiSwitchLabelStatement && !PsiTreeUtil.isAncestor(child, parent, false)) {
isOld = true;
}
}
if (isOld) {
info.registerFix(new InsertMissingTokenFix(":", true), null, null, null, null);
}
if (isRule) {
info.registerFix(new InsertMissingTokenFix(" ->", true), null, null, null, null);
}
}
}
if (parent instanceof PsiSwitchLabeledRuleStatement && description.equals(JavaPsiBundle.message("expected.switch.rule"))) {
IntentionAction action =
QuickFixFactory.getInstance().createWrapSwitchRuleStatementsIntoBlockFix((PsiSwitchLabeledRuleStatement)parent);

View File

@@ -15,10 +15,17 @@ import java.util.List;
import java.util.Objects;
public class InsertMissingTokenFix implements ModCommandAction {
@NotNull
private final String myToken;
private final boolean myMoveAfter;
public InsertMissingTokenFix(String token) {
public InsertMissingTokenFix(@NotNull String token) {
this(token, false);
}
public InsertMissingTokenFix(@NotNull String token, boolean moveAfter) {
myToken = token;
myMoveAfter = moveAfter;
}
@Override
@@ -44,7 +51,11 @@ public class InsertMissingTokenFix implements ModCommandAction {
String oldText = document.getText();
String newText = oldText.substring(0, offset) + myToken + oldText.substring(offset);
VirtualFile file = Objects.requireNonNull(FileDocumentManager.getInstance().getFile(document));
return new ModUpdateFileText(file, oldText, newText,
List.of(new ModUpdateFileText.Fragment(offset, 0, myToken.length())));
ModCommand fix = new ModUpdateFileText(file, oldText, newText,
List.of(new ModUpdateFileText.Fragment(offset, 0, myToken.length())));
if (myMoveAfter) {
fix = fix.andThen(new ModNavigate(file, -1, -1, offset + myToken.length()));
}
return fix;
}
}

View File

@@ -0,0 +1,61 @@
class IncompleteSwitch {
public void testStatement(char o) {
switch (o) {
case
<error descr="':' or '->' expected"><error descr="Expression, pattern, 'default' or 'null' expected">}</error></error>
switch (o) {
case '1'<EOLError descr="':' or '->' expected"></EOLError>
}
switch (o) {
case '1' when<EOLError descr="Expression expected"></EOLError><EOLError descr="':' or '->' expected"></EOLError>
}
switch (o) {
case <error descr="Primitive types in patterns, instanceof and switch are not supported at language level '21'">char a</error> when a == '1'<EOLError descr="':' or '->' expected"></EOLError>
}
switch (o) {
case '2' -> System.out.println("1");
case
<error descr="':' or '->' expected"><error descr="Expression, pattern, 'default' or 'null' expected">}</error></error>
switch (o) {
case '2' -> System.out.println("1");
case '1'<EOLError descr="':' or '->' expected"></EOLError>
}
switch (o) {
case '2' -> System.out.println("1");
case '1' when<EOLError descr="Expression expected"></EOLError><EOLError descr="':' or '->' expected"></EOLError>
}
switch (o) {
case '2' -> System.out.println("1");
case <error descr="Primitive types in patterns, instanceof and switch are not supported at language level '21'">char a</error> when a == '1'<EOLError descr="':' or '->' expected"></EOLError>
}
}
public void testExpression(char o) {
int i = switch (<error descr="'switch' expression does not cover all possible input values">o</error>) {
case '2':
yield 1;
case
<error descr="':' or '->' expected"><error descr="Expression, pattern, 'default' or 'null' expected">}</error></error>;
i = switch (<error descr="'switch' expression does not cover all possible input values">o</error>) {
case '2':
yield 2;
case '1'<EOLError descr="':' or '->' expected"></EOLError>
};
i = switch (<error descr="'switch' expression does not cover all possible input values">o</error>) {
case '2':
yield 2;
case '1' when<EOLError descr="Expression expected"></EOLError><EOLError descr="':' or '->' expected"></EOLError>
};
i = switch (o) {
case '2':
yield 2;
case <error descr="Primitive types in patterns, instanceof and switch are not supported at language level '21'">char a</error> when a == '1'<EOLError descr="':' or '->' expected"></EOLError>
};
}
}

View File

@@ -0,0 +1,10 @@
class IncompleteSwitchFixColon {
public void testStatement(char o) {
switch (o) {
case '2'-> System.out.println("1");
case '1'<caret><EOLError descr="':' or '->' expected"></EOLError>
}
}
}

View File

@@ -0,0 +1,10 @@
class IncompleteSwitchFixColon {
public void testStatement(char o) {
switch (o) {
case '2'-> System.out.println("1");
case '1' -><caret>
}
}
}

View File

@@ -0,0 +1,12 @@
class IncompleteSwitchFixColon {
public void testStatement(char o) {
switch (o) {
case '2':
System.out.println("1");
break;
case '1'<caret><EOLError descr="':' or '->' expected"></EOLError>
}
}
}

View File

@@ -0,0 +1,12 @@
class IncompleteSwitchFixColon {
public void testStatement(char o) {
switch (o) {
case '2':
System.out.println("1");
break;
case '1':<caret>
}
}
}

View File

@@ -1,11 +1,14 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.java.codeInsight.daemon
import com.intellij.JavaTestUtil
import com.intellij.codeInsight.daemon.impl.quickfix.InsertMissingTokenFix
import com.intellij.codeInspection.redundantCast.RedundantCastInspection
import com.intellij.pom.java.LanguageLevel
import com.intellij.testFramework.IdeaTestUtil
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase.JAVA_15
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase.assertEquals
class JavaSwitchExpressionsHighlightingTest : LightJavaCodeInsightFixtureTestCase() {
override fun getProjectDescriptor() = JAVA_15
@@ -32,6 +35,26 @@ class JavaSwitchExpressionsHighlightingTest : LightJavaCodeInsightFixtureTestCas
myFixture.enableInspections(RedundantCastInspection())
doTest()
}
fun testIncompleteSwitch() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_21) { doTest() }
fun testIncompleteSwitchFixColon() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_21) {
doTest()
val availableIntentions = myFixture.availableIntentions
.mapNotNull { it.asModCommandAction() }
.filter { it is InsertMissingTokenFix }
assertEquals(1, availableIntentions.size)
myFixture.launchAction(availableIntentions.first().asIntention())
myFixture.checkResultByFile("${getTestName(false)}_after.java")
}
fun testIncompleteSwitchFixArray() = IdeaTestUtil.withLevel(module, LanguageLevel.JDK_21) {
doTest()
val availableIntentions = myFixture.availableIntentions
.mapNotNull { it.asModCommandAction() }
.filter { it is InsertMissingTokenFix }
assertEquals(1, availableIntentions.size)
myFixture.launchAction(availableIntentions.first().asIntention())
myFixture.checkResultByFile("${getTestName(false)}_after.java")
}
private fun doTest() {
myFixture.configureByFile("${getTestName(false)}.java")