diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/SwitchBlockHighlightingModel.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/SwitchBlockHighlightingModel.java
index 5028f1cd630f..0e71b4003101 100644
--- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/SwitchBlockHighlightingModel.java
+++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/SwitchBlockHighlightingModel.java
@@ -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;
}
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorQuickFixProvider.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorQuickFixProvider.java
index fe0da8e3dced..6990862b810b 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorQuickFixProvider.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorQuickFixProvider.java
@@ -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);
diff --git a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/InsertMissingTokenFix.java b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/InsertMissingTokenFix.java
index e70a32358eda..9981c814ca26 100644
--- a/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/InsertMissingTokenFix.java
+++ b/java/java-impl/src/com/intellij/codeInsight/daemon/impl/quickfix/InsertMissingTokenFix.java
@@ -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;
}
}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitch.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitch.java
new file mode 100644
index 000000000000..ade78820ca96
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitch.java
@@ -0,0 +1,61 @@
+class IncompleteSwitch {
+
+
+ public void testStatement(char o) {
+ switch (o) {
+ case
+ }
+ switch (o) {
+ case '1'
+ }
+ switch (o) {
+ case '1' when
+ }
+ switch (o) {
+ case char a when a == '1'
+ }
+
+
+ switch (o) {
+ case '2' -> System.out.println("1");
+ case
+ }
+ switch (o) {
+ case '2' -> System.out.println("1");
+ case '1'
+ }
+ switch (o) {
+ case '2' -> System.out.println("1");
+ case '1' when
+ }
+ switch (o) {
+ case '2' -> System.out.println("1");
+ case char a when a == '1'
+ }
+ }
+
+ public void testExpression(char o) {
+
+ int i = switch (o) {
+ case '2':
+ yield 1;
+ case
+ };
+
+ i = switch (o) {
+ case '2':
+ yield 2;
+ case '1'
+ };
+ i = switch (o) {
+ case '2':
+ yield 2;
+ case '1' when
+ };
+ i = switch (o) {
+ case '2':
+ yield 2;
+ case char a when a == '1'
+ };
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixArray.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixArray.java
new file mode 100644
index 000000000000..02d94387acb8
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixArray.java
@@ -0,0 +1,10 @@
+class IncompleteSwitchFixColon {
+
+ public void testStatement(char o) {
+
+ switch (o) {
+ case '2'-> System.out.println("1");
+ case '1'
+ }
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixArray_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixArray_after.java
new file mode 100644
index 000000000000..af3fd2edce35
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixArray_after.java
@@ -0,0 +1,10 @@
+class IncompleteSwitchFixColon {
+
+ public void testStatement(char o) {
+
+ switch (o) {
+ case '2'-> System.out.println("1");
+ case '1' ->
+ }
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixColon.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixColon.java
new file mode 100644
index 000000000000..370f9b10e644
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixColon.java
@@ -0,0 +1,12 @@
+class IncompleteSwitchFixColon {
+
+ public void testStatement(char o) {
+
+ switch (o) {
+ case '2':
+ System.out.println("1");
+ break;
+ case '1'
+ }
+ }
+}
diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixColon_after.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixColon_after.java
new file mode 100644
index 000000000000..7ead456c0b6a
--- /dev/null
+++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/switchExpressions/IncompleteSwitchFixColon_after.java
@@ -0,0 +1,12 @@
+class IncompleteSwitchFixColon {
+
+ public void testStatement(char o) {
+
+ switch (o) {
+ case '2':
+ System.out.println("1");
+ break;
+ case '1':
+ }
+ }
+}
diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/JavaSwitchExpressionsHighlightingTest.kt b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/JavaSwitchExpressionsHighlightingTest.kt
index ee3341960183..09ecbd58c9b0 100644
--- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/JavaSwitchExpressionsHighlightingTest.kt
+++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/JavaSwitchExpressionsHighlightingTest.kt
@@ -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")