mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
safe delete: suggest to delete constructor parameter (IDEA-173595)
when field is deleted and parameter would be unused after removing of assignment
This commit is contained in:
+56
-6
@@ -31,6 +31,7 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.psi.codeStyle.VariableKind;
|
||||
import com.intellij.psi.javadoc.PsiDocTag;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.FunctionalExpressionSearch;
|
||||
import com.intellij.psi.search.searches.OverridingMethodsSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
@@ -398,6 +399,15 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
|
||||
protected int getParameterIdx() {
|
||||
return parameterIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PsiParameter getParameterInCaller(PsiMethod called, int paramIdx, PsiMethod caller) {
|
||||
return delegatingParams.stream()
|
||||
.filter(usage -> caller.equals(usage.getCallerMethod()))
|
||||
.map(usage -> usage.getParameterInCaller())
|
||||
.findFirst()
|
||||
.orElse(super.getParameterInCaller(called, paramIdx, caller));
|
||||
}
|
||||
};
|
||||
TreeUtil.expand(chooser.getTree(), 2);
|
||||
if (!chooser.showAndGet()) {
|
||||
@@ -883,12 +893,24 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
|
||||
|
||||
private static Condition<PsiElement> findFieldUsages(final PsiField psiField, final List<UsageInfo> usages, final PsiElement[] allElementsToDelete) {
|
||||
final Condition<PsiElement> isInsideDeleted = getUsageInsideDeletedFilter(allElementsToDelete);
|
||||
Set<PsiParameter> parameters = new LinkedHashSet<>();
|
||||
ReferencesSearch.search(psiField).forEach(reference -> {
|
||||
if (!isInsideDeleted.value(reference.getElement())) {
|
||||
final PsiElement element = reference.getElement();
|
||||
final PsiElement parent = element.getParent();
|
||||
if (parent instanceof PsiAssignmentExpression && element == ((PsiAssignmentExpression)parent).getLExpression()) {
|
||||
usages.add(new SafeDeleteFieldWriteReference((PsiAssignmentExpression)parent, psiField));
|
||||
PsiExpression rExpression = PsiUtil.skipParenthesizedExprDown(((PsiAssignmentExpression)parent).getRExpression());
|
||||
if (rExpression instanceof PsiReferenceExpression) {
|
||||
PsiElement resolve = ((PsiReferenceExpression)rExpression).resolve();
|
||||
if (resolve instanceof PsiParameter) {
|
||||
PsiParameter parameter = (PsiParameter)resolve;
|
||||
PsiElement scope = parameter.getDeclarationScope();
|
||||
if (scope instanceof PsiMethod && ((PsiMethod)scope).isConstructor()) {
|
||||
parameters.add(parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
TextRange range = reference.getRangeInElement();
|
||||
@@ -900,9 +922,42 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
|
||||
return true;
|
||||
});
|
||||
|
||||
PsiMethod setterPrototype = PropertyUtil.generateSetterPrototype(psiField, psiField.getContainingClass());
|
||||
PsiParameter setterParameter = setterPrototype.getParameterList().getParameters()[0];
|
||||
for (PsiParameter parameter : parameters) {
|
||||
PsiElement scope = parameter.getDeclarationScope();
|
||||
if (scope instanceof PsiMethod) {
|
||||
if (!ReferencesSearch.search(parameter, new LocalSearchScope(scope)).forEach(ref -> {
|
||||
PsiElement element = ref.getElement();
|
||||
if (element instanceof PsiReferenceExpression) {
|
||||
PsiElement parent = PsiUtil.skipParenthesizedExprUp(element.getParent());
|
||||
if (parent instanceof PsiAssignmentExpression) {
|
||||
PsiExpression lExpression = PsiUtil.skipParenthesizedExprDown(((PsiAssignmentExpression)parent).getLExpression());
|
||||
if (lExpression instanceof PsiReferenceExpression && ((PsiReferenceExpression)lExpression).resolve() == psiField) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
})) continue;
|
||||
usages.add(createParameterCallHierarchyUsageInfo(setterPrototype, setterParameter, (PsiMethod)scope, parameter));
|
||||
}
|
||||
}
|
||||
|
||||
return isInsideDeleted;
|
||||
}
|
||||
|
||||
private static SafeDeleteParameterCallHierarchyUsageInfo createParameterCallHierarchyUsageInfo(PsiMethod called,
|
||||
PsiParameter calledParameter,
|
||||
PsiMethod caller, PsiParameter parameterInCaller) {
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
return new SafeDeleteParameterCallHierarchyUsageInfo(caller, parameterInCaller, caller, parameterInCaller);
|
||||
}
|
||||
else {
|
||||
return new SafeDeleteParameterCallHierarchyUsageInfo(called, calledParameter, caller, parameterInCaller);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void findParameterUsages(final PsiParameter parameter, final List<UsageInfo> usages) {
|
||||
final PsiMethod method = (PsiMethod)parameter.getDeclarationScope();
|
||||
@@ -919,12 +974,7 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
|
||||
final PsiParameter paramInCaller = SafeDeleteJavaCallerChooser.isTheOnlyOneParameterUsage(element.getParent(), parameterIndex, method);
|
||||
if (paramInCaller != null) {
|
||||
final PsiMethod callerMethod = (PsiMethod)paramInCaller.getDeclarationScope();
|
||||
if (ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
usages.add(new SafeDeleteParameterCallHierarchyUsageInfo(callerMethod, paramInCaller, callerMethod));
|
||||
}
|
||||
else {
|
||||
usages.add(new SafeDeleteParameterCallHierarchyUsageInfo(method, parameter, callerMethod));
|
||||
}
|
||||
usages.add(createParameterCallHierarchyUsageInfo( method, parameter, callerMethod, paramInCaller));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+31
-31
@@ -80,7 +80,7 @@ abstract class SafeDeleteJavaCallerChooser extends JavaCallerChooser {
|
||||
final PsiMethod nodeMethod = methodNode.getMethod();
|
||||
if (nodeMethod.equals(myMethod)) continue;
|
||||
final PsiParameter parameter = nodeMethod.getParameterList().getParameters()[methodNode.myParameterIdx];
|
||||
foreignMethodUsages.add(new SafeDeleteParameterCallHierarchyUsageInfo(nodeMethod, parameter, nodeMethod));
|
||||
foreignMethodUsages.add(new SafeDeleteParameterCallHierarchyUsageInfo(nodeMethod, parameter, nodeMethod, parameter));
|
||||
ReferencesSearch.search(nodeMethod).forEach(reference -> {
|
||||
final PsiElement element = reference.getElement();
|
||||
if (element != null) {
|
||||
@@ -191,6 +191,33 @@ abstract class SafeDeleteJavaCallerChooser extends JavaCallerChooser {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected PsiParameter getParameterInCaller(PsiMethod called, int paramIdx, PsiMethod caller) {
|
||||
//do not change hierarchy
|
||||
if (caller.findDeepestSuperMethods().length > 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//find first method call
|
||||
final Ref<PsiParameter> ref = new Ref<>();
|
||||
ReferencesSearch.search(called, new LocalSearchScope(caller)).forEach(reference -> {
|
||||
final PsiElement element = reference.getElement();
|
||||
if (element instanceof PsiJavaCodeReferenceElement) {
|
||||
final PsiElement elementParent = element.getParent();
|
||||
if (elementParent instanceof PsiCallExpression) {
|
||||
ref.set(isTheOnlyOneParameterUsage(elementParent, paramIdx, called));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
protected int getCallerParameterIndex(PsiMethod called, int paramIdx, PsiMethod caller) {
|
||||
final PsiParameter parameter = getParameterInCaller(called, paramIdx, caller);
|
||||
return parameter != null ? caller.getParameterList().getParameterIndex(parameter) : -1;
|
||||
}
|
||||
|
||||
private class SafeDeleteJavaMethodNode extends JavaMethodNode {
|
||||
|
||||
private final int myParameterIdx;
|
||||
@@ -206,7 +233,7 @@ abstract class SafeDeleteJavaCallerChooser extends JavaCallerChooser {
|
||||
|
||||
@Override
|
||||
protected MethodNodeBase<PsiMethod> createNode(PsiMethod caller, HashSet<PsiMethod> called) {
|
||||
return new SafeDeleteJavaMethodNode(caller, called, myCancelCallback, getParameterIndex(caller), myProject);
|
||||
return new SafeDeleteJavaMethodNode(caller, called, myCancelCallback, getCallerParameterIndex(myMethod, myParameterIdx, caller), myProject);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -222,35 +249,8 @@ abstract class SafeDeleteJavaCallerChooser extends JavaCallerChooser {
|
||||
|
||||
@Override
|
||||
protected Condition<PsiMethod> getFilter() {
|
||||
return method -> !myMethod.equals(method) && getParameter(method) != null;
|
||||
}
|
||||
|
||||
private PsiParameter getParameter(PsiMethod caller) {
|
||||
|
||||
//do not change hierarchy
|
||||
if (caller.findDeepestSuperMethods().length > 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//find first method call
|
||||
final Ref<PsiParameter> ref = new Ref<>();
|
||||
ReferencesSearch.search(myMethod, new LocalSearchScope(caller)).forEach(reference -> {
|
||||
final PsiElement element = reference.getElement();
|
||||
if (element instanceof PsiReferenceExpression) {
|
||||
final PsiElement elementParent = element.getParent();
|
||||
if (elementParent instanceof PsiCallExpression) {
|
||||
ref.set(isTheOnlyOneParameterUsage(elementParent, myParameterIdx, myMethod));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return ref.get();
|
||||
}
|
||||
|
||||
private int getParameterIndex(PsiMethod caller) {
|
||||
final PsiParameter parameter = getParameter(caller);
|
||||
return parameter != null ? caller.getParameterList().getParameterIndex(parameter) : -1;
|
||||
return method -> !myMethod.equals(method) && getParameterInCaller(myMethod, myParameterIdx, method) != null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -23,11 +23,16 @@ public class SafeDeleteParameterCallHierarchyUsageInfo extends SafeDeleteUsageIn
|
||||
|
||||
private final PsiMethod myCalledMethod;
|
||||
private final PsiMethod myCallerMethod;
|
||||
private final PsiParameter myParameterInCaller;
|
||||
|
||||
public SafeDeleteParameterCallHierarchyUsageInfo(PsiMethod calledMethod, PsiParameter parameter, PsiMethod callerMethod) {
|
||||
public SafeDeleteParameterCallHierarchyUsageInfo(PsiMethod calledMethod,
|
||||
PsiParameter parameter,
|
||||
PsiMethod callerMethod,
|
||||
PsiParameter parameterInCaller) {
|
||||
super(calledMethod, parameter);
|
||||
myCalledMethod = calledMethod;
|
||||
myCallerMethod = callerMethod;
|
||||
myParameterInCaller = parameterInCaller;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -60,6 +65,7 @@ public class SafeDeleteParameterCallHierarchyUsageInfo extends SafeDeleteUsageIn
|
||||
|
||||
if (!myCalledMethod.equals(info.myCalledMethod)) return false;
|
||||
if (!myCallerMethod.equals(info.myCallerMethod)) return false;
|
||||
if (!myParameterInCaller.equals(info.myParameterInCaller)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -69,6 +75,11 @@ public class SafeDeleteParameterCallHierarchyUsageInfo extends SafeDeleteUsageIn
|
||||
int result = super.hashCode();
|
||||
result = 31 * result + myCalledMethod.hashCode();
|
||||
result = 31 * result + myCallerMethod.hashCode();
|
||||
result = 31 * result + myParameterInCaller.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
public PsiParameter getParameterInCaller() {
|
||||
return myParameterInCaller;
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
class MyTest {
|
||||
String my<caret>Str;
|
||||
|
||||
public MyTest(String str) {
|
||||
myStr = str;
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class MyTest {
|
||||
|
||||
public MyTest() {
|
||||
}
|
||||
}
|
||||
@@ -91,6 +91,10 @@ public class SafeDeleteTest extends MultiFileTestCase {
|
||||
public void testDeepDeleteParameterOtherTypeInBinaryExpression() throws Exception {
|
||||
doSingleFileTest();
|
||||
}
|
||||
|
||||
public void testDeepDeleteFieldAndAssignedParameter() throws Exception {
|
||||
doSingleFileTest();
|
||||
}
|
||||
|
||||
public void testImpossibleToDeepDeleteParameter() throws Exception {
|
||||
doSingleFileTest();
|
||||
@@ -132,7 +136,6 @@ public class SafeDeleteTest extends MultiFileTestCase {
|
||||
doTest("C2");
|
||||
}
|
||||
|
||||
|
||||
public void testTopLevelDocComment() throws Exception {
|
||||
doTest("foo.C1");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user