[java-inspections] IDEA-371955 delete covered cases after deleting guards

GitOrigin-RevId: 712396793650bb88555cb67e116db96ad72fc148
This commit is contained in:
Mikhail Pyltsin
2025-05-15 12:13:19 +02:00
committed by intellij-monorepo-bot
parent 699fe16188
commit bb218c792d
10 changed files with 288 additions and 10 deletions

View File

@@ -12,6 +12,7 @@ import com.intellij.codeInspection.util.IntentionFamilyName;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.java.JavaBundle;
import com.intellij.java.analysis.JavaAnalysisBundle;
import com.intellij.java.codeserver.core.JavaPsiSwitchUtil;
import com.intellij.java.syntax.parser.JavaKeywords;
import com.intellij.modcommand.ActionContext;
import com.intellij.modcommand.ModPsiUpdater;
@@ -471,13 +472,7 @@ public class SimplifyBooleanExpressionFix extends PsiUpdateModCommandAction<PsiE
}
if (parent instanceof PsiSwitchLabelStatementBase label && PsiTreeUtil.isAncestor(label.getGuardExpression(), newExpression, false)) {
if (Boolean.TRUE.equals(value)) {
CommentTracker tracker = new CommentTracker();
PsiExpression guardExpression = label.getGuardExpression();
PsiKeyword psiKeyword = PsiTreeUtil.getPrevSiblingOfType(guardExpression, PsiKeyword.class);
if (psiKeyword != null && psiKeyword.getTokenType() == WHEN_KEYWORD) {
tracker.delete(psiKeyword);
}
tracker.delete(guardExpression);
deleteUnnecessaryGuard(label);
return;
}
if (Boolean.FALSE.equals(value)) {
@@ -491,6 +486,67 @@ public class SimplifyBooleanExpressionFix extends PsiUpdateModCommandAction<PsiE
}
}
private static void deleteUnnecessaryGuard(@NotNull PsiSwitchLabelStatementBase label) {
CommentTracker tracker = new CommentTracker();
PsiExpression guardExpression = label.getGuardExpression();
if (guardExpression == null) return;
PsiKeyword psiKeyword = PsiTreeUtil.getPrevSiblingOfType(guardExpression, PsiKeyword.class);
if (psiKeyword != null && psiKeyword.getTokenType() == WHEN_KEYWORD) {
tracker.delete(psiKeyword);
}
tracker.delete(guardExpression);
PsiSwitchBlock switchBlock = PsiTreeUtil.getParentOfType(label, PsiSwitchBlock.class);
if (switchBlock == null) return;
PsiExpression selector = switchBlock.getExpression();
if (selector == null) return;
PsiType selectorType = selector.getType();
if (selectorType == null) return;
PsiCaseLabelElementList elementList = label.getCaseLabelElementList();
if (elementList == null) return;
PsiCaseLabelElement target = null;
for (PsiCaseLabelElement element : elementList.getElements()) {
boolean isUnconditional = JavaPsiPatternUtil.isUnconditionalForType(element, selectorType, false);
if (isUnconditional) {
target = element;
break;
}
}
if (target == null) return;
boolean afterTarget = false;
for (PsiElement element : JavaPsiSwitchUtil.getSwitchBranches(switchBlock)) {
if (!element.isValid()) continue;
if (element == target) {
afterTarget = true;
continue;
}
if (!afterTarget) continue;
if (element instanceof PsiSwitchLabelStatementBase base && base.isDefaultCase()) {
tracker.delete(element);
continue;
}
boolean deleteCaseElement = false;
if (element instanceof PsiCaseLabelElement caseLabelElement &&
(caseLabelElement instanceof PsiDefaultCaseLabelElement ||
JavaPsiPatternUtil.isUnconditionalForType(caseLabelElement, selectorType, false) ||
JavaPsiSwitchUtil.isDominated(caseLabelElement, target, selectorType))) {
deleteCaseElement = true;
}
if (deleteCaseElement) {
PsiSwitchLabelStatementBase statementBase = PsiTreeUtil.getParentOfType(element, PsiSwitchLabelStatementBase.class);
if (statementBase == null) continue;
PsiCaseLabelElementList labelElementList = statementBase.getCaseLabelElementList();
if (labelElementList == null) continue;
if (labelElementList.getElements().length == 1) {
tracker.delete(statementBase);
}
else {
tracker.delete(element);
}
}
}
}
private static PsiExpression createSimplifiedReplacement(PsiExpression expression) {
final PsiExpression[] result = {(PsiExpression)expression.copy()};
final ExpressionVisitor expressionVisitor = new ExpressionVisitor(expression.getManager(), true);

View File

@@ -0,0 +1,27 @@
// "Remove guard expression" "true-preview"
import org.jetbrains.annotations.*;
import java.math.*;
public class Foo {
record Price(BigDecimal value) {
}
@Nullable
public Price price;
public String test() {
return switch (price) {
case Price p -> switch (p.value().multiply(BigDecimal.valueOf(100)).intValue()) {
case int i when i < 0 -> throw new IllegalStateException("Price is negative: " + p);
case 0 -> "free";
case 1, 2, 3, 4, 5, 6, 7, 8, 9 -> "cheap";
case int i when i < 100_00 -> "regular";
case int i when i < 1000_00 -> "expensive";
case int i -> "pricey";
};
case null -> "priceless";
};
}
}

View File

@@ -0,0 +1,27 @@
// "Remove guard expression" "true-preview"
import org.jetbrains.annotations.*;
import java.math.*;
public class Foo {
record Price(BigDecimal value) {
}
@Nullable
public Price price;
public String test() {
return switch (price) {
case Price p -> switch (p.value().multiply(BigDecimal.valueOf(100)).intValue()) {
case int i when i < 0 -> throw new IllegalStateException("Price is negative: " + p);
case 0 -> "free";
case 1, 2, 3, 4, 5, 6, 7, 8, 9 -> "cheap";
case int i when i < 100_00 -> "regular";
case int i when i < 1000_00 -> "expensive";
case int i -> "pricey";
};
case null -> "priceless";
};
}
}

View File

@@ -0,0 +1,28 @@
// "Remove guard expression" "true-preview"
import org.jetbrains.annotations.*;
import java.math.*;
public class Foo {
record Price(BigDecimal value) {
}
@Nullable
public Price price;
public String test() {
return switch (price) {
case Price p -> switch (p.value().multiply(BigDecimal.valueOf(100)).intValue()) {
case int i when i < 0 -> throw new IllegalStateException("Price is negative: " + p);
case 0 -> "free";
case 1, 2, 3, 4, 5, 6, 7, 8, 9 -> "cheap";
case int i when i < 100_00 -> "regular";
case int i when i < 1000_00 -> "expensive";
case int i -> "pricey";
case null -> throw new IllegalStateException("Price is out of range: " + p); //non-compilable, only for tests
};
case null -> "priceless";
};
}
}

View File

@@ -0,0 +1,27 @@
// "Remove guard expression" "true-preview"
import org.jetbrains.annotations.*;
import java.math.*;
public class Foo {
record Price(BigDecimal value) {
}
@Nullable
public Price price;
public String test() {
return switch (price) {
case Price p -> switch (p.value().multiply(BigDecimal.valueOf(100)).intValue()) {
case int i when i < 0 -> throw new IllegalStateException("Price is negative: " + p);
case 0 -> "free";
case 1, 2, 3, 4, 5, 6, 7, 8, 9 -> "cheap";
case int i when i < 100_00 -> "regular";
case int i when i < 1000_00 -> "expensive";
case int i -> "pricey";
};
case null -> "priceless";
};
}
}

View File

@@ -0,0 +1,29 @@
// "Remove guard expression" "true-preview"
import org.jetbrains.annotations.*;
import java.math.*;
public class Foo {
record Price(BigDecimal value) {
}
@Nullable
public Price price;
public String test() {
return switch (price) {
case Price p -> switch (p.value().multiply(BigDecimal.valueOf(100)).intValue()) {
case int i when i < 0 -> throw new IllegalStateException("Price is negative: " + p);
case 0 -> "free";
case 1, 2, 3, 4, 5, 6, 7, 8, 9 -> "cheap";
case int i when i < 100_00 -> "regular";
case int i when i < 1000_00 -> "expensive";
case int i when i >= <caret>1000_00 -> "pricey";
case int i when i == 1000_01 -> "pricey";
default -> throw new IllegalStateException("Price is out of range: " + p);
};
case null -> "priceless";
};
}
}

View File

@@ -0,0 +1,28 @@
// "Remove guard expression" "true-preview"
import org.jetbrains.annotations.*;
import java.math.*;
public class Foo {
record Price(BigDecimal value) {
}
@Nullable
public Price price;
public String test() {
return switch (price) {
case Price p -> switch (p.value().multiply(BigDecimal.valueOf(100)).intValue()) {
case int i when i < 0 -> throw new IllegalStateException("Price is negative: " + p);
case 0 -> "free";
case 1, 2, 3, 4, 5, 6, 7, 8, 9 -> "cheap";
case int i when i < 100_00 -> "regular";
case int i when i < 1000_00 -> "expensive";
case int i when i >= <caret>1000_00 -> "pricey";
case int i -> "any";
};
case null -> "priceless";
};
}
}

View File

@@ -0,0 +1,28 @@
// "Remove guard expression" "true-preview"
import org.jetbrains.annotations.*;
import java.math.*;
public class Foo {
record Price(BigDecimal value) {
}
@Nullable
public Price price;
public String test() {
return switch (price) {
case Price p -> switch (p.value().multiply(BigDecimal.valueOf(100)).intValue()) {
case int i when i < 0 -> throw new IllegalStateException("Price is negative: " + p);
case 0 -> "free";
case 1, 2, 3, 4, 5, 6, 7, 8, 9 -> "cheap";
case int i when i < 100_00 -> "regular";
case int i when i < 1000_00 -> "expensive";
case int i when i >= <caret>1000_00 -> "pricey";
case null, default -> throw new IllegalStateException("Price is out of range: " + p); //non-compilable, only for tests
};
case null -> "priceless";
};
}
}

View File

@@ -0,0 +1,28 @@
// "Remove guard expression" "true-preview"
import org.jetbrains.annotations.*;
import java.math.*;
public class Foo {
record Price(BigDecimal value) {
}
@Nullable
public Price price;
public String test() {
return switch (price) {
case Price p -> switch (p.value().multiply(BigDecimal.valueOf(100)).intValue()) {
case int i when i < 0 -> throw new IllegalStateException("Price is negative: " + p);
case 0 -> "free";
case 1, 2, 3, 4, 5, 6, 7, 8, 9 -> "cheap";
case int i when i < 100_00 -> "regular";
case int i when i < 1000_00 -> "expensive";
case int i when i >= <caret>1000_00 -> "pricey";
case Integer i -> "any";
};
case null -> "priceless";
};
}
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// Copyright 2000-2025 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.quickfix;
import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase;
@@ -7,7 +7,7 @@ import com.intellij.codeInspection.dataFlow.ConstantValueInspection;
import com.intellij.testFramework.LightProjectDescriptor;
import org.jetbrains.annotations.NotNull;
import static com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase.JAVA_21;
import static com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase.JAVA_23;
/**
* @see UnwrapIfStatementFixTest -- more tests for the same quickfix
@@ -21,7 +21,7 @@ public class SimplifyBooleanExpressionFixTest extends LightQuickFixParameterized
@Override
protected @NotNull LightProjectDescriptor getProjectDescriptor() {
return JAVA_21;
return JAVA_23;
}
@Override