diff --git a/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java b/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java index c95e416b5058..81954cca6222 100644 --- a/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/sameParameterValue/SameParameterValueInspection.java @@ -4,13 +4,14 @@ package com.intellij.codeInspection.sameParameterValue; import com.intellij.analysis.AnalysisScope; import com.intellij.codeInsight.daemon.impl.UnusedSymbolUtil; import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo; +import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils; import com.intellij.codeInsight.options.JavaInspectionControls; import com.intellij.codeInspection.*; import com.intellij.codeInspection.deadCode.UnusedDeclarationInspectionBase; import com.intellij.codeInspection.options.OptPane; import com.intellij.codeInspection.reference.*; import com.intellij.java.JavaBundle; -import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressManager; @@ -18,6 +19,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; +import com.intellij.psi.search.LocalSearchScope; import com.intellij.psi.search.searches.OverridingMethodsSearch; import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.PsiFormatUtil; @@ -65,10 +67,6 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool ); } - protected LocalQuickFix createFix(String paramName, String value) { - return new InlineParameterValueFix(paramName, value); - } - @Override public CommonProblemDescriptor @Nullable [] checkElement(@NotNull RefEntity refEntity, @NotNull AnalysisScope scope, @@ -76,7 +74,7 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool @NotNull GlobalInspectionContext globalContext, @NotNull ProblemDescriptionsProcessor processor) { List problems = null; - if (refEntity instanceof final RefMethod refMethod) { + if (refEntity instanceof RefMethod refMethod) { if (refMethod.hasSuperMethods() || VisibilityUtil.compare(refMethod.getAccessModifier(), highestModifier) < 0 || @@ -109,13 +107,8 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool @Nullable @Contract("null -> null; !null -> !null") private static List valueToList(@Nullable Object rootValue) { - if (rootValue == null) return null; - if (rootValue instanceof List) { - //noinspection unchecked - return (List)rootValue; - } else { - return new SmartList<>(rootValue); - } + //noinspection unchecked + return rootValue == null || rootValue instanceof List ? (List)rootValue : new SmartList<>(rootValue); } @Override @@ -161,9 +154,7 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool if (hint == null) return null; final int spaceIdx = hint.indexOf(' '); if (spaceIdx == -1 || spaceIdx >= hint.length() - 1) return null; //invalid hint - final String paramName = hint.substring(0, spaceIdx); - final String value = hint.substring(spaceIdx + 1); - return createFix(paramName, value); + return new InlineParameterValueFix(hint.substring(0, spaceIdx), hint.substring(spaceIdx + 1)); } @Override @@ -178,15 +169,14 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool return new LocalSameParameterValueInspection(this); } - private @Nullable ProblemDescriptor registerProblem(@NotNull InspectionManager manager, - @NotNull UParameter parameter, - Object value, - boolean suggestFix) { + private static @Nullable ProblemDescriptor registerProblem(@NotNull InspectionManager manager, + @NotNull UParameter parameter, + Object value, + boolean suggestFix) { final String name = parameter.getName(); if (name == null || name.isEmpty()) return null; String shortName; String stringPresentation; - if (value instanceof PsiType) { stringPresentation = ((PsiType)value).getCanonicalText() + ".class"; shortName = ((PsiType)value).getPresentableText() + ".class"; @@ -209,12 +199,13 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool } PsiElement anchor = ObjectUtils.notNull(UDeclarationKt.getAnchorPsi(parameter), parameter); if (!anchor.isPhysical()) return null; + String value1 = stringPresentation.startsWith("\"\"") + ? stringPresentation + : StringUtil.escapeLineBreak(stringPresentation); return manager.createProblemDescriptor(anchor, JavaBundle.message("inspection.same.parameter.problem.descriptor", StringUtil.unquoteString(shortName)), - suggestFix ? createFix(name, stringPresentation.startsWith("\"\"") - ? stringPresentation - : StringUtil.escapeLineBreak(stringPresentation)) : null, + suggestFix ? new InlineParameterValueFix(name, value1) : null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false); } @@ -256,42 +247,22 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool final PsiElement element = descriptor.getPsiElement(); final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class); if (method == null) return; - PsiParameter parameter = findParameter(method, element); + PsiParameter parameter = PsiTreeUtil.getParentOfType(element, PsiParameter.class, false); + if (parameter == null) { + parameter = + ContainerUtil.find(method.getParameterList().getParameters(), (param) -> Comparing.strEqual(param.getName(), myParameterName)); + } if (parameter == null) return; - final PsiExpression defToInline; - try { - defToInline = JavaPsiFacade.getElementFactory(project).createExpressionFromText(myValue, parameter); - } - catch (IncorrectOperationException e) { - return; - } - inlineSameParameterValue(method, parameter, defToInline); + final PsiExpression expression = JavaPsiFacade.getElementFactory(project).createExpressionFromText(myValue, parameter); + inlineSameParameterValue(method, parameter, expression); } @Override public @NotNull IntentionPreviewInfo generatePreview(@NotNull Project project, @NotNull ProblemDescriptor previewDescriptor) { - final PsiElement element = previewDescriptor.getPsiElement(); - final PsiMethod method = PsiTreeUtil.getParentOfType(element, PsiMethod.class); - if (method == null) return IntentionPreviewInfo.EMPTY; - final PsiParameter parameter = findParameterByName(method); - if (parameter == null) return IntentionPreviewInfo.EMPTY; - Collection references = ReferencesSearch.search(parameter).findAll(); - final PsiExpression defToInline = JavaPsiFacade.getElementFactory(project).createExpressionFromText(myValue, parameter); - references.forEach((ref) -> ref.getElement().replace(defToInline)); - parameter.delete(); + applyFix(project, previewDescriptor); return IntentionPreviewInfo.DIFF; } - private @Nullable PsiParameter findParameter(PsiMethod method, PsiElement descriptorElement) { - PsiParameter parameter = PsiTreeUtil.getParentOfType(descriptorElement, PsiParameter.class, false); - if (parameter == null) parameter = findParameterByName(method); - return parameter; - } - - private @Nullable PsiParameter findParameterByName(PsiMethod method) { - return ContainerUtil.find(method.getParameterList().getParameters(), (param) -> Comparing.strEqual(param.getName(), myParameterName)); - } - @Override public boolean startInWriteAction() { return false; @@ -302,12 +273,17 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool Collection methods = new ArrayList<>(); methods.add(method); Project project = method.getProject(); - if (!ProgressManager.getInstance() - .runProcessWithProgressSynchronously(() -> { methods.addAll(OverridingMethodsSearch.search(method).findAll()); }, - JavaBundle.message("progress.title.search.for.overriding.methods"), true, project)) { - return; + boolean preview = IntentionPreviewUtils.isIntentionPreviewActive(); + if (!preview) { + if (!ProgressManager.getInstance().runProcessWithProgressSynchronously( + () -> { + methods.addAll(OverridingMethodsSearch.search(method).findAll()); + }, + JavaBundle.message("progress.title.search.for.overriding.methods"), true, project)) { + return; + } + if (!CommonRefactoringUtil.checkReadOnlyStatus(project, methods, true)) return; } - if (!CommonRefactoringUtil.checkReadOnlyStatus(project, methods, true)) return; int parameterIndex = method.getParameterList().getParameterIndex(parameter); Map> paramsToInline = new HashMap<>(); @@ -326,29 +302,50 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool } if (!BaseRefactoringProcessor.processConflicts(project, conflicts)) return; - ApplicationManager.getApplication().runWriteAction(() -> { - for (Map.Entry> entry : paramsToInline.entrySet()) { - Collection refsToInline = entry.getValue(); - try { - PsiExpression[] exprs = new PsiExpression[refsToInline.size()]; - int idx = 0; - for (PsiReference reference : refsToInline) { - if (reference instanceof PsiJavaCodeReferenceElement) { - exprs[idx++] = CommonJavaInlineUtil.getInstance().inlineVariable(entry.getKey(), defToInline, (PsiJavaCodeReferenceElement)reference, null); - } + if (preview) { + inlineParameters(defToInline, paramsToInline); + final boolean vararg = parameter.isVarArgs(); + parameter.delete(); + Collection calls = ReferencesSearch.search(method, new LocalSearchScope(method.getContainingFile())).findAll(); + for (PsiReference call : calls) { + PsiElement parent = call.getElement().getParent(); + if (parent instanceof PsiMethodCallExpression methodCallExpression) { + PsiExpression[] arguments = methodCallExpression.getArgumentList().getExpressions(); + if (vararg) { + methodCallExpression.deleteChildRange(arguments[parameterIndex], arguments[arguments.length - 1]); } - - for (PsiExpression expr : exprs) { - if (expr != null) CommonJavaRefactoringUtil.tryToInlineArrayCreationForVarargs(expr); + else { + arguments[parameterIndex].delete(); } } - catch (IncorrectOperationException e) { - LOG.error(e); - } } - }); + } + else { + WriteAction.run(() -> inlineParameters(defToInline, paramsToInline)); + removeParameter(method, parameter); + } + } - removeParameter(method, parameter); + private static void inlineParameters(PsiExpression defToInline, Map> paramsToInline) { + for (Map.Entry> entry : paramsToInline.entrySet()) { + Collection refsToInline = entry.getValue(); + try { + PsiExpression[] exprs = new PsiExpression[refsToInline.size()]; + int idx = 0; + for (PsiReference reference : refsToInline) { + if (reference instanceof PsiJavaCodeReferenceElement) { + exprs[idx++] = CommonJavaInlineUtil.getInstance().inlineVariable(entry.getKey(), defToInline, (PsiJavaCodeReferenceElement)reference, null); + } + } + + for (PsiExpression expr : exprs) { + if (expr != null) CommonJavaRefactoringUtil.tryToInlineArrayCreationForVarargs(expr); + } + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } } public static void removeParameter(PsiMethod method, PsiParameter parameter) { @@ -473,8 +470,8 @@ public class SameParameterValueInspection extends GlobalJavaBatchInspectionTool if (Boolean.FALSE.equals(isFixAvailable) && myGlobal.ignoreWhenRefactoringIsComplicated) return true; Object presentableValue = value; if (valueList != null && valueList.size() == 1 && valueList.get(0) == null) presentableValue = valueList.get(0); - ProblemDescriptor descriptor = - myGlobal.registerProblem(holder.getManager(), parameter, presentableValue, Boolean.TRUE.equals(isFixAvailable)); + ProblemDescriptor descriptor = + registerProblem(holder.getManager(), parameter, presentableValue, Boolean.TRUE.equals(isFixAvailable)); if (descriptor != null) { holder.registerProblem(descriptor); } diff --git a/java/java-tests/testData/inspection/sameParameterValueQuickFix/Simple.after.java b/java/java-tests/testData/inspection/sameParameterValueQuickFix/Simple.after.java new file mode 100644 index 000000000000..dbed8ca680d2 --- /dev/null +++ b/java/java-tests/testData/inspection/sameParameterValueQuickFix/Simple.after.java @@ -0,0 +1,10 @@ +class Simple { + + void x() { + System.out.println(10); + } + + void y() { + x(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/inspection/sameParameterValueQuickFix/Simple.java b/java/java-tests/testData/inspection/sameParameterValueQuickFix/Simple.java new file mode 100644 index 000000000000..f4e46c051614 --- /dev/null +++ b/java/java-tests/testData/inspection/sameParameterValueQuickFix/Simple.java @@ -0,0 +1,10 @@ +class Simple { + + void x(int i) { + System.out.println(i); + } + + void y() { + x(10); + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/SameParameterValueQuickFixTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/SameParameterValueQuickFixTest.java new file mode 100644 index 000000000000..17e7bacf2a79 --- /dev/null +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/SameParameterValueQuickFixTest.java @@ -0,0 +1,41 @@ +// 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.java.codeInspection; + +import com.intellij.JavaTestUtil; +import com.intellij.codeInsight.intention.IntentionAction; +import com.intellij.codeInspection.LocalInspectionTool; +import com.intellij.codeInspection.sameParameterValue.SameParameterValueInspection; +import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Bas Leijdekkers + */ +public final class SameParameterValueQuickFixTest extends LightJavaCodeInsightFixtureTestCase { + + public void testSimple() { + doTest(); + } + + private void doTest() { + doNamedTest(getTestName(false)); + } + + private void doNamedTest(String name) { + LocalInspectionTool inspection = new SameParameterValueInspection().getSharedLocalInspectionTool(); + myFixture.enableInspections(inspection); + myFixture.configureByFile(name + ".java"); + myFixture.testHighlighting(true, false, false); + final @NotNull List intentions = myFixture.filterAvailableIntentions("Inline value"); + assertEquals("intention not found", 1, intentions.size()); + myFixture.checkPreviewAndLaunchAction(intentions.get(0)); + myFixture.checkResultByFile(name + ".after.java"); + } + + @Override + protected String getTestDataPath() { + return JavaTestUtil.getJavaTestDataPath() + "/inspection/sameParameterValueQuickFix"; + } +}