rename: remember 'Search for text occurrences' checkbox state (IDEA-21328)
[fedora-idea.git] / java / java-impl / src / com / intellij / refactoring / rename / RenameJavaMethodProcessor.java
blob06b9d3025149ffecef8d9b6082a4e2fa68141221
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.rename;
18 import com.intellij.ide.util.SuperMethodWarningUtil;
19 import com.intellij.openapi.diagnostic.Logger;
20 import com.intellij.openapi.editor.Editor;
21 import com.intellij.psi.*;
22 import com.intellij.psi.search.GlobalSearchScope;
23 import com.intellij.psi.search.searches.ClassInheritorsSearch;
24 import com.intellij.psi.search.searches.MethodReferencesSearch;
25 import com.intellij.psi.search.searches.OverridingMethodsSearch;
26 import com.intellij.psi.util.MethodSignature;
27 import com.intellij.psi.util.MethodSignatureUtil;
28 import com.intellij.psi.util.PsiTreeUtil;
29 import com.intellij.psi.util.TypeConversionUtil;
30 import com.intellij.refactoring.HelpID;
31 import com.intellij.refactoring.JavaRefactoringSettings;
32 import com.intellij.refactoring.RefactoringBundle;
33 import com.intellij.refactoring.listeners.RefactoringElementListener;
34 import com.intellij.refactoring.util.ConflictsUtil;
35 import com.intellij.refactoring.util.MoveRenameUsageInfo;
36 import com.intellij.refactoring.util.RefactoringUtil;
37 import com.intellij.usageView.UsageInfo;
38 import com.intellij.util.IncorrectOperationException;
39 import com.intellij.util.Processor;
40 import com.intellij.util.containers.HashSet;
41 import com.intellij.util.containers.MultiMap;
42 import org.jetbrains.annotations.NonNls;
43 import org.jetbrains.annotations.NotNull;
44 import org.jetbrains.annotations.Nullable;
46 import java.util.*;
48 public class RenameJavaMethodProcessor extends RenameJavaMemberProcessor {
49 private static final Logger LOG = Logger.getInstance("#com.intellij.refactoring.rename.RenameJavaMethodProcessor");
51 public boolean canProcessElement(final PsiElement element) {
52 return element instanceof PsiMethod;
55 public void renameElement(final PsiElement psiElement,
56 final String newName,
57 final UsageInfo[] usages, final RefactoringElementListener listener) throws IncorrectOperationException {
58 PsiMethod method = (PsiMethod) psiElement;
59 Set<PsiMethod> methodAndOverriders = new HashSet<PsiMethod>();
60 Set<PsiClass> containingClasses = new HashSet<PsiClass>();
61 List<PsiElement> renamedReferences = new ArrayList<PsiElement>();
62 List<MemberHidesOuterMemberUsageInfo> outerHides = new ArrayList<MemberHidesOuterMemberUsageInfo>();
63 List<MemberHidesStaticImportUsageInfo> staticImportHides = new ArrayList<MemberHidesStaticImportUsageInfo>();
65 methodAndOverriders.add(method);
66 containingClasses.add(method.getContainingClass());
68 findCollisionsAgainstNewName(method, newName, staticImportHides);
70 // do actual rename of overriding/implementing methods and of references to all them
71 for (UsageInfo usage : usages) {
72 PsiElement element = usage.getElement();
73 if (element == null) continue;
75 if (usage instanceof MemberHidesStaticImportUsageInfo) {
76 staticImportHides.add((MemberHidesStaticImportUsageInfo)usage);
77 } else if (usage instanceof MemberHidesOuterMemberUsageInfo) {
78 PsiJavaCodeReferenceElement collidingRef = (PsiJavaCodeReferenceElement)element;
79 PsiMethod resolved = (PsiMethod)collidingRef.resolve();
80 outerHides.add(new MemberHidesOuterMemberUsageInfo(element, resolved));
82 else if (!(element instanceof PsiMethod)) {
83 final PsiReference ref;
84 if (usage instanceof MoveRenameUsageInfo) {
85 ref = usage.getReference();
87 else {
88 ref = element.getReference();
90 if (ref != null) {
91 renamedReferences.add(ref.handleElementRename(newName));
94 else {
95 PsiMethod overrider = (PsiMethod)element;
96 methodAndOverriders.add(overrider);
97 containingClasses.add(overrider.getContainingClass());
101 // do actual rename of method
102 method.setName(newName);
103 for (UsageInfo usage : usages) {
104 PsiElement element = usage.getElement();
105 if (element instanceof PsiMethod) {
106 ((PsiMethod)element).setName(newName);
109 listener.elementRenamed(method);
111 for (PsiElement element: renamedReferences) {
112 fixNameCollisionsWithInnerClassMethod(element, newName, methodAndOverriders, containingClasses,
113 method.hasModifierProperty(PsiModifier.STATIC));
115 qualifyOuterMemberReferences(outerHides);
116 qualifyStaticImportReferences(staticImportHides);
119 private static void fixNameCollisionsWithInnerClassMethod(final PsiElement element, final String newName,
120 final Set<PsiMethod> methodAndOverriders, final Set<PsiClass> containingClasses,
121 final boolean isStatic) throws IncorrectOperationException {
122 if (!(element instanceof PsiReferenceExpression)) return;
123 PsiElement elem = ((PsiReferenceExpression)element).resolve();
125 if (elem instanceof PsiMethod) {
126 PsiMethod actualMethod = (PsiMethod) elem;
127 if (!methodAndOverriders.contains(actualMethod)) {
128 PsiClass outerClass = PsiTreeUtil.getParentOfType(element, PsiClass.class);
129 while (outerClass != null) {
130 if (containingClasses.contains(outerClass)) {
131 qualifyMember(element, newName, outerClass, isStatic);
132 break;
134 outerClass = outerClass.getContainingClass();
140 @NotNull
141 public Collection<PsiReference> findReferences(final PsiElement element) {
142 GlobalSearchScope projectScope = GlobalSearchScope.projectScope(element.getProject());
143 return MethodReferencesSearch.search((PsiMethod)element, projectScope, true).findAll();
146 public void findCollisions(final PsiElement element, final String newName, final Map<? extends PsiElement, String> allRenames,
147 final List<UsageInfo> result) {
148 final PsiMethod methodToRename = (PsiMethod)element;
149 findSubmemberHidesMemberCollisions(methodToRename, newName, result);
150 findMemberHidesOuterMemberCollisions((PsiMethod) element, newName, result);
151 findCollisionsAgainstNewName(methodToRename, newName, result);
154 public void findExistingNameConflicts(final PsiElement element, final String newName, final MultiMap<PsiElement, String> conflicts) {
155 if (element instanceof PsiCompiledElement) return;
156 PsiMethod refactoredMethod = (PsiMethod)element;
157 if (newName.equals(refactoredMethod.getName())) return;
158 final PsiMethod prototype = (PsiMethod)refactoredMethod.copy();
159 try {
160 prototype.setName(newName);
162 catch (IncorrectOperationException e) {
163 LOG.error(e);
164 return;
167 ConflictsUtil.checkMethodConflicts(
168 refactoredMethod.getContainingClass(),
169 refactoredMethod,
170 prototype,
171 conflicts);
174 public void prepareRenaming(final PsiElement element, final String newName, final Map<PsiElement, String> allRenames) {
175 final PsiMethod method = (PsiMethod) element;
176 OverridingMethodsSearch.search(method, true).forEach(new Processor<PsiMethod>() {
177 public boolean process(PsiMethod overrider) {
178 final String overriderName = overrider.getName();
179 final String baseName = method.getName();
180 final String newOverriderName = RefactoringUtil.suggestNewOverriderName(overriderName, baseName, newName);
181 if (newOverriderName != null) {
182 allRenames.put(overrider, newOverriderName);
184 return true;
189 @NonNls
190 public String getHelpID(final PsiElement element) {
191 return HelpID.RENAME_METHOD;
194 public boolean isToSearchInComments(final PsiElement psiElement) {
195 return JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD;
198 public void setToSearchInComments(final PsiElement element, final boolean enabled) {
199 JavaRefactoringSettings.getInstance().RENAME_SEARCH_IN_COMMENTS_FOR_METHOD = enabled;
202 @Nullable
203 public PsiElement substituteElementToRename(PsiElement element, Editor editor) {
204 PsiMethod psiMethod = (PsiMethod)element;
205 if (psiMethod.isConstructor()) {
206 PsiClass containingClass = psiMethod.getContainingClass();
207 if (containingClass == null) return null;
208 element = containingClass;
209 if (!PsiElementRenameHandler.canRename(element.getProject(), editor, element)) {
210 return null;
212 return element;
214 return SuperMethodWarningUtil.checkSuperMethod(psiMethod, RefactoringBundle.message("to.rename"));
217 private static void findSubmemberHidesMemberCollisions(final PsiMethod method, final String newName, final List<UsageInfo> result) {
218 final PsiClass containingClass = method.getContainingClass();
219 if (containingClass == null) return;
220 if (method.hasModifierProperty(PsiModifier.PRIVATE)) return;
221 Collection<PsiClass> inheritors = ClassInheritorsSearch.search(containingClass, containingClass.getUseScope(), true).findAll();
223 MethodSignature oldSignature = method.getSignature(PsiSubstitutor.EMPTY);
224 MethodSignature newSignature = MethodSignatureUtil.createMethodSignature(newName, oldSignature.getParameterTypes(),
225 oldSignature.getTypeParameters(),
226 oldSignature.getSubstitutor());
227 for (PsiClass inheritor : inheritors) {
228 PsiSubstitutor superSubstitutor = TypeConversionUtil.getSuperClassSubstitutor(containingClass, inheritor, PsiSubstitutor.EMPTY);
229 final PsiMethod[] methodsByName = inheritor.findMethodsByName(newName, false);
230 for (PsiMethod conflictingMethod : methodsByName) {
231 if (newSignature.equals(conflictingMethod.getSignature(superSubstitutor))) {
232 result.add(new SubmemberHidesMemberUsageInfo(conflictingMethod, method));
233 break;
239 public boolean isToSearchForTextOccurrences(final PsiElement element) {
240 return JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD;
243 public void setToSearchForTextOccurrences(final PsiElement element, final boolean enabled) {
244 JavaRefactoringSettings.getInstance().RENAME_SEARCH_FOR_TEXT_FOR_METHOD = enabled;