ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / safeDelete / JavaSafeDeleteProcessor.java
blob2173e1901a91a0a3801573f5664d33a599383f33
1 /*
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;
49 import java.util.*;
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;
59 @Nullable
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"),
86 allElementsToDelete);
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]);
98 return true;
102 OverridingMethodsSearch.search(method).forEach(new Processor<PsiMethod>() {
103 public boolean process(PsiMethod overrider) {
104 parametersToDelete.add(overrider.getParameterList().getParameters()[parameterIndex]);
105 return true;
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;
115 else {
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) {
137 getter = null;
138 setter = null;
141 List<PsiElement> elements = new ArrayList<PsiElement>();
142 if (setter != null) elements.add(setter);
143 if (getter != null) elements.add(getter);
144 return elements;
147 return null;
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);
166 return null;
169 @Nullable
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) {
175 result.add(usage);
177 else if (usage instanceof SafeDeleteOverridingMethodUsageInfo) {
178 overridingMethods.add(usage);
180 else {
181 result.add(usage);
185 if(!overridingMethods.isEmpty()) {
186 if (ApplicationManager.getApplication().isUnitTestMode()) {
187 result.addAll(overridingMethods);
189 else {
190 OverridingMethodsDialog dialog = new OverridingMethodsDialog(project, overridingMethods);
191 dialog.show();
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
228 if (justPrivates) {
229 if (parent.equals(inheritor.getExtendsList()) || parent.equals(inheritor.getImplementsList())) {
230 usages.add(new SafeDeleteExtendsClassUsageInfo((PsiJavaCodeReferenceElement)element, psiClass, inheritor));
231 return true;
236 LOG.assertTrue(element.getTextRange() != null);
237 usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element, psiClass, parent instanceof PsiImportStatement));
239 return true;
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();
255 if (body != null) {
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)) {
263 continue;
269 return false;
273 final PsiClass[] inners = aClass.getInnerClasses();
274 for (PsiClass inner : inners) {
275 if (!inner.hasModifierProperty(PsiModifier.PRIVATE)) return false;
278 return true;
281 private static void findTypeParameterExternalUsages(final PsiTypeParameter typeParameter, final Collection<UsageInfo> usages) {
282 PsiTypeParameterListOwner owner = typeParameter.getOwner();
283 if (owner != null) {
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));
294 return true;
300 @Nullable
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) {
340 isDeleted = true;
341 break;
344 if (!isDeleted) {
345 list.add(method);
348 return list.toArray(new PsiMethod[list.size()]);
351 @Nullable
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>();
361 do {
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;
405 do {
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;
415 break;
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) {
463 return true;
466 return false;
469 @Nullable
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) {
494 return false;
497 PsiManager manager = method.getManager();
498 final JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
499 final PsiElementFactory factory = facade.getElementFactory();
500 final PsiModifierList privateModifierList;
501 try {
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);
507 return 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)) {
513 return false;
516 return true;
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));
529 else {
530 TextRange range = reference.getRangeInElement();
531 usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(reference.getElement(), psiField, range.getStartOffset(),
532 range.getEndOffset(), false, false));
536 return true;
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();
551 PsiCall call = null;
552 if (element instanceof PsiCall) {
553 call = (PsiCall)element;
554 } else if (element.getParent() instanceof PsiCall) {
555 call = (PsiCall)element.getParent();
557 if (call != null) {
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));
565 else {
566 for (int i = index; i < args.length; i++) {
567 usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(args[i], parameter, true));
573 return 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));
583 return 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)) {
591 isSafeDelete = true;
593 else if (methodExpression.getQualifierExpression() instanceof PsiSuperExpression) {
594 final PsiMethod superMethod = call.resolveMethod();
595 if (superMethod != null && MethodSignatureUtil.isSuperMethod(superMethod, method)) {
596 isSafeDelete = true;
601 usages.add(new SafeDeleteReferenceJavaDeleteUsageInfo(element, parameter, isSafeDelete));
602 return true;
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;
615 return false;
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
626 return true;
632 return false;