[java-inspections] Do not suggest a fix which breaks the compilation (removing used pattern var)

Fixes IDEA-360403 Quick-fix for always-true pattern breaks the code

GitOrigin-RevId: eb71b14424e628c6b9ea9ca115bc904447e9e7f6
This commit is contained in:
Tagir Valeev
2024-10-17 10:31:16 +02:00
committed by intellij-monorepo-bot
parent 039cec877f
commit 9e1742e86a
2 changed files with 51 additions and 5 deletions

View File

@@ -36,6 +36,7 @@ import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ObjectUtils;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.*;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -47,22 +48,47 @@ import static com.intellij.psi.JavaTokenType.WHEN_KEYWORD;
public class SimplifyBooleanExpressionFix extends PsiUpdateModCommandAction<PsiExpression> {
private static final Logger LOG = Logger.getInstance(SimplifyBooleanExpressionFix.class);
enum SideEffectStatus {
NO_SIDE_EFFECTS,
CAN_BE_EXTRACTED,
MAY_CHANGE_SEMANTICS,
BREAKS_COMPILATION
}
private final boolean mySubExpressionValue;
private final @NotNull SideEffectStatus mySideEffectStatus;
public SimplifyBooleanExpressionFix(@NotNull PsiExpression subExpression, boolean subExpressionValue) {
super(subExpression);
mySubExpressionValue = subExpressionValue;
mySideEffectStatus = computeStatus(subExpression);
}
private @IntentionName @NotNull String getText(@NotNull PsiExpression subExpression) {
String suffix = "";
if (SideEffectChecker.mayHaveSideEffects(subExpression, e -> shouldIgnore(e, subExpression))) {
suffix = canExtractSideEffect(subExpression) ? QuickFixBundle.message("simplify.boolean.expression.extracting.side.effects")
: JavaBundle.message("quickfix.text.suffix.may.change.semantics");
}
String suffix = switch (mySideEffectStatus) {
case NO_SIDE_EFFECTS, BREAKS_COMPILATION -> "";
case CAN_BE_EXTRACTED -> QuickFixBundle.message("simplify.boolean.expression.extracting.side.effects");
case MAY_CHANGE_SEMANTICS -> JavaBundle.message("quickfix.text.suffix.may.change.semantics");
};
return getIntentionText(subExpression, mySubExpressionValue) + suffix;
}
private SideEffectStatus computeStatus(@NotNull PsiExpression expression) {
return StreamEx.of(SideEffectChecker.extractSideEffectExpressions(expression))
.map(sideEffectExpression -> {
if (sideEffectExpression instanceof PsiInstanceOfExpression instanceOf) {
return shouldIgnore(instanceOf, expression) ? SideEffectStatus.NO_SIDE_EFFECTS :
canExtractSideEffect(sideEffectExpression) ? SideEffectStatus.CAN_BE_EXTRACTED :
SideEffectStatus.BREAKS_COMPILATION;
}
else {
return canExtractSideEffect(sideEffectExpression) ? SideEffectStatus.CAN_BE_EXTRACTED : SideEffectStatus.MAY_CHANGE_SEMANTICS;
}
})
.max(Comparator.naturalOrder())
.orElse(SideEffectStatus.NO_SIDE_EFFECTS);
}
private boolean shouldIgnore(PsiElement e, PsiExpression subExpression) {
return e instanceof PsiInstanceOfExpression &&
!ContainerUtil.exists(JavaPsiPatternUtil.getExposedPatternVariables(((PsiInstanceOfExpression)e)),
@@ -119,6 +145,7 @@ public class SimplifyBooleanExpressionFix extends PsiUpdateModCommandAction<PsiE
public boolean isAvailable(@NotNull PsiExpression expression) {
if (PsiUtil.isAccessedForWriting(expression)) return false;
if (mySideEffectStatus == SideEffectStatus.BREAKS_COMPILATION) return false;
PsiElement element = PsiUtil.skipParenthesizedExprUp(expression);
PsiElement parent = element == null ? null : element.getParent();
if (parent instanceof PsiDoWhileStatement && containsBreakOrContinue((PsiDoWhileStatement)parent)) return false;

View File

@@ -0,0 +1,19 @@
// "Simplify 'u instanceof Upper(Lower l)' to true (may change semantics)" "false"
class X {
void test() {
record Lower(int a, int b) {
}
record Upper(Lower lower) {
}
Object rec = new Upper(new Lower(0, 0));
switch (rec) {
case Upper u when u instanceof <caret>Upper(Lower l) && l instanceof Lower(int a, int b) -> {
System.out.println(u);
System.out.println(l);
System.out.println(a);
}
default -> throw new IllegalStateException("Unexpected value: " + rec);
}
}
}