From b3b3fcf587a1e67f8751b43999a870d02dc1f6a7 Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Thu, 27 Feb 2025 11:32:05 +0100 Subject: [PATCH] [java-highlighting] Use JavaPsiSwitchUtil.isBooleanSwitchWithTrueAndFalse Part of IDEA-365344 Create a new Java error highlighter with minimal dependencies (PSI only) GitOrigin-RevId: bde4078ac2d09977730c7803a3565c9bbe683a06 --- .../codeserver/core/JavaPsiSwitchUtil.java | 11 +++++++- ...atternsInSwitchBlockHighlightingModel.java | 27 +++++++------------ .../SwitchBlockHighlightingModel.java | 5 ---- 3 files changed, 20 insertions(+), 23 deletions(-) diff --git a/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiSwitchUtil.java b/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiSwitchUtil.java index 3d225dac10d3..70529c93753e 100644 --- a/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiSwitchUtil.java +++ b/java/codeserver/core/src/com/intellij/java/codeserver/core/JavaPsiSwitchUtil.java @@ -315,9 +315,18 @@ public final class JavaPsiSwitchUtil { return null; } - public static boolean hasTrueAndFalse(@NotNull PsiSwitchBlock block) { + /** + * @param block block to check + * @return true if this switch block is a boolean switch that contains both true and false branches. + * All unrelated branches or duplicate branches are ignored. + */ + public static boolean isBooleanSwitchWithTrueAndFalse(@NotNull PsiSwitchBlock block) { PsiCodeBlock body = block.getBody(); if (body == null) return false; + PsiExpression selector = block.getExpression(); + if (selector == null) return false; + PsiType selectorType = selector.getType(); + if (selectorType == null || getSwitchSelectorKind(selector.getType()) != SelectorKind.BOOLEAN) return false; PsiConstantEvaluationHelper helper = JavaPsiFacade.getInstance(block.getProject()).getConstantEvaluationHelper(); boolean hasTrue = false, hasFalse = false; 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 0ba4b3ae10b2..99e09a93cd83 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 @@ -1,6 +1,7 @@ // 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.codeInsight.daemon.impl.analysis; +import com.intellij.codeInsight.ExpressionUtil; import com.intellij.codeInsight.daemon.JavaErrorBundle; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.intention.IntentionAction; @@ -26,7 +27,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; -import java.util.stream.Collectors; import static com.intellij.codeInsight.daemon.impl.analysis.PatternHighlightingModel.*; import static com.intellij.codeInsight.daemon.impl.analysis.PatternsInSwitchBlockHighlightingModel.SwitchExhaustivenessState.*; @@ -61,14 +61,15 @@ public class PatternsInSwitchBlockHighlightingModel extends SwitchBlockHighlight Collections.addAll(elementsToCheckCompleteness, labelElementList.getElements()); } } - if (needToCheckCompleteness(elementsToCheckCompleteness)) { - if (checkRedundantDefaultBranch(elementsToCheckCompleteness, errorSink)) return; + if (ExpressionUtil.isEnhancedSwitch(myBlock)) { + if (checkRedundantDefaultBranch(errorSink)) return; + if (JavaPsiSwitchUtil.getUnconditionalPatternLabel(myBlock) != null) return; + if (JavaPsiSwitchUtil.findDefaultElement(myBlock) != null) return; checkCompleteness(elementsToCheckCompleteness, errorSink); } } - private boolean checkRedundantDefaultBranch(@NotNull List elements, - @NotNull Consumer errorSink) { + private boolean checkRedundantDefaultBranch(@NotNull Consumer errorSink) { //T is an intersection type T1& ... &Tn, and P covers Ti, for one of the type Ti (1≤i≤n) PsiCaseLabelElement elementCoversType = JavaPsiSwitchUtil.getUnconditionalPatternLabel(myBlock); PsiElement defaultElement = JavaPsiSwitchUtil.findDefaultElement(myBlock); @@ -86,7 +87,7 @@ public class PatternsInSwitchBlockHighlightingModel extends SwitchBlockHighlight } //default (or unconditional), TRUE and FALSE cannot be together if ((defaultElement != null || elementCoversType != null) && - mySelectorKind == JavaPsiSwitchUtil.SelectorKind.BOOLEAN && JavaPsiSwitchUtil.hasTrueAndFalse(myBlock)) { + JavaPsiSwitchUtil.isBooleanSwitchWithTrueAndFalse(myBlock)) { if (defaultElement != null) { HighlightInfo.Builder defaultInfo = createError(defaultElement.getFirstChild(), JavaErrorBundle.message("switch.unconditional.boolean.and.default.exist")); @@ -108,7 +109,7 @@ public class PatternsInSwitchBlockHighlightingModel extends SwitchBlockHighlight private void checkCompleteness(@NotNull List elements, @NotNull Consumer errorSink) { if (isExhaustiveForSwitchSelectorPrimitiveWrapper(elements)) return; - if (mySelectorKind == JavaPsiSwitchUtil.SelectorKind.BOOLEAN && hasTrueAndFalse(elements)) return; + if (JavaPsiSwitchUtil.isBooleanSwitchWithTrueAndFalse(myBlock)) return; //enums are final; checking intersections are not needed PsiClass selectorClass = PsiUtil.resolveClassInClassTypeOnly(TypeConversionUtil.erasure(mySelectorType)); if (selectorClass != null && mySelectorKind == JavaPsiSwitchUtil.SelectorKind.ENUM) { @@ -150,14 +151,6 @@ public class PatternsInSwitchBlockHighlightingModel extends SwitchBlockHighlight } } - private static boolean hasTrueAndFalse(@NotNull List elements) { - Set constants = elements.stream() - .filter(e -> e instanceof PsiExpression expression && PsiTypes.booleanType().equals(expression.getType())) - .map(e -> evaluateConstant(e)) - .collect(Collectors.toSet()); - return constants.contains(Boolean.TRUE) && constants.contains(Boolean.FALSE); - } - private boolean isExhaustiveForSwitchSelectorPrimitiveWrapper(@NotNull List elements) { PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(TypeConversionUtil.erasure(mySelectorType)); if (unboxedType == null) return false; @@ -288,14 +281,14 @@ public class PatternsInSwitchBlockHighlightingModel extends SwitchBlockHighlight List labelElements = StreamEx.of(SwitchUtils.getSwitchBranches(switchBlock)).select(PsiCaseLabelElement.class) .filter(element -> !(element instanceof PsiDefaultCaseLabelElement)).toList(); if (labelElements.isEmpty()) return UNEVALUATED; - boolean needToCheckCompleteness = switchModel.needToCheckCompleteness(labelElements); + boolean needToCheckCompleteness = ExpressionUtil.isEnhancedSwitch(switchBlock); boolean isEnumSelector = switchModel.getSwitchSelectorKind() == JavaPsiSwitchUtil.SelectorKind.ENUM; AtomicBoolean reported = new AtomicBoolean(); if (switchModel instanceof PatternsInSwitchBlockHighlightingModel patternsInSwitchModel) { if (findUnconditionalPatternForType(labelElements, switchModel.mySelectorType) != null) { return EXHAUSTIVE_WITH_UNCONDITIONAL; } - if (switchModel.getSwitchSelectorKind() == JavaPsiSwitchUtil.SelectorKind.BOOLEAN && hasTrueAndFalse(labelElements)) { + if (JavaPsiSwitchUtil.isBooleanSwitchWithTrueAndFalse(switchBlock)) { return EXHAUSTIVE_WITH_UNCONDITIONAL; } if (!needToCheckCompleteness && !isEnumSelector) return INCOMPLETE; 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 5a06b09bf872..de3a25ab3106 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 @@ -1,7 +1,6 @@ // 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.codeInsight.daemon.impl.analysis; -import com.intellij.codeInsight.ExpressionUtil; import com.intellij.codeInsight.daemon.JavaErrorBundle; import com.intellij.codeInsight.daemon.impl.HighlightInfo; import com.intellij.codeInsight.daemon.impl.HighlightInfoType; @@ -122,10 +121,6 @@ public class SwitchBlockHighlightingModel { return JavaPsiFacade.getInstance(constant.getProject()).getConstantEvaluationHelper().computeConstantExpression(constant, false); } - boolean needToCheckCompleteness(@NotNull List elements) { - return ExpressionUtil.isEnhancedSwitch(myBlock); - } - void checkEnumCompleteness(@NotNull PsiClass selectorClass, @NotNull List enumElements, @NotNull Consumer errorSink) {