diff --git a/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties b/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties index 01876e7f2117..f4114c31e953 100644 --- a/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties +++ b/java/codeserver/highlighting/resources/messages/JavaCompilationErrorBundle.properties @@ -312,6 +312,8 @@ statement.unreachable.loop.body=Loop condition is always false making the loop b switch.rule.should.produce.result=Switch expression rule should produce result in all execution paths switch.expression.no.result=Switch expression does not have any result expressions switch.expression.should.produce.result=Switch expression should produce result in all execution paths +switch.expression.incompatible.type=Bad type in switch expression: {0} cannot be converted to {1} +switch.expression.cannot.be.void=Target type for switch expression cannot be void guard.misplaced=Guard is allowed after patterns only guard.evaluated.to.false=This 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/ExpressionChecker.java b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ExpressionChecker.java index f43472da1e78..6d5f6b78abf4 100644 --- a/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ExpressionChecker.java +++ b/java/codeserver/highlighting/src/com/intellij/java/codeserver/highlighting/ExpressionChecker.java @@ -1709,4 +1709,24 @@ final class ExpressionChecker { } } } + + void checkSwitchExpressionReturnTypeCompatible(@NotNull PsiSwitchExpression switchExpression) { + if (!PsiPolyExpressionUtil.isPolyExpression(switchExpression)) { + return; + } + PsiType switchExpressionType = switchExpression.getType(); + if (switchExpressionType != null) { + for (PsiExpression expression : PsiUtil.getSwitchResultExpressions(switchExpression)) { + PsiType expressionType = expression.getType(); + if (expressionType != null && !TypeConversionUtil.areTypesAssignmentCompatible(switchExpressionType, expression)) { + myVisitor.report(JavaErrorKinds.SWITCH_EXPRESSION_INCOMPATIBLE_TYPE.create( + expression, new JavaIncompatibleTypeErrorContext(switchExpressionType, expressionType))); + } + } + + if (PsiTypes.voidType().equals(switchExpressionType)) { + myVisitor.report(JavaErrorKinds.SWITCH_EXPRESSION_CANNOT_BE_VOID.create(switchExpression)); + } + } + } } 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 2267cda05cdc..4fd99e42c4ba 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 @@ -626,6 +626,7 @@ final class JavaErrorVisitor extends JavaElementVisitor { public void visitSwitchExpression(@NotNull PsiSwitchExpression expression) { super.visitSwitchExpression(expression); if (!hasErrorResults()) checkFeature(expression, JavaFeature.SWITCH_EXPRESSION); + if (!hasErrorResults()) myExpressionChecker.checkSwitchExpressionReturnTypeCompatible(expression); if (!hasErrorResults()) myExpressionChecker.checkSwitchExpressionHasResult(expression); } 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 f1c38c4c7329..fb9375b33f6b 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 @@ -905,6 +905,12 @@ public final class JavaErrorKinds { public static final Simple SWITCH_EXPRESSION_SHOULD_PRODUCE_RESULT = error(PsiSwitchExpression.class, "switch.expression.should.produce.result") .withAnchor(switchExpression -> requireNonNullElse(tryCast(switchExpression.getFirstChild(), PsiKeyword.class), switchExpression)); + public static final Simple SWITCH_EXPRESSION_CANNOT_BE_VOID = + error(PsiSwitchExpression.class, "switch.expression.cannot.be.void") + .withAnchor(switchExpression -> requireNonNullElse(tryCast(switchExpression.getFirstChild(), PsiKeyword.class), switchExpression)); + public static final Parameterized SWITCH_EXPRESSION_INCOMPATIBLE_TYPE = + parameterized(PsiExpression.class, JavaIncompatibleTypeErrorContext.class, "switch.expression.incompatible.type") + .withRawDescription((expr, context) -> message("switch.expression.incompatible.type", formatType(context.rType()), formatType(context.lType()))); 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/HighlightUtil.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java index dc6324d5577b..11be67e028cd 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightUtil.java @@ -27,7 +27,6 @@ import com.intellij.pom.java.JavaFeature; import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.impl.IncompleteModelUtil; -import com.intellij.psi.impl.source.resolve.graphInference.PsiPolyExpressionUtil; import com.intellij.psi.util.*; import com.intellij.ui.ColorUtil; import com.intellij.ui.NewUI; @@ -121,34 +120,6 @@ public final class HighlightUtil { return PsiFormatUtil.formatVariable(field, PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_NAME, PsiSubstitutor.EMPTY); } - static void checkSwitchExpressionReturnTypeCompatible(@NotNull PsiSwitchExpression switchExpression, - @NotNull Consumer errorSink) { - if (!PsiPolyExpressionUtil.isPolyExpression(switchExpression)) { - return; - } - PsiType switchExpressionType = switchExpression.getType(); - if (switchExpressionType != null) { - for (PsiExpression expression : PsiUtil.getSwitchResultExpressions(switchExpression)) { - PsiType expressionType = expression.getType(); - if (expressionType != null && !TypeConversionUtil.areTypesAssignmentCompatible(switchExpressionType, expression)) { - String text = JavaErrorBundle - .message("bad.type.in.switch.expression", expressionType.getCanonicalText(), switchExpressionType.getCanonicalText()); - HighlightInfo.Builder info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(expression).descriptionAndTooltip(text); - HighlightFixUtil.registerIncompatibleTypeFixes(asConsumer(info), switchExpression, switchExpressionType, expressionType); - errorSink.accept(info); - } - } - - if (PsiTypes.voidType().equals(switchExpressionType)) { - String text = JavaErrorBundle.message("switch.expression.cannot.be.void"); - HighlightInfo.Builder info = - HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(switchExpression.getFirstChild()).descriptionAndTooltip(text); - errorSink.accept(info); - } - } - } - static @NotNull @NlsContexts.DetailedDescription String staticContextProblemDescription(@NotNull PsiElement refElement) { String type = JavaElementKind.fromElement(refElement).lessDescriptive().subject(); String name = HighlightMessageUtil.getSymbolName(refElement, PsiSubstitutor.EMPTY); @@ -516,7 +487,7 @@ public final class HighlightUtil { return ref; } - static @NlsSafe @NotNull String format(@NotNull PsiElement element) { + private static @NlsSafe @NotNull String format(@NotNull PsiElement element) { if (element instanceof PsiClass psiClass) return formatClass(psiClass); if (element instanceof PsiMethod psiMethod) return JavaHighlightUtil.formatMethod(psiMethod); if (element instanceof PsiField psiField) return formatField(psiField); diff --git a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java index 4e443795ec7a..562b850db230 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java +++ b/java/java-analysis-impl/src/com/intellij/codeInsight/daemon/impl/analysis/HighlightVisitorImpl.java @@ -310,7 +310,6 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh @Override public void visitSwitchExpression(@NotNull PsiSwitchExpression expression) { checkSwitchBlock(expression); - if (!hasErrorResults()) HighlightUtil.checkSwitchExpressionReturnTypeCompatible(expression, myErrorSink); if (!hasErrorResults()) super.visitSwitchExpression(expression); } 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 65edf3249513..24d4cee2e4b5 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 @@ -677,6 +677,10 @@ final class JavaErrorFixProvider { private void createTypeFixes() { fixes(TYPE_INCOMPATIBLE, (error, sink) -> HighlightFixUtil.registerIncompatibleTypeFixes(sink, error.psi(), error.context().lType(), error.context().rType())); + fixes(SWITCH_EXPRESSION_INCOMPATIBLE_TYPE, (error, sink) -> + HighlightFixUtil.registerIncompatibleTypeFixes(sink, + requireNonNull(PsiTreeUtil.getParentOfType(error.psi(), PsiSwitchExpression.class)), + error.context().lType(), error.context().rType())); fixes(CALL_TYPE_INFERENCE_ERROR, (error, sink) -> { if (error.psi() instanceof PsiMethodCallExpression callExpression) { HighlightFixUtil.registerCallInferenceFixes(callExpression, sink);