mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 13:02:30 +07:00
[java-inspections] RemoveInitializerFix2: mod-command action, with chooser
IDEA-323888 Replace 'side effect' dialog in Java quick-fixes with chooser GitOrigin-RevId: 99e43ec42520ff407ad755c1b05cd5c9320bd273
This commit is contained in:
committed by
intellij-monorepo-bot
parent
51c5999d0b
commit
5b29f251c1
@@ -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.codeInspection.defUse;
|
||||
|
||||
import com.intellij.codeInsight.ExpressionUtil;
|
||||
@@ -157,7 +157,7 @@ public class DefUseInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||
|
||||
private static void reportInitializerProblem(PsiVariable psiVariable, ProblemsHolder holder) {
|
||||
List<LocalQuickFix> fixes = ContainerUtil.createMaybeSingletonList(
|
||||
isOnTheFlyOrNoSideEffects(holder.isOnTheFly(), psiVariable, psiVariable.getInitializer()) ? new RemoveInitializerFix() : null);
|
||||
isOnTheFlyOrNoSideEffects(holder.isOnTheFly(), psiVariable, psiVariable.getInitializer()) ? new RemoveInitializerFix2() : null);
|
||||
holder.registerProblem(ObjectUtils.notNull(psiVariable.getInitializer(), psiVariable),
|
||||
JavaBundle.message("inspection.unused.assignment.problem.descriptor2", psiVariable.getName()),
|
||||
fixes.toArray(LocalQuickFix.EMPTY_ARRAY)
|
||||
|
||||
@@ -5,13 +5,15 @@ import com.intellij.codeInsight.BlockUtils;
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.intention.PriorityAction;
|
||||
import com.intellij.codeInspection.CommonQuickFixBundle;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.codeInspection.PsiUpdateModCommandAction;
|
||||
import com.intellij.codeInspection.util.IntentionName;
|
||||
import com.intellij.modcommand.ModPsiUpdater;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.JavaElementKind;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.PsiUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.SideEffectChecker;
|
||||
import com.siyeh.ig.psiutils.StatementExtractor;
|
||||
@@ -24,8 +26,7 @@ import java.util.Objects;
|
||||
|
||||
public class DeleteSideEffectsAwareFix extends PsiUpdateModCommandAction<PsiStatement> {
|
||||
private final SmartPsiElementPointer<PsiExpression> myExpressionPtr;
|
||||
private final @IntentionName String myMessage;
|
||||
private final boolean myIsAvailable;
|
||||
private final boolean myAlwaysAvailable;
|
||||
|
||||
public DeleteSideEffectsAwareFix(@NotNull PsiStatement statement, PsiExpression expression) {
|
||||
this(statement, expression, false);
|
||||
@@ -33,26 +34,9 @@ public class DeleteSideEffectsAwareFix extends PsiUpdateModCommandAction<PsiStat
|
||||
|
||||
public DeleteSideEffectsAwareFix(@NotNull PsiStatement statement, PsiExpression expression, boolean alwaysAvailable) {
|
||||
super(statement);
|
||||
myAlwaysAvailable = alwaysAvailable;
|
||||
SmartPointerManager manager = SmartPointerManager.getInstance(statement.getProject());
|
||||
myExpressionPtr = manager.createSmartPsiElementPointer(expression);
|
||||
List<PsiExpression> sideEffects = SideEffectChecker.extractSideEffectExpressions(expression);
|
||||
if (sideEffects.isEmpty()) {
|
||||
JavaElementKind kind = statement instanceof PsiExpressionStatement ? JavaElementKind.EXPRESSION : JavaElementKind.STATEMENT;
|
||||
myMessage = CommonQuickFixBundle.message("fix.remove.title", kind.object());
|
||||
}
|
||||
else {
|
||||
PsiStatement[] statements = StatementExtractor.generateStatements(sideEffects, expression);
|
||||
if (statements.length == 1 && statements[0] instanceof PsiIfStatement) {
|
||||
myMessage = QuickFixBundle.message("extract.side.effects.convert.to.if");
|
||||
}
|
||||
else {
|
||||
myMessage = QuickFixBundle.message("extract.side.effects", statements.length);
|
||||
}
|
||||
}
|
||||
myIsAvailable = alwaysAvailable ||
|
||||
// "Remove unnecessary parentheses" action is already present which will do the same
|
||||
sideEffects.size() != 1 || !(statement instanceof PsiExpressionStatement) ||
|
||||
sideEffects.get(0) != PsiUtil.skipParenthesizedExprDown(expression);
|
||||
}
|
||||
|
||||
@Nls
|
||||
@@ -63,8 +47,37 @@ public class DeleteSideEffectsAwareFix extends PsiUpdateModCommandAction<PsiStat
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiStatement element) {
|
||||
return myIsAvailable ? Presentation.of(myMessage).withPriority(PriorityAction.Priority.LOW) : null;
|
||||
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiStatement statement) {
|
||||
PsiExpression expression = myExpressionPtr.getElement();
|
||||
if (expression == null) return null;
|
||||
List<PsiExpression> sideEffects = SideEffectChecker.extractSideEffectExpressions(expression);
|
||||
String message = getMessage(expression, sideEffects);
|
||||
if (!myAlwaysAvailable &&
|
||||
// "Remove unnecessary parentheses" action is already present which will do the same
|
||||
sideEffects.size() == 1 && statement instanceof PsiExpressionStatement &&
|
||||
sideEffects.get(0) == PsiUtil.skipParenthesizedExprDown(expression)) {
|
||||
return null;
|
||||
}
|
||||
return Presentation.of(message).withPriority(PriorityAction.Priority.LOW)
|
||||
.withHighlighting(ContainerUtil.map2Array(sideEffects, TextRange.EMPTY_ARRAY, effect -> effect.getTextRange()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param expression expression to remove
|
||||
* @param sideEffects side effects
|
||||
* @return inspection message
|
||||
*/
|
||||
@IntentionName
|
||||
public static @NotNull String getMessage(@NotNull PsiExpression expression, @NotNull List<@NotNull PsiExpression> sideEffects) {
|
||||
if (sideEffects.isEmpty()) {
|
||||
JavaElementKind kind = expression.getParent() instanceof PsiExpressionStatement ? JavaElementKind.EXPRESSION : JavaElementKind.STATEMENT;
|
||||
return CommonQuickFixBundle.message("fix.remove.title", kind.object());
|
||||
}
|
||||
PsiStatement[] statements = StatementExtractor.generateStatements(sideEffects, expression);
|
||||
if (statements.length == 1 && statements[0] instanceof PsiIfStatement) {
|
||||
return QuickFixBundle.message("extract.side.effects.convert.to.if");
|
||||
}
|
||||
return QuickFixBundle.message("extract.side.effects", statements.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -27,7 +27,7 @@ public class RemoveInitializerFix implements LocalQuickFix {
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return JavaBundle.message("inspection.unused.assignment.remove.quickfix");
|
||||
return JavaBundle.message("inspection.unused.assignment.remove.initializer.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// 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.codeInspection;
|
||||
|
||||
import com.intellij.codeInsight.BlockUtils;
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.DeleteElementFix;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.DeleteSideEffectsAwareFix;
|
||||
import com.intellij.java.JavaBundle;
|
||||
import com.intellij.modcommand.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.siyeh.ig.psiutils.CodeBlockSurrounder;
|
||||
import com.siyeh.ig.psiutils.CommentTracker;
|
||||
import com.siyeh.ig.psiutils.SideEffectChecker;
|
||||
import com.siyeh.ig.psiutils.StatementExtractor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class RemoveInitializerFix2 extends ModCommandQuickFix {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return JavaBundle.message("inspection.unused.assignment.remove.initializer.quickfix");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ModCommand perform(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
|
||||
if (!(descriptor.getPsiElement() instanceof PsiExpression initializer)) return ModCommands.nop();
|
||||
if (!(initializer.getParent() instanceof PsiVariable variable)) return ModCommands.nop();
|
||||
List<ModCommandAction> subActions;
|
||||
List<PsiExpression> sideEffects = SideEffectChecker.extractSideEffectExpressions(initializer);
|
||||
if (!sideEffects.isEmpty()) {
|
||||
subActions = List.of(new DeleteElementFix(initializer, JavaBundle.message("delete.initializer.completely")),
|
||||
new SideEffectAwareRemove(variable));
|
||||
}
|
||||
else {
|
||||
subActions = List.of(new DeleteElementFix(initializer));
|
||||
}
|
||||
return new ModChooseAction(JavaBundle.message("inspection.unused.assignment.remove.initializer.quickfix.title"), subActions);
|
||||
}
|
||||
|
||||
static class SideEffectAwareRemove extends PsiUpdateModCommandAction<PsiVariable> {
|
||||
SideEffectAwareRemove(@NotNull PsiVariable variable) {
|
||||
super(variable);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void invoke(@NotNull ActionContext context, @NotNull PsiVariable variable, @NotNull ModPsiUpdater updater) {
|
||||
PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer == null) return;
|
||||
CodeBlockSurrounder surrounder = CodeBlockSurrounder.forExpression(initializer);
|
||||
if (surrounder == null) return;
|
||||
CodeBlockSurrounder.SurroundResult result = surrounder.surround();
|
||||
PsiStatement anchor = result.getAnchor();
|
||||
initializer = result.getExpression();
|
||||
List<PsiExpression> sideEffects = SideEffectChecker.extractSideEffectExpressions(initializer);
|
||||
CommentTracker ct = new CommentTracker();
|
||||
sideEffects.forEach(ct::markUnchanged);
|
||||
PsiStatement[] statements = StatementExtractor.generateStatements(sideEffects, initializer);
|
||||
if (statements.length > 0) {
|
||||
BlockUtils.addBefore(anchor, statements);
|
||||
}
|
||||
PsiElement parent = initializer.getParent();
|
||||
if (parent instanceof PsiVariable) {
|
||||
ct.deleteAndRestoreComments(initializer);
|
||||
} else if (parent instanceof PsiAssignmentExpression) {
|
||||
ct.deleteAndRestoreComments(parent.getParent());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiVariable variable) {
|
||||
PsiExpression initializer = variable.getInitializer();
|
||||
if (initializer == null) return null;
|
||||
if (!CodeBlockSurrounder.canSurround(initializer)) return null;
|
||||
List<PsiExpression> sideEffects = SideEffectChecker.extractSideEffectExpressions(initializer);
|
||||
return Presentation.of(DeleteSideEffectsAwareFix.getMessage(initializer, sideEffects))
|
||||
.withHighlighting(ContainerUtil.map2Array(sideEffects, TextRange.EMPTY_ARRAY, PsiExpression::getTextRange));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getFamilyName() {
|
||||
return QuickFixBundle.message("extract.side.effects.family.name");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// "Remove redundant initializer" "true-preview"
|
||||
class A {
|
||||
void test() {
|
||||
if (!isA() || !isB()) {
|
||||
isC();
|
||||
}
|
||||
boolean b;
|
||||
b = 10;
|
||||
System.out.println(b);
|
||||
}
|
||||
|
||||
native boolean isA();
|
||||
native boolean isB();
|
||||
native boolean isC();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Remove redundant initializer" "true-preview"
|
||||
class A {
|
||||
void test() {
|
||||
boolean b = isA() <caret>&& isB() || isC();
|
||||
b = 10;
|
||||
System.out.println(b);
|
||||
}
|
||||
|
||||
native boolean isA();
|
||||
native boolean isB();
|
||||
native boolean isC();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Remove redundant initializer" "true-preview"
|
||||
class A {
|
||||
private String myFoo;
|
||||
|
||||
protected String abc() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public A(String myFoo) {
|
||||
this.myFoo = myFoo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// "Remove redundant initializer" "true-preview"
|
||||
class A {
|
||||
void testFor() {
|
||||
if (true)
|
||||
for(int i;; i++) {
|
||||
i = 10;
|
||||
System.out.println("Hello!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static int read() {
|
||||
System.out.println();
|
||||
return 0;
|
||||
}}
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Remove redundant initializer" "true-preview"
|
||||
class A {
|
||||
void test() {
|
||||
boolean b;
|
||||
b = 10;
|
||||
System.out.println(b);
|
||||
}
|
||||
|
||||
native boolean isA();
|
||||
native boolean isB();
|
||||
native boolean isC();
|
||||
}
|
||||
@@ -1,13 +1,24 @@
|
||||
// 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.daemon.quickFix.LightQuickFixParameterizedTestCase;
|
||||
import com.intellij.codeInspection.LocalInspectionTool;
|
||||
import com.intellij.codeInspection.defUse.DefUseInspection;
|
||||
import com.intellij.codeInspection.sillyAssignment.SillyAssignmentInspection;
|
||||
import com.intellij.ui.ChooserInterceptor;
|
||||
import com.intellij.ui.UiInterceptors;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class RemoveUnusedAssignmentTest extends LightQuickFixParameterizedTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
String name = getTestName(false);
|
||||
if (name.endsWith("WithSideEffect.java")) {
|
||||
UiInterceptors.register(new ChooserInterceptor(null, "Extract side effect.*"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LocalInspectionTool @NotNull [] configureLocalInspectionTools() {
|
||||
return new LocalInspectionTool[] {new DefUseInspection(), new SillyAssignmentInspection()};
|
||||
|
||||
@@ -753,7 +753,8 @@ inspection.unused.assignment.problem.descriptor4=The value changed at <code>#ref
|
||||
inspection.unused.assignment.problem.descriptor5=The value of pattern variable <code>#ref</code> #loc is never used
|
||||
inspection.unused.assignment.problem.descriptor6=The value of foreach iteration parameter <code>#ref</code> #loc is never used
|
||||
inspection.unused.assignment.remove.assignment.quickfix=Remove redundant assignment
|
||||
inspection.unused.assignment.remove.quickfix=Remove redundant initializer
|
||||
inspection.unused.assignment.remove.initializer.quickfix=Remove redundant initializer
|
||||
inspection.unused.assignment.remove.initializer.quickfix.title=Remove Redundant Initializer
|
||||
inspection.unused.parameter.problem.descriptor=Parameter <code>#ref</code> is not used
|
||||
inspection.unused.parameter.composer=Parameter <code>#ref</code> is not used in any implementation
|
||||
inspection.unused.parameter.composer1=Parameter <code>#ref</code> is not used in this method nor in any of its overriding methods
|
||||
@@ -1860,4 +1861,5 @@ convert.number.binary=binary
|
||||
convert.number.octal=octal
|
||||
convert.number.decimal=decimal
|
||||
convert.number.plain.format=plain format
|
||||
convert.number.scientific.format=scientific format
|
||||
convert.number.scientific.format=scientific format
|
||||
delete.initializer.completely=Delete initializer completely
|
||||
Reference in New Issue
Block a user