diff --git a/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteDelegateImpl.java b/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteDelegateImpl.java index f222beea5818..b25843776b20 100644 --- a/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteDelegateImpl.java +++ b/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteDelegateImpl.java @@ -3,9 +3,9 @@ package com.intellij.refactoring.safeDelete; import com.intellij.psi.*; import com.intellij.psi.impl.source.javadoc.PsiDocMethodOrFieldRef; -import com.intellij.psi.search.searches.ReferencesSearch; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; +import com.intellij.psi.util.JavaPsiRecordUtil; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.refactoring.safeDelete.usageInfo.*; import com.intellij.refactoring.util.LambdaRefactoringUtil; @@ -15,7 +15,6 @@ import com.intellij.util.JavaPsiConstructorUtil; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; -import java.util.Collections; import java.util.List; /** @@ -123,13 +122,17 @@ public final class JavaSafeDeleteDelegateImpl implements JavaSafeDeleteDelegate } @Override - public void createCleanupOverriding(@NotNull PsiElement overriddenFunction, PsiElement @NotNull [] elements2Delete, @NotNull List result) { - if (overriddenFunction instanceof PsiMethod && - JavaSafeDeleteProcessor.canBePrivate((PsiMethod)overriddenFunction, ReferencesSearch.search(overriddenFunction).findAll(), Collections.emptyList(), elements2Delete)) { - result.add(new SafeDeletePrivatizeMethod((PsiMethod)overriddenFunction, (PsiMethod)overriddenFunction)); - } else { - result.add(new SafeDeleteOverrideAnnotation(overriddenFunction, overriddenFunction)); + public void createCleanupOverriding(@NotNull PsiElement overriddenFunction, PsiElement @NotNull [] elements2Delete, + @NotNull List result) { + if (overriddenFunction instanceof PsiMethod method) { + if (JavaPsiRecordUtil.getRecordComponentForAccessor(method) != null || method.findSuperMethods().length > 1) return; + + if (JavaSafeDeleteProcessor.canBePrivate(method, elements2Delete)) { + result.add(new SafeDeletePrivatizeMethod(method, method)); + return; + } } + result.add(new SafeDeleteOverrideAnnotation(overriddenFunction, overriddenFunction)); } @Override diff --git a/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java b/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java index 26865ff6a4d7..c507e5c9b2ca 100644 --- a/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java +++ b/java/java-impl-refactorings/src/com/intellij/refactoring/safeDelete/JavaSafeDeleteProcessor.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.refactoring.safeDelete; import com.intellij.codeInsight.AnnotationUtil; @@ -884,31 +884,20 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase { return null; } - static boolean canBePrivate(@NotNull PsiMethod method, - @NotNull Collection references, - @NotNull Collection deleted, - PsiElement @NotNull [] allElementsToDelete) { + static boolean canBePrivate(@NotNull PsiMethod method, PsiElement @NotNull [] allElementsToDelete) { PsiClass containingClass = method.getContainingClass(); - if(containingClass == null) { + if (containingClass == null) { return false; } - PsiManager manager = method.getManager(); - JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject()); + JavaPsiFacade facade = JavaPsiFacade.getInstance(method.getProject()); + PsiResolveHelper resolveHelper = facade.getResolveHelper(); PsiElementFactory factory = facade.getElementFactory(); - PsiModifierList privateModifierList; - try { - PsiMethod newMethod = factory.createMethod("x3", PsiTypes.voidType()); - privateModifierList = newMethod.getModifierList(); - privateModifierList.setModifierProperty(PsiModifier.PRIVATE, true); - } catch (IncorrectOperationException e) { - LOG.error(e); - return false; - } - for (PsiReference reference : references) { + PsiModifierList privateModifierList = factory.createMethod("x3", PsiTypes.voidType()).getModifierList(); + privateModifierList.setModifierProperty(PsiModifier.PRIVATE, true); + for (PsiReference reference : ReferencesSearch.search(method).findAll()) { PsiElement element = reference.getElement(); - if (!isInside(element, allElementsToDelete) && !isInside(element, deleted) - && !facade.getResolveHelper().isAccessible(method, privateModifierList, element, null, null)) { + if (!isInside(element, allElementsToDelete) && !resolveHelper.isAccessible(method, privateModifierList, element, null, null)) { return false; } } diff --git a/java/java-tests/testData/refactoring/safeDelete/MethodCannotBePrivate.java b/java/java-tests/testData/refactoring/safeDelete/MethodCannotBePrivate.java new file mode 100644 index 000000000000..02fdcf0e1223 --- /dev/null +++ b/java/java-tests/testData/refactoring/safeDelete/MethodCannotBePrivate.java @@ -0,0 +1,17 @@ +class ChildA extends MyAbstractClass implements MyInterface { + @Override + public void buggyMethod() { + System.out.println("ChildA"); + } + public void caller() { + buggyMethod(); + } +} +abstract class MyAbstractClass { + public void buggyMethod() { + System.out.println("buggyMethod from MyAbstractClass"); + } +} +interface MyInterface { + void buggyMethod(); +} \ No newline at end of file diff --git a/java/java-tests/testData/refactoring/safeDelete/MethodCannotBePrivate_after.java b/java/java-tests/testData/refactoring/safeDelete/MethodCannotBePrivate_after.java new file mode 100644 index 000000000000..23efa168a93f --- /dev/null +++ b/java/java-tests/testData/refactoring/safeDelete/MethodCannotBePrivate_after.java @@ -0,0 +1,16 @@ +class ChildA extends MyAbstractClass implements MyInterface { + @Override + public void buggyMethod() { + System.out.println("ChildA"); + } + public void caller() { + buggyMethod(); + } +} +abstract class MyAbstractClass { + public void buggyMethod() { + System.out.println("buggyMethod from MyAbstractClass"); + } +} +interface MyInterface { +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/refactoring/SafeDeleteTest.java b/java/java-tests/testSrc/com/intellij/java/refactoring/SafeDeleteTest.java index 04d04a6e0e94..24d29cba355b 100644 --- a/java/java-tests/testSrc/com/intellij/java/refactoring/SafeDeleteTest.java +++ b/java/java-tests/testSrc/com/intellij/java/refactoring/SafeDeleteTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.java.refactoring; import com.intellij.JavaTestUtil; @@ -83,69 +83,23 @@ public class SafeDeleteTest extends MultiFileTestCase { doTest("IFoo"); } - public void testUsageInExtendsList() { - doSingleFileTest(); - } - - public void testDeepDeleteParameterSimple() { - doSingleFileTest(); - } - - public void testDeepDeleteParameterOtherTypeInBinaryExpression() { - doSingleFileTest(); - } - - public void testDeepDeleteFieldAndAssignedParameter() { - doSingleFileTest(); - } - - public void testImpossibleToDeepDeleteParameter() { - doSingleFileTest(); - } - - public void testNoDeepDeleteParameterUsedInCallQualifier() { - doSingleFileTest(); - } - - public void testNoDeepDeleteParameterUsedInNextArgumentExpression() { - doSingleFileTest(); - } - - public void testToDeepDeleteParameterOverriders() { - doSingleFileTest(); - } - - public void testDeleteParameterOfASiblingMethod() { - doSingleFileTest(); - } - - public void testDeleteMethodCascade() { - doSingleFileTest(); - } - - public void testDeleteMethodKeepEnumValues() { - doSingleFileTest(); - } - - public void testDeleteMethodCascadeRecursive() { - doSingleFileTest(); - } - - public void testDeleteMethodCascadeOverridden() { - doSingleFileTest(); - } - - public void testDeleteParameterAndUpdateJavadocRef() { - doSingleFileTest(); - } - - public void testDeleteConstructorParameterWithAnonymousClassUsage() { - doSingleFileTest(); - } - - public void testAccidentalPropertyRef() { - doSingleFileTest(); - } + public void testUsageInExtendsList() { doSingleFileTest(); } + public void testDeepDeleteParameterSimple() { doSingleFileTest(); } + public void testDeepDeleteParameterOtherTypeInBinaryExpression() { doSingleFileTest(); } + public void testDeepDeleteFieldAndAssignedParameter() { doSingleFileTest(); } + public void testImpossibleToDeepDeleteParameter() { doSingleFileTest(); } + public void testNoDeepDeleteParameterUsedInCallQualifier() { doSingleFileTest(); } + public void testNoDeepDeleteParameterUsedInNextArgumentExpression() { doSingleFileTest(); } + public void testToDeepDeleteParameterOverriders() { doSingleFileTest(); } + public void testDeleteParameterOfASiblingMethod() { doSingleFileTest(); } + public void testDeleteMethodCascade() { doSingleFileTest(); } + public void testDeleteMethodKeepEnumValues() { doSingleFileTest(); } + public void testDeleteMethodCascadeRecursive() { doSingleFileTest(); } + public void testDeleteMethodCascadeOverridden() { doSingleFileTest(); } + public void testDeleteParameterAndUpdateJavadocRef() { doSingleFileTest(); } + public void testDeleteConstructorParameterWithAnonymousClassUsage() { doSingleFileTest(); } + public void testAccidentalPropertyRef() { doSingleFileTest(); } + public void testMethodCannotBePrivate() { doSingleFileTest(); } public void testDeleteMethodWithPropertyUsage() { doTest("Foo");