[java-inspections] SwitchStatementWithTooFewBranchesInspection: deal with side effects when unwrapping switch expression

GitOrigin-RevId: 65421bfe8edf8962161919991fbb9eaa3671f6d9
This commit is contained in:
Tagir Valeev
2023-03-20 12:49:53 +01:00
committed by intellij-monorepo-bot
parent 338f8674e2
commit 62741ff30a
4 changed files with 72 additions and 20 deletions

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-2023 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.BlockUtils;
@@ -21,7 +21,6 @@ import com.intellij.util.SmartList;
import com.siyeh.ig.psiutils.*;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
@@ -157,26 +156,13 @@ public class UnwrapSwitchLabelFix implements LocalQuickFix {
}
}
/**
* Unwraps switch expression if it consists of single expression-branch; does nothing otherwise
*
* @param switchExpression expression to unwrap
*/
public static void unwrapExpression(@NotNull PsiSwitchExpression switchExpression) {
unwrapExpression(switchExpression, null);
}
private static void unwrapExpression(@NotNull PsiSwitchExpression switchExpression, @Nullable PsiCaseLabelElement label) {
private static void unwrapExpression(@NotNull PsiSwitchExpression switchExpression, @NotNull PsiCaseLabelElement label) {
PsiCodeBlock body = switchExpression.getBody();
if (body == null) return;
PsiStatement[] statements = body.getStatements();
if (statements.length != 1 || !(statements[0] instanceof PsiSwitchLabeledRuleStatement rule)) return;
PsiStatement ruleBody = rule.getBody();
if (!(ruleBody instanceof PsiExpressionStatement expressionStatement)) return;
if (label == null) {
new CommentTracker().replaceAndRestoreComments(switchExpression, expressionStatement.getExpression());
return;
}
CodeBlockSurrounder surrounder = CodeBlockSurrounder.forExpression(switchExpression);
if (surrounder != null) {
CodeBlockSurrounder.SurroundResult surroundResult = surrounder.surround();

View File

@@ -0,0 +1,11 @@
// "Unwrap 'switch'" "true-preview"
class X {
int[] someArray;
native boolean someCondition(int i);
void test(int i) {
--i;
int x = 1;
}
}

View File

@@ -0,0 +1,12 @@
// "Unwrap 'switch'" "true-preview"
class X {
int[] someArray;
native boolean someCondition(int i);
void test(int i) {
int x = <caret>switch (someArray[--i]) {
default -> 1;
};
}
}

View File

@@ -16,7 +16,6 @@
package com.siyeh.ig.controlflow;
import com.intellij.codeInsight.daemon.impl.quickfix.ConvertSwitchToIfIntention;
import com.intellij.codeInsight.daemon.impl.quickfix.UnwrapSwitchLabelFix;
import com.intellij.codeInspection.CleanupLocalInspectionTool;
import com.intellij.codeInspection.CommonQuickFixBundle;
import com.intellij.codeInspection.ProblemDescriptor;
@@ -31,7 +30,7 @@ import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.DelegatingFix;
import com.siyeh.ig.InspectionGadgetsFix;
import com.siyeh.ig.psiutils.SwitchUtils;
import com.siyeh.ig.psiutils.*;
import org.jdom.Element;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -103,6 +102,46 @@ public class SwitchStatementWithTooFewBranchesInspection extends BaseInspection
return new MinimumSwitchBranchesVisitor();
}
/**
* Unwraps switch expression if it consists of single expression-branch; does nothing otherwise
*
* @param switchExpression expression to unwrap
*/
private static void unwrapExpression(@NotNull PsiSwitchExpression switchExpression) {
PsiExpression expression = getOnlyExpression(switchExpression);
if (expression == null) return;
PsiExpression selector = switchExpression.getExpression();
CommentTracker tracker = new CommentTracker();
if (selector != null) {
List<PsiExpression> expressions = SideEffectChecker.extractSideEffectExpressions(selector);
if (!expressions.isEmpty()) {
expressions.forEach(tracker::markUnchanged);
PsiStatement[] sideEffects = StatementExtractor.generateStatements(expressions, selector);
CodeBlockSurrounder surrounder = CodeBlockSurrounder.forExpression(switchExpression);
if (surrounder != null) {
CodeBlockSurrounder.SurroundResult result = surrounder.surround();
PsiStatement anchor = result.getAnchor();
for (PsiStatement effect : sideEffects) {
anchor.getParent().addBefore(effect, anchor);
}
switchExpression = (PsiSwitchExpression)result.getExpression();
}
}
}
tracker.replaceAndRestoreComments(switchExpression, expression);
}
@Nullable
private static PsiExpression getOnlyExpression(@NotNull PsiSwitchExpression switchExpression) {
PsiCodeBlock body = switchExpression.getBody();
if (body == null) return null;
PsiStatement[] statements = body.getStatements();
if (statements.length != 1 || !(statements[0] instanceof PsiSwitchLabeledRuleStatement rule)) return null;
PsiStatement ruleBody = rule.getBody();
if (!(ruleBody instanceof PsiExpressionStatement expressionStatement)) return null;
return expressionStatement.getExpression();
}
private class MinimumSwitchBranchesVisitor extends BaseInspectionVisitor {
@Override
public void visitSwitchExpression(@NotNull PsiSwitchExpression expression) {
@@ -145,7 +184,11 @@ public class SwitchStatementWithTooFewBranchesInspection extends BaseInspection
else {
PsiStatement[] statements = body.getStatements();
if (statements.length == 1 && statements[0] instanceof PsiSwitchLabeledRuleStatement statement) {
fixIsAvailable = SwitchUtils.isDefaultLabel(statement) && statement.getBody() instanceof PsiExpressionStatement;
fixIsAvailable = SwitchUtils.isDefaultLabel(statement) &&
statement.getBody() instanceof PsiExpressionStatement &&
(block.getExpression() == null ||
!SideEffectChecker.mayHaveSideEffects(block.getExpression()) ||
CodeBlockSurrounder.canSurround(block.getExpression()));
}
else {
fixIsAvailable = false;
@@ -182,7 +225,7 @@ public class SwitchStatementWithTooFewBranchesInspection extends BaseInspection
if (block instanceof PsiSwitchStatement) {
ConvertSwitchToIfIntention.doProcessIntention((PsiSwitchStatement)block);
} else if (block instanceof PsiSwitchExpression) {
UnwrapSwitchLabelFix.unwrapExpression((PsiSwitchExpression)block);
unwrapExpression((PsiSwitchExpression)block);
}
}
}