diff --git a/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties b/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties index 729457a53cfc..3b5a66019c8a 100644 --- a/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties +++ b/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties @@ -324,6 +324,9 @@ switch.label.constant.expected=Constant expression required switch.label.pattern.expected=Pattern expected for switch selector type ''{0}'' switch.label.unexpected=Constant expression, pattern or null is required switch.default.label.contains.case=The label for the default case must only use the 'default' keyword, without 'case' +switch.label.duplicate.unconditional.pattern=Duplicate unconditional pattern +switch.label.duplicate.default=Duplicate default label +switch.label.duplicate=Duplicate label ''{0}'' guard.misplaced=Guard is allowed after patterns only guard.evaluated.to.false=Case label has a guard that is a constant expression with value 'false' diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java index c61ee461615e..0bb79a86ec05 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/JavaErrorVisitor.java @@ -642,6 +642,7 @@ final class JavaErrorVisitor extends JavaElementVisitor { if (!hasErrorResults()) mySwitchChecker.checkSwitchBlockStatements(block); if (!hasErrorResults()) mySwitchChecker.checkSwitchSelectorType(block); if (!hasErrorResults()) mySwitchChecker.checkLabelSelectorCompatibility(block); + if (!hasErrorResults()) mySwitchChecker.checkDuplicates(block); } @Override diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/SwitchChecker.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/SwitchChecker.java index e271d662c508..207caa3742de 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/SwitchChecker.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/SwitchChecker.java @@ -15,6 +15,9 @@ import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; +import java.util.Map; + final class SwitchChecker { private final @NotNull JavaErrorVisitor myVisitor; @@ -436,4 +439,14 @@ final class SwitchChecker { } myVisitor.report(JavaErrorKinds.SWITCH_LABEL_UNEXPECTED.create(label)); } + + void checkDuplicates(@NotNull PsiSwitchBlock block) { + for (Map.Entry> entry : JavaPsiSwitchUtil.getValuesAndLabels(block).entrySet()) { + if (entry.getValue().size() <= 1) continue; + Object duplicateKey = entry.getKey(); + for (PsiElement duplicateElement : entry.getValue()) { + myVisitor.report(JavaErrorKinds.SWITCH_LABEL_DUPLICATE.create(duplicateElement, duplicateKey)); + } + } + } } diff --git a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java index 34b0a4b229a0..d988fa1d053a 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/errors/JavaErrorKinds.java @@ -955,6 +955,26 @@ public final class JavaErrorKinds { public static final Parameterized SWITCH_LABEL_PATTERN_EXPECTED = parameterized(PsiExpression.class, PsiType.class, "switch.label.pattern.expected") .withRawDescription((expr, type) -> message("switch.label.pattern.expected", formatType(type))); + public static final Parameterized SWITCH_LABEL_DUPLICATE = + parameterized(PsiElement.class, Object.class, "switch.label.duplicate") + .withRawDescription((label, value) -> { + if (value instanceof JavaPsiSwitchUtil.SwitchSpecialValue specialValue) { + return switch (specialValue) { + case UNCONDITIONAL_PATTERN -> message("switch.label.duplicate.unconditional.pattern"); + case DEFAULT_VALUE -> message("switch.label.duplicate.default"); + case NULL_VALUE -> message("switch.label.duplicate", PsiKeyword.NULL); + }; + } + else if (value instanceof PsiEnumConstant constant) { + return message("switch.label.duplicate", constant.getName()); + } + else if (label instanceof PsiLiteralExpression literalExpression) { + return message("switch.label.duplicate", literalExpression.getValue()); + } + else { + return message("switch.label.duplicate", value); + } + }); public static final Simple EXPRESSION_EXPECTED = error("expression.expected"); public static final Parameterized EXPRESSION_SUPER_UNQUALIFIED_DEFAULT_METHOD = diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java index 85e593f2f6ac..7281c29ec798 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/JavaErrorFixProvider.java @@ -235,6 +235,15 @@ final class JavaErrorFixProvider { HighlightFixUtil.getIncreaseLanguageLevelFixes(error.psi(), feature).forEach(sink); } }); + fix(SWITCH_LABEL_DUPLICATE, error -> { + if (error.psi() instanceof PsiCaseLabelElement caseLabel) { + return myFactory.createDeleteSwitchLabelFix(caseLabel); + } + else if (error.context() == JavaPsiSwitchUtil.SwitchSpecialValue.DEFAULT_VALUE) { + return myFactory.createDeleteDefaultFix(null, error.psi()); + } + return null; + }); } private void createMethodFixes() { diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PatternsInSwitchBlockHighlightingModel.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PatternsInSwitchBlockHighlightingModel.java index 50390f79e820..99589abd79a5 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PatternsInSwitchBlockHighlightingModel.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/PatternsInSwitchBlockHighlightingModel.java @@ -57,12 +57,6 @@ public class PatternsInSwitchBlockHighlightingModel extends SwitchBlockHighlight PsiCodeBlock body = myBlock.getBody(); if (body == null) return; - MultiMap elementsToCheckDuplicates = JavaPsiSwitchUtil.getValuesAndLabels(myBlock); - - if (checkDuplicates(elementsToCheckDuplicates, errorSink)) { - return; - } - List> elementsToCheckFallThroughLegality = new SmartList<>(); List elementsToCheckDominance = new ArrayList<>(); List elementsToCheckCompleteness = new ArrayList<>(); 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 0304d8ff6f40..f124a1bc991d 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 @@ -21,7 +21,6 @@ import com.intellij.util.containers.MultiMap; import com.intellij.util.containers.SmartHashSet; import com.siyeh.ig.psiutils.SwitchUtils; import one.util.streamex.StreamEx; -import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.PropertyKey; @@ -86,12 +85,6 @@ public class SwitchBlockHighlightingModel { PsiCodeBlock body = myBlock.getBody(); if (body == null) return; - MultiMap elementsToCheckDuplicates = JavaPsiSwitchUtil.getValuesAndLabels(myBlock); - - if (checkDuplicates(elementsToCheckDuplicates, errorSink)) { - return; - } - // todo replace with needToCheckCompleteness if (myBlock instanceof PsiSwitchExpression && !hasDefaultCase(body)) { PsiClass selectorClass = PsiUtil.resolveClassInClassTypeOnly(mySelectorType); @@ -131,35 +124,6 @@ public class SwitchBlockHighlightingModel { return JavaPsiFacade.getInstance(constant.getProject()).getConstantEvaluationHelper().computeConstantExpression(constant, false); } - static boolean checkDuplicates(@NotNull MultiMap values, Consumer errorSink) { - boolean reported = false; - for (Map.Entry> entry : values.entrySet()) { - if (entry.getValue().size() <= 1) continue; - Object duplicateKey = entry.getKey(); - for (PsiElement duplicateElement : entry.getValue()) { - HighlightInfo.Builder info = createDuplicateInfo(duplicateKey, duplicateElement); - errorSink.accept(info); - reported = true; - } - } - return reported; - } - - @NotNull - private static HighlightInfo.Builder createDuplicateInfo(@Nullable Object duplicateKey, @NotNull PsiElement duplicateElement) { - String description = createDuplicateDescription(duplicateKey, duplicateElement); - HighlightInfo.Builder info = createError(duplicateElement, description); - if (duplicateElement instanceof PsiCaseLabelElement caseLabel) { - IntentionAction action = getFixFactory().createDeleteSwitchLabelFix(caseLabel); - info.registerFix(action, null, null, null, null); - } - else if (duplicateKey == JavaPsiSwitchUtil.SwitchSpecialValue.DEFAULT_VALUE) { - IntentionAction action = getFixFactory().createDeleteDefaultFix(null, duplicateElement); - info.registerFix(action, null, null, null, null); - } - return info; - } - boolean needToCheckCompleteness(@NotNull List elements) { return myBlock instanceof PsiSwitchExpression || myBlock instanceof PsiSwitchStatement && isEnhancedSwitch(elements); } @@ -259,23 +223,4 @@ public class SwitchBlockHighlightingModel { return StreamEx.ofKeys(patternInSwitchModel.findDominatedLabels(dominanceCheckingCandidates), value -> value instanceof PsiPattern) .into(result); } - - private static @NotNull @Nls String createDuplicateDescription(@Nullable Object duplicateKey, @NotNull PsiElement duplicateElement) { - if (duplicateKey instanceof JavaPsiSwitchUtil.SwitchSpecialValue specialValue) { - return switch (specialValue) { - case UNCONDITIONAL_PATTERN -> JavaErrorBundle.message("duplicate.unconditional.pattern.label"); - case DEFAULT_VALUE -> JavaErrorBundle.message("duplicate.default.switch.label"); - case NULL_VALUE -> JavaErrorBundle.message("duplicate.switch.label", PsiKeyword.NULL); - }; - } - else if (duplicateKey instanceof PsiEnumConstant constant) { - return JavaErrorBundle.message("duplicate.switch.label", constant.getName()); - } - else if (duplicateElement instanceof PsiLiteralExpression literalExpression) { - return JavaErrorBundle.message("duplicate.switch.label", literalExpression.getValue()); - } - else { - return JavaErrorBundle.message("duplicate.switch.label", duplicateKey); - } - } }