2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.refactoring
.safeDelete
;
18 import com
.intellij
.ide
.util
.SuperMethodWarningUtil
;
19 import com
.intellij
.openapi
.application
.ApplicationManager
;
20 import com
.intellij
.openapi
.diagnostic
.Logger
;
21 import com
.intellij
.openapi
.project
.Project
;
22 import com
.intellij
.openapi
.ui
.DialogWrapper
;
23 import com
.intellij
.openapi
.ui
.Messages
;
24 import com
.intellij
.openapi
.util
.Condition
;
25 import com
.intellij
.openapi
.util
.TextRange
;
26 import com
.intellij
.psi
.*;
27 import com
.intellij
.psi
.codeStyle
.JavaCodeStyleManager
;
28 import com
.intellij
.psi
.codeStyle
.VariableKind
;
29 import com
.intellij
.psi
.javadoc
.PsiDocTag
;
30 import com
.intellij
.psi
.search
.searches
.OverridingMethodsSearch
;
31 import com
.intellij
.psi
.search
.searches
.ReferencesSearch
;
32 import com
.intellij
.psi
.search
.searches
.SuperMethodsSearch
;
33 import com
.intellij
.psi
.util
.MethodSignatureBackedByPsiMethod
;
34 import com
.intellij
.psi
.util
.MethodSignatureUtil
;
35 import com
.intellij
.psi
.util
.PropertyUtil
;
36 import com
.intellij
.psi
.util
.PsiTreeUtil
;
37 import com
.intellij
.refactoring
.RefactoringBundle
;
38 import com
.intellij
.refactoring
.safeDelete
.usageInfo
.*;
39 import com
.intellij
.refactoring
.util
.RefactoringMessageUtil
;
40 import com
.intellij
.refactoring
.util
.RefactoringUIUtil
;
41 import com
.intellij
.usageView
.UsageInfo
;
42 import com
.intellij
.usageView
.UsageViewUtil
;
43 import com
.intellij
.util
.ArrayUtil
;
44 import com
.intellij
.util
.IncorrectOperationException
;
45 import com
.intellij
.util
.Processor
;
46 import com
.intellij
.util
.containers
.HashMap
;
47 import org
.jetbrains
.annotations
.Nullable
;
51 public class JavaSafeDeleteProcessor
implements SafeDeleteProcessorDelegate
{
52 private static final Logger LOG
= Logger
.getInstance("#com.intellij.refactoring.safeDelete.JavaSafeDeleteProcessor");
54 public boolean handlesElement(final PsiElement element
) {
55 return element
instanceof PsiClass
|| element
instanceof PsiMethod
||
56 element
instanceof PsiField
|| element
instanceof PsiParameter
;
60 public NonCodeUsageSearchInfo
findUsages(final PsiElement element
, final PsiElement
[] allElementsToDelete
, final List
<UsageInfo
> usages
) {
61 Condition
<PsiElement
> insideDeletedCondition
= getUsageInsideDeletedFilter(allElementsToDelete
);
62 if (element
instanceof PsiClass
) {
63 findClassUsages((PsiClass
) element
, allElementsToDelete
, usages
);
64 if (element
instanceof PsiTypeParameter
) {
65 findTypeParameterExternalUsages((PsiTypeParameter
)element
, usages
);
68 else if (element
instanceof PsiMethod
) {
69 insideDeletedCondition
= findMethodUsages((PsiMethod
) element
, allElementsToDelete
, usages
);
71 else if (element
instanceof PsiField
) {
72 insideDeletedCondition
= findFieldUsages((PsiField
)element
, usages
, allElementsToDelete
);
74 else if (element
instanceof PsiParameter
) {
75 LOG
.assertTrue(((PsiParameter
) element
).getDeclarationScope() instanceof PsiMethod
);
76 findParameterUsages((PsiParameter
)element
, usages
);
78 return new NonCodeUsageSearchInfo(insideDeletedCondition
, element
);
81 public Collection
<?
extends PsiElement
> getElementsToSearch(final PsiElement element
, final Collection
<PsiElement
> allElementsToDelete
) {
82 Project project
= element
.getProject();
83 if (element
instanceof PsiMethod
) {
84 final PsiMethod
[] methods
=
85 SuperMethodWarningUtil
.checkSuperMethods((PsiMethod
)element
, RefactoringBundle
.message("to.delete.with.usage.search"),
87 if (methods
.length
== 0) return null;
88 return Arrays
.asList(methods
);
90 else if (element
instanceof PsiParameter
&& ((PsiParameter
) element
).getDeclarationScope() instanceof PsiMethod
) {
91 PsiMethod method
= (PsiMethod
) ((PsiParameter
) element
).getDeclarationScope();
92 final Set
<PsiParameter
> parametersToDelete
= new com
.intellij
.util
.containers
.HashSet
<PsiParameter
>();
93 parametersToDelete
.add((PsiParameter
) element
);
94 final int parameterIndex
= method
.getParameterList().getParameterIndex((PsiParameter
) element
);
95 SuperMethodsSearch
.search(method
, null, true, false).forEach(new Processor
<MethodSignatureBackedByPsiMethod
>() {
96 public boolean process(MethodSignatureBackedByPsiMethod signature
) {
97 parametersToDelete
.add(signature
.getMethod().getParameterList().getParameters()[parameterIndex
]);
102 OverridingMethodsSearch
.search(method
).forEach(new Processor
<PsiMethod
>() {
103 public boolean process(PsiMethod overrider
) {
104 parametersToDelete
.add(overrider
.getParameterList().getParameters()[parameterIndex
]);
108 if (parametersToDelete
.size() > 1) {
109 String message
= RefactoringBundle
.message("0.is.a.part.of.method.hierarchy.do.you.want.to.delete.multiple.parameters", UsageViewUtil
.getLongName(method
));
110 if (Messages
.showYesNoDialog(project
, message
, SafeDeleteHandler
.REFACTORING_NAME
,
111 Messages
.getQuestionIcon()) != DialogWrapper
.OK_EXIT_CODE
) return null;
113 return parametersToDelete
;
116 return Collections
.singletonList(element
);
120 public Collection
<PsiElement
> getAdditionalElementsToDelete(final PsiElement element
, final Collection
<PsiElement
> allElementsToDelete
,
121 final boolean askUser
) {
122 if (element
instanceof PsiField
) {
123 PsiField field
= (PsiField
)element
;
124 final Project project
= element
.getProject();
125 String propertyName
= JavaCodeStyleManager
.getInstance(project
).variableNameToPropertyName(field
.getName(), VariableKind
.FIELD
);
127 PsiClass aClass
= field
.getContainingClass();
128 if (aClass
!= null) {
129 boolean isStatic
= field
.hasModifierProperty(PsiModifier
.STATIC
);
130 PsiMethod getter
= PropertyUtil
.findPropertyGetter(aClass
, propertyName
, isStatic
, false);
131 if (allElementsToDelete
.contains(getter
)) getter
= null;
132 PsiMethod setter
= PropertyUtil
.findPropertySetter(aClass
, propertyName
, isStatic
, false);
133 if (allElementsToDelete
.contains(setter
)) setter
= null;
134 if (askUser
&& (getter
!= null || setter
!= null)) {
135 final String message
= RefactoringMessageUtil
.getGetterSetterMessage(field
.getName(), RefactoringBundle
.message("delete.title"), getter
, setter
);
136 if (Messages
.showYesNoDialog(project
, message
, RefactoringBundle
.message("safe.delete.title"), Messages
.getQuestionIcon()) != 0) {
141 List
<PsiElement
> elements
= new ArrayList
<PsiElement
>();
142 if (setter
!= null) elements
.add(setter
);
143 if (getter
!= null) elements
.add(getter
);
150 public Collection
<String
> findConflicts(final PsiElement element
, final PsiElement
[] allElementsToDelete
) {
151 if (element
instanceof PsiMethod
) {
152 final PsiClass containingClass
= ((PsiMethod
)element
).getContainingClass();
154 if (!containingClass
.hasModifierProperty(PsiModifier
.ABSTRACT
)) {
155 final PsiMethod
[] superMethods
= ((PsiMethod
) element
).findSuperMethods();
156 for (PsiMethod superMethod
: superMethods
) {
157 if (isInside(superMethod
, allElementsToDelete
)) continue;
158 if (superMethod
.hasModifierProperty(PsiModifier
.ABSTRACT
)) {
159 String message
= RefactoringBundle
.message("0.implements.1", RefactoringUIUtil
.getDescription(element
, true),
160 RefactoringUIUtil
.getDescription(superMethod
, true));
161 return Collections
.singletonList(message
);
170 public UsageInfo
[] preprocessUsages(final Project project
, final UsageInfo
[] usages
) {
171 ArrayList
<UsageInfo
> result
= new ArrayList
<UsageInfo
>();
172 ArrayList
<UsageInfo
> overridingMethods
= new ArrayList
<UsageInfo
>();
173 for (UsageInfo usage
: usages
) {
174 if (usage
.isNonCodeUsage
) {
177 else if (usage
instanceof SafeDeleteOverridingMethodUsageInfo
) {
178 overridingMethods
.add(usage
);
185 if(!overridingMethods
.isEmpty()) {
186 if (ApplicationManager
.getApplication().isUnitTestMode()) {
187 result
.addAll(overridingMethods
);
190 OverridingMethodsDialog dialog
= new OverridingMethodsDialog(project
, overridingMethods
);
192 if(!dialog
.isOK()) return null;
193 result
.addAll(dialog
.getSelected());
197 return result
.toArray(new UsageInfo
[result
.size()]);
200 public void prepareForDeletion(final PsiElement element
) throws IncorrectOperationException
{
201 if (element
instanceof PsiVariable
) {
202 ((PsiVariable
)element
).normalizeDeclaration();
206 public static Condition
<PsiElement
> getUsageInsideDeletedFilter(final PsiElement
[] allElementsToDelete
) {
207 return new Condition
<PsiElement
>() {
208 public boolean value(final PsiElement usage
) {
209 return !(usage
instanceof PsiFile
) && isInside(usage
, allElementsToDelete
);
214 private static void findClassUsages(final PsiClass psiClass
, final PsiElement
[] allElementsToDelete
, final List
<UsageInfo
> usages
) {
215 final boolean justPrivates
= containsOnlyPrivates(psiClass
);
217 ReferencesSearch
.search(psiClass
).forEach(new Processor
<PsiReference
>() {
218 public boolean process(final PsiReference reference
) {
219 final PsiElement element
= reference
.getElement();
221 if (!isInside(element
, allElementsToDelete
)) {
222 PsiElement parent
= element
.getParent();
223 if (parent
instanceof PsiReferenceList
) {
224 final PsiElement pparent
= parent
.getParent();
225 if (pparent
instanceof PsiClass
) {
226 final PsiClass inheritor
= (PsiClass
) pparent
;
227 //If psiClass contains only private members, then it is safe to remove it and change inheritor's extends/implements accordingly
229 if (parent
.equals(inheritor
.getExtendsList()) || parent
.equals(inheritor
.getImplementsList())) {
230 usages
.add(new SafeDeleteExtendsClassUsageInfo((PsiJavaCodeReferenceElement
)element
, psiClass
, inheritor
));
236 LOG
.assertTrue(element
.getTextRange() != null);
237 usages
.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element
, psiClass
, parent
instanceof PsiImportStatement
));
244 private static boolean containsOnlyPrivates(final PsiClass aClass
) {
245 final PsiField
[] fields
= aClass
.getFields();
246 for (PsiField field
: fields
) {
247 if (!field
.hasModifierProperty(PsiModifier
.PRIVATE
)) return false;
250 final PsiMethod
[] methods
= aClass
.getMethods();
251 for (PsiMethod method
: methods
) {
252 if (!method
.hasModifierProperty(PsiModifier
.PRIVATE
)) {
253 if (method
.isConstructor()) { //skip non-private constructors with call to super only
254 final PsiCodeBlock body
= method
.getBody();
256 final PsiStatement
[] statements
= body
.getStatements();
257 if (statements
.length
== 0) continue;
258 if (statements
.length
== 1 && statements
[0] instanceof PsiExpressionStatement
) {
259 final PsiExpression expression
= ((PsiExpressionStatement
)statements
[0]).getExpression();
260 if (expression
instanceof PsiMethodCallExpression
) {
261 PsiReferenceExpression methodExpression
= ((PsiMethodCallExpression
)expression
).getMethodExpression();
262 if (methodExpression
.getText().equals(PsiKeyword
.SUPER
)) {
273 final PsiClass
[] inners
= aClass
.getInnerClasses();
274 for (PsiClass inner
: inners
) {
275 if (!inner
.hasModifierProperty(PsiModifier
.PRIVATE
)) return false;
281 private static void findTypeParameterExternalUsages(final PsiTypeParameter typeParameter
, final Collection
<UsageInfo
> usages
) {
282 PsiTypeParameterListOwner owner
= typeParameter
.getOwner();
284 final int index
= owner
.getTypeParameterList().getTypeParameterIndex(typeParameter
);
286 ReferencesSearch
.search(owner
).forEach(new Processor
<PsiReference
>() {
287 public boolean process(final PsiReference reference
) {
288 if (reference
instanceof PsiJavaCodeReferenceElement
) {
289 PsiTypeElement
[] typeArgs
= ((PsiJavaCodeReferenceElement
)reference
).getParameterList().getTypeParameterElements();
290 if (typeArgs
.length
> index
) {
291 usages
.add(new SafeDeleteReferenceJavaDeleteUsageInfo(typeArgs
[index
], typeParameter
, true));
301 private static Condition
<PsiElement
> findMethodUsages(PsiMethod psiMethod
, final PsiElement
[] allElementsToDelete
, List
<UsageInfo
> usages
) {
302 final Collection
<PsiReference
> references
= ReferencesSearch
.search(psiMethod
).findAll();
304 if(psiMethod
.isConstructor()) {
305 return findConstructorUsages(psiMethod
, references
, usages
, allElementsToDelete
);
307 final PsiMethod
[] overridingMethods
=
308 removeDeletedMethods(OverridingMethodsSearch
.search(psiMethod
, psiMethod
.getUseScope(), true).toArray(PsiMethod
.EMPTY_ARRAY
),
309 allElementsToDelete
);
311 for (PsiReference reference
: references
) {
312 final PsiElement element
= reference
.getElement();
313 if (!isInside(element
, allElementsToDelete
) && !isInside(element
, overridingMethods
)) {
314 usages
.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element
, psiMethod
, false));
318 final HashMap
<PsiMethod
, Collection
<PsiReference
>> methodToReferences
= new HashMap
<PsiMethod
, Collection
<PsiReference
>>();
319 for (PsiMethod overridingMethod
: overridingMethods
) {
320 final Collection
<PsiReference
> overridingReferences
= ReferencesSearch
.search(overridingMethod
).findAll();
321 methodToReferences
.put(overridingMethod
, overridingReferences
);
323 final Set
<PsiMethod
> validOverriding
=
324 validateOverridingMethods(psiMethod
, references
, Arrays
.asList(overridingMethods
), methodToReferences
, usages
,
325 allElementsToDelete
);
326 return new Condition
<PsiElement
>() {
327 public boolean value(PsiElement usage
) {
328 if(usage
instanceof PsiFile
) return false;
329 return isInside(usage
, allElementsToDelete
) || isInside(usage
, validOverriding
);
334 private static PsiMethod
[] removeDeletedMethods(PsiMethod
[] methods
, final PsiElement
[] allElementsToDelete
) {
335 ArrayList
<PsiMethod
> list
= new ArrayList
<PsiMethod
>();
336 for (PsiMethod method
: methods
) {
337 boolean isDeleted
= false;
338 for (PsiElement element
: allElementsToDelete
) {
339 if (element
== method
) {
348 return list
.toArray(new PsiMethod
[list
.size()]);
352 private static Condition
<PsiElement
> findConstructorUsages(PsiMethod constructor
, Collection
<PsiReference
> originalReferences
, List
<UsageInfo
> usages
,
353 final PsiElement
[] allElementsToDelete
) {
354 HashMap
<PsiMethod
, Collection
<PsiReference
>> constructorsToRefs
= new HashMap
<PsiMethod
, Collection
<PsiReference
>>();
355 HashSet
<PsiMethod
> newConstructors
= new HashSet
<PsiMethod
>();
356 if (isTheOnlyEmptyDefaultConstructor(constructor
)) return null;
358 newConstructors
.add(constructor
);
359 constructorsToRefs
.put(constructor
, originalReferences
);
360 HashSet
<PsiMethod
> passConstructors
= new HashSet
<PsiMethod
>();
362 passConstructors
.clear();
363 for (PsiMethod method
: newConstructors
) {
364 final Collection
<PsiReference
> references
= constructorsToRefs
.get(method
);
365 for (PsiReference reference
: references
) {
366 PsiMethod overridingConstructor
= getOverridingConstructorOfSuperCall(reference
.getElement());
367 if (overridingConstructor
!= null && !constructorsToRefs
.containsKey(overridingConstructor
)) {
368 Collection
<PsiReference
> overridingConstructorReferences
= ReferencesSearch
.search(overridingConstructor
).findAll();
369 constructorsToRefs
.put(overridingConstructor
, overridingConstructorReferences
);
370 passConstructors
.add(overridingConstructor
);
374 newConstructors
.clear();
375 newConstructors
.addAll(passConstructors
);
377 while(!newConstructors
.isEmpty());
379 final Set
<PsiMethod
> validOverriding
=
380 validateOverridingMethods(constructor
, originalReferences
, constructorsToRefs
.keySet(), constructorsToRefs
, usages
,
381 allElementsToDelete
);
383 return new Condition
<PsiElement
>() {
384 public boolean value(PsiElement usage
) {
385 if(usage
instanceof PsiFile
) return false;
386 return isInside(usage
, allElementsToDelete
) || isInside(usage
, validOverriding
);
391 private static boolean isTheOnlyEmptyDefaultConstructor(final PsiMethod constructor
) {
392 if (constructor
.getParameterList().getParameters().length
> 0) return false;
393 final PsiCodeBlock body
= constructor
.getBody();
394 if (body
!= null && body
.getStatements().length
> 0) return false;
395 return constructor
.getContainingClass().getConstructors().length
== 1;
398 private static Set
<PsiMethod
> validateOverridingMethods(PsiMethod originalMethod
, final Collection
<PsiReference
> originalReferences
,
399 Collection
<PsiMethod
> overridingMethods
, HashMap
<PsiMethod
, Collection
<PsiReference
>> methodToReferences
,
400 List
<UsageInfo
> usages
,
401 final PsiElement
[] allElementsToDelete
) {
402 Set
<PsiMethod
> validOverriding
= new LinkedHashSet
<PsiMethod
>(overridingMethods
);
403 Set
<PsiMethod
> multipleInterfaceImplementations
= new HashSet
<PsiMethod
>();
404 boolean anyNewBadRefs
;
406 anyNewBadRefs
= false;
407 for (PsiMethod overridingMethod
: overridingMethods
) {
408 if (validOverriding
.contains(overridingMethod
)) {
409 final Collection
<PsiReference
> overridingReferences
= methodToReferences
.get(overridingMethod
);
410 boolean anyOverridingRefs
= false;
411 for (final PsiReference overridingReference
: overridingReferences
) {
412 final PsiElement element
= overridingReference
.getElement();
413 if (!isInside(element
, allElementsToDelete
) && !isInside(element
, validOverriding
)) {
414 anyOverridingRefs
= true;
418 if (!anyOverridingRefs
&& isMultipleInterfacesImplementation(overridingMethod
, allElementsToDelete
)) {
419 anyOverridingRefs
= true;
420 multipleInterfaceImplementations
.add(overridingMethod
);
423 if (anyOverridingRefs
) {
424 validOverriding
.remove(overridingMethod
);
425 anyNewBadRefs
= true;
427 for (PsiReference reference
: originalReferences
) {
428 final PsiElement element
= reference
.getElement();
429 if (!isInside(element
, allElementsToDelete
) && !isInside(element
, overridingMethods
)) {
430 usages
.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element
, originalMethod
, false));
431 validOverriding
.clear();
438 while(anyNewBadRefs
&& !validOverriding
.isEmpty());
440 for (PsiMethod method
: validOverriding
) {
441 if (method
!= originalMethod
) {
443 usages
.add(new SafeDeleteOverridingMethodUsageInfo(method
, originalMethod
));
447 for (PsiMethod method
: overridingMethods
) {
448 if (!validOverriding
.contains(method
) && !multipleInterfaceImplementations
.contains(method
)) {
449 final boolean methodCanBePrivate
=
450 canBePrivate(method
, methodToReferences
.get(method
), validOverriding
, allElementsToDelete
);
451 if (methodCanBePrivate
) {
452 usages
.add(new SafeDeletePrivatizeMethod(method
, originalMethod
));
456 return validOverriding
;
459 private static boolean isMultipleInterfacesImplementation(final PsiMethod method
, final PsiElement
[] allElementsToDelete
) {
460 final PsiMethod
[] methods
= method
.findSuperMethods();
461 for(PsiMethod superMethod
: methods
) {
462 if (ArrayUtil
.find(allElementsToDelete
, superMethod
) < 0) {
470 private static PsiMethod
getOverridingConstructorOfSuperCall(final PsiElement element
) {
471 PsiMethod overridingConstructor
= null;
472 if(element
instanceof PsiReferenceExpression
&& "super".equals(element
.getText())) {
473 PsiElement parent
= element
.getParent();
474 if(parent
instanceof PsiMethodCallExpression
) {
475 parent
= parent
.getParent();
476 if(parent
instanceof PsiExpressionStatement
) {
477 parent
= parent
.getParent();
478 if(parent
instanceof PsiCodeBlock
) {
479 parent
= parent
.getParent();
480 if(parent
instanceof PsiMethod
&& ((PsiMethod
) parent
).isConstructor()) {
481 overridingConstructor
= (PsiMethod
) parent
;
487 return overridingConstructor
;
490 private static boolean canBePrivate(PsiMethod method
, Collection
<PsiReference
> references
, Collection
<?
extends PsiElement
> deleted
,
491 final PsiElement
[] allElementsToDelete
) {
492 final PsiClass containingClass
= method
.getContainingClass();
493 if(containingClass
== null) {
497 PsiManager manager
= method
.getManager();
498 final JavaPsiFacade facade
= JavaPsiFacade
.getInstance(manager
.getProject());
499 final PsiElementFactory factory
= facade
.getElementFactory();
500 final PsiModifierList privateModifierList
;
502 final PsiMethod newMethod
= factory
.createMethod("x3", PsiType
.VOID
);
503 privateModifierList
= newMethod
.getModifierList();
504 privateModifierList
.setModifierProperty(PsiModifier
.PRIVATE
, true);
505 } catch (IncorrectOperationException e
) {
506 LOG
.assertTrue(false);
509 for (PsiReference reference
: references
) {
510 final PsiElement element
= reference
.getElement();
511 if (!isInside(element
, allElementsToDelete
) && !isInside(element
, deleted
)
512 && !facade
.getResolveHelper().isAccessible(method
, privateModifierList
, element
, null, null)) {
519 private static Condition
<PsiElement
> findFieldUsages(final PsiField psiField
, final List
<UsageInfo
> usages
, final PsiElement
[] allElementsToDelete
) {
520 final Condition
<PsiElement
> isInsideDeleted
= getUsageInsideDeletedFilter(allElementsToDelete
);
521 ReferencesSearch
.search(psiField
).forEach(new Processor
<PsiReference
>() {
522 public boolean process(final PsiReference reference
) {
523 if (!isInsideDeleted
.value(reference
.getElement())) {
524 final PsiElement element
= reference
.getElement();
525 final PsiElement parent
= element
.getParent();
526 if (parent
instanceof PsiAssignmentExpression
&& element
== ((PsiAssignmentExpression
)parent
).getLExpression()) {
527 usages
.add(new SafeDeleteFieldWriteReference((PsiAssignmentExpression
)parent
, psiField
));
530 TextRange range
= reference
.getRangeInElement();
531 usages
.add(new SafeDeleteReferenceJavaDeleteUsageInfo(reference
.getElement(), psiField
, range
.getStartOffset(),
532 range
.getEndOffset(), false, false));
540 return isInsideDeleted
;
544 private static void findParameterUsages(final PsiParameter parameter
, final List
<UsageInfo
> usages
) {
545 final PsiMethod method
= (PsiMethod
)parameter
.getDeclarationScope();
546 final int index
= method
.getParameterList().getParameterIndex(parameter
);
547 //search for refs to current method only, do not search for refs to overriding methods, they'll be searched separately
548 ReferencesSearch
.search(method
).forEach(new Processor
<PsiReference
>() {
549 public boolean process(final PsiReference reference
) {
550 final PsiElement element
= reference
.getElement();
552 if (element
instanceof PsiCall
) {
553 call
= (PsiCall
)element
;
554 } else if (element
.getParent() instanceof PsiCall
) {
555 call
= (PsiCall
)element
.getParent();
558 final PsiExpressionList argList
= call
.getArgumentList();
559 if (argList
!= null) {
560 final PsiExpression
[] args
= argList
.getExpressions();
561 if (index
< args
.length
) {
562 if (!parameter
.isVarArgs()) {
563 usages
.add(new SafeDeleteReferenceJavaDeleteUsageInfo(args
[index
], parameter
, true));
566 for (int i
= index
; i
< args
.length
; i
++) {
567 usages
.add(new SafeDeleteReferenceJavaDeleteUsageInfo(args
[i
], parameter
, true));
577 ReferencesSearch
.search(parameter
).forEach(new Processor
<PsiReference
>() {
578 public boolean process(final PsiReference reference
) {
579 PsiElement element
= reference
.getElement();
580 final PsiDocTag docTag
= PsiTreeUtil
.getParentOfType(element
, PsiDocTag
.class);
581 if (docTag
!= null) {
582 usages
.add(new SafeDeleteReferenceJavaDeleteUsageInfo(docTag
, parameter
, true));
586 boolean isSafeDelete
= false;
587 if (element
.getParent().getParent() instanceof PsiMethodCallExpression
) {
588 PsiMethodCallExpression call
= (PsiMethodCallExpression
)element
.getParent().getParent();
589 PsiReferenceExpression methodExpression
= call
.getMethodExpression();
590 if (methodExpression
.getText().equals(PsiKeyword
.SUPER
)) {
593 else if (methodExpression
.getQualifierExpression() instanceof PsiSuperExpression
) {
594 final PsiMethod superMethod
= call
.resolveMethod();
595 if (superMethod
!= null && MethodSignatureUtil
.isSuperMethod(superMethod
, method
)) {
601 usages
.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element
, parameter
, isSafeDelete
));
607 private static boolean isInside(PsiElement place
, PsiElement
[] ancestors
) {
608 return isInside(place
, Arrays
.asList(ancestors
));
611 private static boolean isInside(PsiElement place
, Collection
<?
extends PsiElement
> ancestors
) {
612 for (PsiElement element
: ancestors
) {
613 if (isInside(place
, element
)) return true;
618 public static boolean isInside (PsiElement place
, PsiElement ancestor
) {
619 if (SafeDeleteProcessor
.isInside(place
, ancestor
)) return true;
620 if (place
instanceof PsiComment
&& ancestor
instanceof PsiClass
) {
621 final PsiClass aClass
= (PsiClass
)ancestor
;
622 if (aClass
.getParent() instanceof PsiJavaFile
) {
623 final PsiJavaFile file
= (PsiJavaFile
)aClass
.getParent();
624 if (PsiTreeUtil
.isAncestor(file
, place
, false)) {
625 if (file
.getClasses().length
== 1) { // file will be deleted on class deletion