[java] IDEA-353981 'Rename to ignored' fix: ModCommand, allow 'fix all' action

GitOrigin-RevId: 83676caca1d4a0f6308d649efd92d6f58845b57e
This commit is contained in:
Tagir Valeev
2024-05-23 18:14:21 +02:00
committed by intellij-monorepo-bot
parent 11599e6cae
commit 3b688121d2
10 changed files with 107 additions and 25 deletions

View File

@@ -385,7 +385,7 @@ public abstract class QuickFixFactory {
public abstract IntentionAction createCreateGetterOrSetterFix(boolean createGetter, boolean createSetter, @NotNull PsiField field);
@NotNull
public abstract LocalQuickFixAndIntentionActionOnPsiElement createRenameToIgnoredFix(@NotNull PsiNamedElement namedElement, boolean useElementNameAsSuffix);
public abstract IntentionAction createRenameToIgnoredFix(@NotNull PsiVariable namedElement, boolean useElementNameAsSuffix);
@NotNull
public abstract IntentionAction createEnableOptimizeImportsOnTheFlyFix();

View File

@@ -15,6 +15,12 @@
*/
package com.intellij.codeInsight.daemon.impl.quickfix;
import com.intellij.codeInsight.CodeInsightBundle;
import com.intellij.java.JavaBundle;
import com.intellij.modcommand.ActionContext;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.modcommand.Presentation;
import com.intellij.modcommand.PsiUpdateModCommandAction;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.JavaFeature;
import com.intellij.psi.*;
@@ -22,36 +28,60 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.util.PsiUtil;
import com.siyeh.ig.psiutils.VariableAccessUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class RenameToIgnoredFix extends RenameElementFix {
import java.util.List;
public class RenameToIgnoredFix extends PsiUpdateModCommandAction<PsiVariable> {
private static final String PREFIX = "ignored";
private final String myName;
private RenameToIgnoredFix(@NotNull PsiNamedElement place, @NotNull String name) {
super(place, name);
private RenameToIgnoredFix(@NotNull PsiVariable place, @NotNull String name) {
super(place);
myName = name;
}
@Override
protected void invoke(@NotNull ActionContext context, @NotNull PsiVariable variable, @NotNull ModPsiUpdater updater) {
List<PsiReferenceExpression> references = VariableAccessUtils.getVariableReferences(variable);
variable.setName(myName);
for (PsiReferenceExpression reference : references) {
reference.bindToElement(variable);
}
}
@Override
protected @Nullable Presentation getPresentation(@NotNull ActionContext context, @NotNull PsiVariable variable) {
return Presentation.of(CodeInsightBundle.message("rename.named.element.text", variable.getName(), myName));
}
@Override
public @NotNull String getFamilyName() {
return JavaBundle.message("intention.family.name.rename.to.ignored");
}
/**
* @param useElementNameAsSuffix if true, let the fix suggest the variable name that consists of the "ignored" and name of the element
* e.g. ignoredVar
* <p>if false, let the fix suggest the variable that consists of the "ignored" and some number
* e.g. ignored1.
* If variable can be unnamed (place and language level allows, and it's totally unused), renaming to unnamed
* If a variable can be unnamed (place and language level allows, and it's totally unused), renaming to unnamed
* will be suggested instead.
*/
public static RenameToIgnoredFix createRenameToIgnoreFix(@NotNull PsiNamedElement element, boolean useElementNameAsSuffix) {
if (element instanceof PsiVariable variable && canBeUnnamed(variable)
&& !VariableAccessUtils.variableIsUsed(variable, PsiUtil.getVariableCodeBlock(variable, null))) {
public static RenameToIgnoredFix createRenameToIgnoreFix(@NotNull PsiVariable variable, boolean useElementNameAsSuffix) {
if (canBeUnnamed(variable) && !VariableAccessUtils.variableIsUsed(variable, PsiUtil.getVariableCodeBlock(variable, null))) {
return new RenameToIgnoredFix(variable, "_");
}
String baseName = "";
if (useElementNameAsSuffix) {
String elementName = element.getName();
String elementName = variable.getName();
if (elementName != null) {
baseName = StringUtil.capitalize(elementName);
}
}
return new RenameToIgnoredFix(element, JavaCodeStyleManager.getInstance(element.getProject())
.suggestUniqueVariableName(PREFIX + baseName, element, true));
return new RenameToIgnoredFix(variable, JavaCodeStyleManager.getInstance(variable.getProject())
.suggestUniqueVariableName(PREFIX + baseName, variable, true));
}
private static boolean canBeUnnamed(PsiVariable variable) {

View File

@@ -681,9 +681,8 @@ public final class QuickFixFactoryImpl extends QuickFixFactory {
}
@Override
public @NotNull LocalQuickFixAndIntentionActionOnPsiElement createRenameToIgnoredFix(@NotNull PsiNamedElement namedElement,
boolean useElementNameAsSuffix) {
return RenameToIgnoredFix.createRenameToIgnoreFix(namedElement, useElementNameAsSuffix);
public @NotNull IntentionAction createRenameToIgnoredFix(@NotNull PsiVariable namedElement, boolean useElementNameAsSuffix) {
return RenameToIgnoredFix.createRenameToIgnoreFix(namedElement, useElementNameAsSuffix).asIntention();
}
@Override

View File

@@ -2,7 +2,7 @@
package com.intellij.codeInspection.deadCode;
import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInsight.daemon.impl.quickfix.RenameToIgnoredFix;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.ex.EntryPointsManager;
import com.intellij.codeInspection.reference.*;
@@ -61,12 +61,11 @@ class UnusedParametersInspection extends GlobalJavaBatchInspectionTool {
UParameter parameter = refParameter.getUastElement();
PsiElement anchor = UElementKt.getSourcePsiElement(parameter.getUastAnchor());
if (anchor != null) {
final QuickFixFactory quickFixFactory = QuickFixFactory.getInstance();
final List<LocalQuickFix> fixes = new ArrayList<>(2);
fixes.add(new AcceptSuggested(refParameter.getName()));
PsiElement parent = anchor.getParent();
if (parent instanceof PsiNamedElement) {
fixes.add(quickFixFactory.createRenameToIgnoredFix((PsiNamedElement)parent, true));
if (parent instanceof PsiVariable) {
fixes.add(LocalQuickFix.from(RenameToIgnoredFix.createRenameToIgnoreFix((PsiVariable)parent, true)));
}
String message;
if (refMethod.isAbstract()) {

View File

@@ -2,8 +2,8 @@
package com.siyeh.ig.errorhandling;
import com.intellij.codeInsight.Nullability;
import com.intellij.codeInsight.daemon.impl.quickfix.RenameToIgnoredFix;
import com.intellij.codeInsight.intention.LowPriorityAction;
import com.intellij.codeInsight.intention.QuickFixFactory;
import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemsHolder;
@@ -110,17 +110,16 @@ public final class CatchMayIgnoreExceptionInspection extends AbstractBaseJavaLoc
if (block == null) return;
SuppressForTestsScopeFix fix = SuppressForTestsScopeFix.build(CatchMayIgnoreExceptionInspection.this, section);
if (ControlFlowUtils.isEmpty(block, m_ignoreCatchBlocksWithComments, true)) {
var renameFix = QuickFixFactory.getInstance().createRenameToIgnoredFix(parameter, false);
var renameFix = RenameToIgnoredFix.createRenameToIgnoreFix(parameter, false);
AddCatchBodyFix addBodyFix = getAddBodyFix(block);
holder.registerProblem(catchToken, InspectionGadgetsBundle.message("inspection.catch.ignores.exception.empty.message"),
LocalQuickFix.notNullElements(renameFix, addBodyFix, fix));
holder.problem(catchToken, InspectionGadgetsBundle.message("inspection.catch.ignores.exception.empty.message"))
.fix(renameFix).maybeFix(addBodyFix).maybeFix(fix).register();
}
else if (!VariableAccessUtils.variableIsUsed(parameter, section)) {
if (!m_ignoreNonEmptyCatchBlock &&
(!m_ignoreCatchBlocksWithComments || PsiTreeUtil.getChildOfType(block, PsiComment.class) == null)) {
holder.registerProblem(identifier, InspectionGadgetsBundle.message("inspection.catch.ignores.exception.unused.message"),
LocalQuickFix.notNullElements(
QuickFixFactory.getInstance().createRenameToIgnoredFix(parameter, false), fix));
holder.problem(identifier, InspectionGadgetsBundle.message("inspection.catch.ignores.exception.unused.message"))
.fix(RenameToIgnoredFix.createRenameToIgnoreFix(parameter, false)).maybeFix(fix).register();
}
}
else {

View File

@@ -0,0 +1,13 @@
import java.io.IOException;
class AAA {
public static void main(String[] args) {
try {
System.out.println(System.in.read());
} c<caret>atch (IOException ignored) {
} catch (RuntimeException ignored) {
}
}
}

View File

@@ -0,0 +1,13 @@
import java.io.IOException;
class AAA {
public static void main(String[] args) {
try {
System.out.println(System.in.read());
} c<caret>atch (IOException ex) {
} catch (RuntimeException ex2) {
}
}
}

View File

@@ -63,6 +63,30 @@ public final class RenameToIgnoredFixTest extends LightJavaCodeInsightFixtureTes
}""");
});
}
public void testRenameToIgnoredMultiple() {
myFixture.configureByText("Test.java", """
class X {
void test(int[] data) {
for(int <caret>x : data) System.out.println(1);
for(int x : data) System.out.println(2);
for(int x : data) System.out.println(3);
}
}
""");
myFixture.enableInspections(new UnusedDeclarationInspection());
IntentionAction intention = myFixture.findSingleIntention("Fix all 'Unused declaration' problems in file");
myFixture.launchAction(intention);
myFixture.checkResult("""
class X {
void test(int[] data) {
for(int _ : data) System.out.println(1);
for(int _ : data) System.out.println(2);
for(int _ : data) System.out.println(3);
}
}
""");
}
public void testRenameToIgnoredSwitch2() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21, () -> {

View File

@@ -47,6 +47,10 @@ public class CatchMayIgnoreExceptionInspectionFixTest extends IGQuickFixesTestCa
doTest("Rename 'ex' to 'ignored'");
}
public void testRenameToIgnoredFixAll() {
doTest("Fix all 'Catch block may ignore exception' problems in file");
}
public void testRenameToIgnoredJava21() {
IdeaTestUtil.withLevel(getModule(), LanguageLevel.JDK_21_PREVIEW, () -> doTest("Rename 'ex' to '_'"));
}

View File

@@ -1934,3 +1934,4 @@ intention.name.delete.method.with.callees=... along with other private methods u
intention.name.delete.method.only=... and nothing else
intention.family.name.delete.private.method=Delete private method
checkbox.check.for.jdk.updates=Check for JDK updates
intention.family.name.rename.to.ignored=Rename to ignored