Java: Safe Delete should not make method private when it does not compile (IDEA-248028, IDEA-365766)

GitOrigin-RevId: 29071dfc72f3bb572d42b1d7f84e5aaa104323c0
This commit is contained in:
Bas Leijdekkers
2025-01-15 19:47:39 +00:00
committed by intellij-monorepo-bot
parent f42116023e
commit 052a9496b9
5 changed files with 71 additions and 92 deletions
@@ -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<? super UsageInfo> 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<? super UsageInfo> 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
@@ -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<? extends PsiReference> references,
@NotNull Collection<? extends PsiElement> 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;
}
}
@@ -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 buggy<caret>Method();
}
@@ -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 {
}
@@ -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");