KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > rename > RenameMethodProcessor


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.corext.refactoring.rename;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Set JavaDoc;
19
20 import org.eclipse.text.edits.ReplaceEdit;
21
22 import org.eclipse.core.runtime.Assert;
23 import org.eclipse.core.runtime.CoreException;
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.OperationCanceledException;
26 import org.eclipse.core.runtime.SubProgressMonitor;
27
28 import org.eclipse.core.resources.IFile;
29
30 import org.eclipse.ltk.core.refactoring.Change;
31 import org.eclipse.ltk.core.refactoring.GroupCategorySet;
32 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
33 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
34 import org.eclipse.ltk.core.refactoring.TextChange;
35 import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
36 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
37 import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
38
39 import org.eclipse.jdt.core.Flags;
40 import org.eclipse.jdt.core.ICompilationUnit;
41 import org.eclipse.jdt.core.IJavaElement;
42 import org.eclipse.jdt.core.IJavaProject;
43 import org.eclipse.jdt.core.IMember;
44 import org.eclipse.jdt.core.IMethod;
45 import org.eclipse.jdt.core.IType;
46 import org.eclipse.jdt.core.ITypeHierarchy;
47 import org.eclipse.jdt.core.JavaConventions;
48 import org.eclipse.jdt.core.JavaCore;
49 import org.eclipse.jdt.core.JavaModelException;
50 import org.eclipse.jdt.core.WorkingCopyOwner;
51 import org.eclipse.jdt.core.dom.MethodDeclaration;
52 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
53 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
54 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
55 import org.eclipse.jdt.core.refactoring.descriptors.RenameJavaElementDescriptor;
56 import org.eclipse.jdt.core.search.IJavaSearchConstants;
57 import org.eclipse.jdt.core.search.IJavaSearchScope;
58 import org.eclipse.jdt.core.search.MethodDeclarationMatch;
59 import org.eclipse.jdt.core.search.SearchEngine;
60 import org.eclipse.jdt.core.search.SearchMatch;
61 import org.eclipse.jdt.core.search.SearchParticipant;
62 import org.eclipse.jdt.core.search.SearchPattern;
63 import org.eclipse.jdt.core.search.SearchRequestor;
64
65 import org.eclipse.jdt.internal.corext.refactoring.Checks;
66 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor;
67 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
68 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
69 import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
70 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
71 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
72 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
73 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
74 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
75 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
76 import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
77 import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring;
78 import org.eclipse.jdt.internal.corext.refactoring.delegates.DelegateCreator;
79 import org.eclipse.jdt.internal.corext.refactoring.delegates.DelegateMethodCreator;
80 import org.eclipse.jdt.internal.corext.refactoring.participants.JavaProcessors;
81 import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil;
82 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
83 import org.eclipse.jdt.internal.corext.refactoring.tagging.IDelegateUpdating;
84 import org.eclipse.jdt.internal.corext.refactoring.tagging.IReferenceUpdating;
85 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
86 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
87 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
88 import org.eclipse.jdt.internal.corext.util.JdtFlags;
89 import org.eclipse.jdt.internal.corext.util.Messages;
90 import org.eclipse.jdt.internal.corext.util.SearchUtils;
91
92 import org.eclipse.jdt.ui.JavaElementLabels;
93
94 import org.eclipse.jdt.internal.ui.JavaPlugin;
95 import org.eclipse.jdt.internal.ui.refactoring.RefactoringSaveHelper;
96
97 public abstract class RenameMethodProcessor extends JavaRenameProcessor implements IReferenceUpdating, IDelegateUpdating {
98
99     private static final String JavaDoc ATTRIBUTE_DELEGATE= "delegate"; //$NON-NLS-1$
100
private static final String JavaDoc ATTRIBUTE_DEPRECATE= "deprecate"; //$NON-NLS-1$
101

102     private SearchResultGroup[] fOccurrences;
103     private boolean fUpdateReferences;
104     private IMethod fMethod;
105     private Set JavaDoc/*<IMethod>*/ fMethodsToRename;
106     private TextChangeManager fChangeManager;
107     private WorkingCopyOwner fWorkingCopyOwner;
108     private boolean fIsComposite;
109     private GroupCategorySet fCategorySet;
110     private boolean fDelegateUpdating;
111     private boolean fDelegateDeprecation;
112     protected boolean fInitialized= false;
113
114     public static final String JavaDoc IDENTIFIER= "org.eclipse.jdt.ui.renameMethodProcessor"; //$NON-NLS-1$
115

116     /**
117      * Creates a new rename method processor.
118      * @param method the method, or <code>null</code> if invoked by scripting
119      */

120     protected RenameMethodProcessor(IMethod method) {
121         this(method, new TextChangeManager(true), null);
122         fIsComposite= false;
123     }
124     
125     /**
126      * Creates a new rename method processor.
127      * <p>
128      * This constructor is only invoked by <code>RenameTypeProcessor</code>.
129      * </p>
130      *
131      * @param method the method
132      * @param manager the change manager
133      * @param categorySet the group category set
134      */

135     protected RenameMethodProcessor(IMethod method, TextChangeManager manager, GroupCategorySet categorySet) {
136         initialize(method);
137         fChangeManager= manager;
138         fCategorySet= categorySet;
139         fDelegateUpdating= false;
140         fDelegateDeprecation= true;
141         fIsComposite= true;
142     }
143     
144     protected void initialize(IMethod method) {
145         fMethod= method;
146         if (!fInitialized) {
147             if (method != null)
148                 setNewElementName(method.getElementName());
149             fUpdateReferences= true;
150             initializeWorkingCopyOwner();
151         }
152     }
153
154     protected void initializeWorkingCopyOwner() {
155         fWorkingCopyOwner= new WorkingCopyOwner() {/*must subclass*/};
156     }
157     
158     protected void setData(RenameMethodProcessor other) {
159         fUpdateReferences= other.fUpdateReferences;
160         setNewElementName(other.getNewElementName());
161     }
162
163     public String JavaDoc getIdentifier() {
164         return IDENTIFIER;
165     }
166
167     public boolean isApplicable() throws CoreException {
168         return RefactoringAvailabilityTester.isRenameAvailable(fMethod);
169     }
170
171     public String JavaDoc getProcessorName() {
172         return RefactoringCoreMessages.RenameMethodRefactoring_name;
173     }
174     
175     protected String JavaDoc[] getAffectedProjectNatures() throws CoreException {
176         return JavaProcessors.computeAffectedNatures(fMethod);
177     }
178
179     public Object JavaDoc[] getElements() {
180         return new Object JavaDoc[] {fMethod};
181     }
182
183     protected RenameModifications computeRenameModifications() throws CoreException {
184         RenameModifications result= new RenameModifications();
185         RenameArguments args= new RenameArguments(getNewElementName(), getUpdateReferences());
186         for (Iterator JavaDoc iter= fMethodsToRename.iterator(); iter.hasNext();) {
187             IMethod method= (IMethod) iter.next();
188             result.rename(method, args);
189         }
190         return result;
191     }
192     
193     protected IFile[] getChangedFiles() throws CoreException {
194         return ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits());
195     }
196     
197     public int getSaveMode() {
198         return RefactoringSaveHelper.SAVE_NON_JAVA_UPDATES;
199     }
200     
201     //---- INameUpdating -------------------------------------
202

203     public final String JavaDoc getCurrentElementName(){
204         return fMethod.getElementName();
205     }
206         
207     public final RefactoringStatus checkNewElementName(String JavaDoc newName) {
208         Assert.isNotNull(newName, "new name"); //$NON-NLS-1$
209

210         RefactoringStatus status= Checks.checkName(newName, JavaConventions.validateMethodName(newName));
211         if (status.isOK() && Checks.startsWithUpperCase(newName))
212             status= RefactoringStatus.createWarningStatus(fIsComposite
213                     ? Messages.format(RefactoringCoreMessages.Checks_method_names_lowercase2, new String JavaDoc[] { newName, fMethod.getDeclaringType().getElementName()})
214                     : RefactoringCoreMessages.Checks_method_names_lowercase);
215         
216         if (Checks.isAlreadyNamed(fMethod, newName))
217             status.addFatalError(fIsComposite
218                     ? Messages.format(RefactoringCoreMessages.RenameMethodRefactoring_same_name2, new String JavaDoc[] { newName, fMethod.getDeclaringType().getElementName() } )
219                     : RefactoringCoreMessages.RenameMethodRefactoring_same_name,
220                     JavaStatusContext.create(fMethod));
221         return status;
222     }
223     
224     public Object JavaDoc getNewElement() {
225         return fMethod.getDeclaringType().getMethod(getNewElementName(), fMethod.getParameterTypes());
226     }
227     
228     public final IMethod getMethod() {
229         return fMethod;
230     }
231     
232     private void initializeMethodsToRename(IProgressMonitor pm) throws CoreException {
233         if (fMethodsToRename == null)
234             fMethodsToRename= new HashSet JavaDoc(Arrays.asList(MethodChecks.getOverriddenMethods(getMethod(), pm)));
235     }
236     
237     protected void setMethodsToRename(IMethod[] methods) {
238         fMethodsToRename= new HashSet JavaDoc(Arrays.asList(methods));
239     }
240     
241     protected Set JavaDoc getMethodsToRename() {
242         return fMethodsToRename;
243     }
244     
245     //---- IReferenceUpdating -----------------------------------
246

247     public boolean canEnableUpdateReferences() {
248         return true;
249     }
250
251     public final void setUpdateReferences(boolean update) {
252         fUpdateReferences= update;
253     }
254     
255     public boolean getUpdateReferences() {
256         return fUpdateReferences;
257     }
258     
259     //------------------- IDelegateUpdating ----------------------
260

261     public boolean canEnableDelegateUpdating() {
262         return true;
263     }
264
265     public boolean getDelegateUpdating() {
266         return fDelegateUpdating;
267     }
268
269     public void setDelegateUpdating(boolean updating) {
270         fDelegateUpdating= updating;
271     }
272
273     public boolean getDeprecateDelegates() {
274         return fDelegateDeprecation;
275     }
276
277     public void setDeprecateDelegates(boolean deprecate) {
278         fDelegateDeprecation= deprecate;
279     }
280
281     //----------- preconditions ------------------
282

283     public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
284         if (! fMethod.exists()){
285             String JavaDoc message= Messages.format(RefactoringCoreMessages.RenameMethodRefactoring_deleted,
286                                 fMethod.getCompilationUnit().getElementName());
287             return RefactoringStatus.createFatalErrorStatus(message);
288         }
289         
290         RefactoringStatus result= Checks.checkAvailability(fMethod);
291         if (result.hasFatalError())
292                 return result;
293         result.merge(Checks.checkIfCuBroken(fMethod));
294         if (JdtFlags.isNative(fMethod))
295             result.addError(RefactoringCoreMessages.RenameMethodRefactoring_no_native);
296         return result;
297     }
298
299     protected RefactoringStatus doCheckFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException {
300         try{
301             RefactoringStatus result= new RefactoringStatus();
302             pm.beginTask("", 9); //$NON-NLS-1$
303
// TODO workaround for https://bugs.eclipse.org/bugs/show_bug.cgi?id=40367
304
if (!Checks.isAvailable(fMethod)) {
305                 result.addFatalError(RefactoringCoreMessages.RenameMethodProcessor_is_binary, JavaStatusContext.create(fMethod));
306                 return result;
307             }
308             result.merge(Checks.checkIfCuBroken(fMethod));
309             if (result.hasFatalError())
310                 return result;
311             pm.setTaskName(RefactoringCoreMessages.RenameMethodRefactoring_taskName_checkingPreconditions);
312             result.merge(checkNewElementName(getNewElementName()));
313             if (result.hasFatalError())
314                 return result;
315             
316             boolean mustAnalyzeShadowing;
317             IMethod[] newNameMethods= searchForDeclarationsOfClashingMethods(new SubProgressMonitor(pm, 1));
318             if (newNameMethods.length == 0) {
319                 mustAnalyzeShadowing= false;
320                 pm.worked(1);
321             } else {
322                 IType[] outerTypes= searchForOuterTypesOfReferences(newNameMethods, new SubProgressMonitor(pm, 1));
323                 if (outerTypes.length > 0) {
324                     //There exists a reference to a clashing method, where the reference is in a nested type.
325
//That nested type could be a type in a ripple method's hierarchy, which could
326
//cause the reference to bind to the new ripple method instead of to
327
//its old binding (a method of an enclosing scope).
328
//-> Getting *more* references than before -> Semantics not preserved.
329
//Example: RenamePrivateMethodTests#testFail6()
330
//TODO: could pass declaringTypes to the RippleMethodFinder and check whether
331
//a hierarchy contains one of outerTypes (or an outer type of an outerType, recursively).
332
mustAnalyzeShadowing= true;
333                     
334                 } else {
335                     boolean hasOldRefsInInnerTypes= true;
336                         //TODO: to implement this optimization:
337
//- move search for references to before this check.
338
//- collect references in inner types.
339
//- for each reference, check for all supertypes and their enclosing types
340
//(recursively), whether they declare a rippleMethod
341
if (hasOldRefsInInnerTypes) {
342                         //There exists a reference to a ripple method in a nested type
343
//of a type in the hierarchy of any ripple method.
344
//When that reference is renamed, and one of the supertypes of the
345
//nested type declared a method matching the new name, then
346
//the renamed reference will bind to the method in its supertype,
347
//since inherited methods bind stronger than methods from enclosing scopes.
348
//Getting *less* references than before -> Semantics not preserved.
349
//Examples: RenamePrivateMethodTests#testFail2(), RenamePrivateMethodTests#testFail5()
350
mustAnalyzeShadowing= true;
351                     } else {
352                         mustAnalyzeShadowing= false;
353                     }
354                 }
355             }
356             
357             initializeMethodsToRename(new SubProgressMonitor(pm, 1));
358             pm.setTaskName(RefactoringCoreMessages.RenameMethodRefactoring_taskName_searchingForReferences);
359             fOccurrences= getOccurrences(new SubProgressMonitor(pm, 3), result);
360             pm.setTaskName(RefactoringCoreMessages.RenameMethodRefactoring_taskName_checkingPreconditions);
361             
362             if (fUpdateReferences)
363                 result.merge(checkRelatedMethods());
364             
365             result.merge(analyzeCompilationUnits()); //removes CUs with syntax errors
366
pm.worked(1);
367             
368             if (result.hasFatalError())
369                 return result;
370             
371             createChanges(new SubProgressMonitor(pm, 1), result);
372             if (fUpdateReferences & mustAnalyzeShadowing)
373                 result.merge(analyzeRenameChanges(new SubProgressMonitor(pm, 1)));
374             else
375                 pm.worked(1);
376             
377             return result;
378         } finally{
379             pm.done();
380         }
381     }
382     
383     private IType[] searchForOuterTypesOfReferences(IMethod[] newNameMethods, IProgressMonitor pm) throws CoreException {
384         final Set JavaDoc outerTypesOfReferences= new HashSet JavaDoc();
385         SearchPattern pattern= RefactoringSearchEngine.createOrPattern(newNameMethods, IJavaSearchConstants.REFERENCES);
386         IJavaSearchScope scope= createRefactoringScope(getMethod());
387         SearchRequestor requestor= new SearchRequestor() {
388             public void acceptSearchMatch(SearchMatch match) throws CoreException {
389                 IMember member= (IMember) match.getElement();
390                 IType declaring= member.getDeclaringType();
391                 if (declaring == null)
392                     return;
393                 IType outer= declaring.getDeclaringType();
394                 if (outer != null)
395                     outerTypesOfReferences.add(declaring);
396             }
397         };
398         new SearchEngine().search(pattern, SearchUtils.getDefaultSearchParticipants(),
399                 scope, requestor, pm);
400         return (IType[]) outerTypesOfReferences.toArray(new IType[outerTypesOfReferences.size()]);
401     }
402
403     private IMethod[] searchForDeclarationsOfClashingMethods(IProgressMonitor pm) throws CoreException {
404         final List JavaDoc results= new ArrayList JavaDoc();
405         SearchPattern pattern= createNewMethodPattern();
406         IJavaSearchScope scope= RefactoringScopeFactory.create(getMethod().getJavaProject());
407         SearchRequestor requestor= new SearchRequestor() {
408             public void acceptSearchMatch(SearchMatch match) throws CoreException {
409                 Object JavaDoc method= match.getElement();
410                 if (method instanceof IMethod) // check for bug 90138: [refactoring] [rename] Renaming method throws internal exception
411
results.add(method);
412                 else
413                     JavaPlugin.logErrorMessage("Unexpected element in search match: " + match.toString()); //$NON-NLS-1$
414
}
415         };
416         new SearchEngine().search(pattern, SearchUtils.getDefaultSearchParticipants(), scope, requestor, pm);
417         return (IMethod[]) results.toArray(new IMethod[results.size()]);
418     }
419     
420     private SearchPattern createNewMethodPattern() throws JavaModelException {
421         StringBuffer JavaDoc stringPattern= new StringBuffer JavaDoc(getNewElementName()).append('(');
422         int paramCount= getMethod().getNumberOfParameters();
423         for (int i= 0; i < paramCount; i++) {
424             if (i > 0)
425                 stringPattern.append(',');
426             stringPattern.append('*');
427         }
428         stringPattern.append(')');
429         
430         return SearchPattern.createPattern(stringPattern.toString(), IJavaSearchConstants.METHOD,
431                 IJavaSearchConstants.DECLARATIONS, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE);
432     }
433     
434     protected final IJavaSearchScope createRefactoringScope() throws CoreException {
435         return createRefactoringScope(fMethod);
436     }
437     //TODO: shouldn't scope take all ripple methods into account?
438
protected static final IJavaSearchScope createRefactoringScope(IMethod method) throws CoreException {
439         return RefactoringScopeFactory.create(method);
440     }
441     
442     SearchPattern createOccurrenceSearchPattern() {
443         HashSet JavaDoc methods= new HashSet JavaDoc(fMethodsToRename);
444         methods.add(fMethod);
445         IMethod[] ms= (IMethod[]) methods.toArray(new IMethod[methods.size()]);
446         return RefactoringSearchEngine.createOrPattern(ms, IJavaSearchConstants.ALL_OCCURRENCES);
447     }
448
449     SearchResultGroup[] getOccurrences(){
450         return fOccurrences;
451     }
452     
453     /*
454      * XXX made protected to allow overriding and working around bug 39700
455      */

456     protected SearchResultGroup[] getOccurrences(IProgressMonitor pm, RefactoringStatus status) throws CoreException {
457         SearchPattern pattern= createOccurrenceSearchPattern();
458         return RefactoringSearchEngine.search(pattern, createRefactoringScope(),
459             new MethodOccurenceCollector(getMethod().getElementName()), pm, status);
460     }
461
462     private RefactoringStatus checkRelatedMethods() throws CoreException {
463         RefactoringStatus result= new RefactoringStatus();
464         for (Iterator JavaDoc iter= fMethodsToRename.iterator(); iter.hasNext(); ) {
465             IMethod method= (IMethod)iter.next();
466             
467             result.merge(Checks.checkIfConstructorName(method, getNewElementName(), method.getDeclaringType().getElementName()));
468             
469             String JavaDoc[] msgData= new String JavaDoc[]{method.getElementName(), JavaModelUtil.getFullyQualifiedName(method.getDeclaringType())};
470             if (! method.exists()){
471                 result.addFatalError(Messages.format(RefactoringCoreMessages.RenameMethodRefactoring_not_in_model, msgData));
472                 continue;
473             }
474             if (method.isBinary())
475                 result.addFatalError(Messages.format(RefactoringCoreMessages.RenameMethodRefactoring_no_binary, msgData));
476             if (method.isReadOnly())
477                 result.addFatalError(Messages.format(RefactoringCoreMessages.RenameMethodRefactoring_no_read_only, msgData));
478             if (JdtFlags.isNative(method))
479                 result.addError(Messages.format(RefactoringCoreMessages.RenameMethodRefactoring_no_native_1, msgData));
480         }
481         return result;
482     }
483     
484     private RefactoringStatus analyzeCompilationUnits() throws CoreException {
485         if (fOccurrences.length == 0)
486             return null;
487             
488         RefactoringStatus result= new RefactoringStatus();
489         fOccurrences= Checks.excludeCompilationUnits(fOccurrences, result);
490         if (result.hasFatalError())
491             return result;
492         
493         result.merge(Checks.checkCompileErrorsInAffectedFiles(fOccurrences));
494             
495         return result;
496     }
497     
498     //-------
499

500     private RefactoringStatus analyzeRenameChanges(IProgressMonitor pm) throws CoreException {
501         ICompilationUnit[] newDeclarationWCs= null;
502         try {
503             pm.beginTask("", 4); //$NON-NLS-1$
504
RefactoringStatus result= new RefactoringStatus();
505             ICompilationUnit[] declarationCUs= getDeclarationCUs();
506             newDeclarationWCs= RenameAnalyzeUtil.createNewWorkingCopies(declarationCUs,
507                     fChangeManager, fWorkingCopyOwner, new SubProgressMonitor(pm, 1));
508             
509             IMethod[] wcOldMethods= new IMethod[fMethodsToRename.size()];
510             IMethod[] wcNewMethods= new IMethod[fMethodsToRename.size()];
511             int i= 0;
512             for (Iterator JavaDoc iter= fMethodsToRename.iterator(); iter.hasNext(); i++) {
513                 IMethod method= (IMethod) iter.next();
514                 ICompilationUnit newCu= RenameAnalyzeUtil.findWorkingCopyForCu(newDeclarationWCs, method.getCompilationUnit());
515                 IType typeWc= (IType) JavaModelUtil.findInCompilationUnit(newCu, method.getDeclaringType());
516                 if (typeWc == null)
517                     continue;
518                 wcOldMethods[i]= getMethodInWorkingCopy(method, getCurrentElementName(), typeWc);
519                 wcNewMethods[i]= getMethodInWorkingCopy(method, getNewElementName(), typeWc);
520             }
521             
522 // SearchResultGroup[] newOccurrences= findNewOccurrences(newMethods, newDeclarationWCs, new SubProgressMonitor(pm, 3));
523
SearchResultGroup[] newOccurrences= batchFindNewOccurrences(wcNewMethods, wcOldMethods, newDeclarationWCs, new SubProgressMonitor(pm, 3), result);
524             
525             result.merge(RenameAnalyzeUtil.analyzeRenameChanges2(fChangeManager, fOccurrences, newOccurrences, getNewElementName()));
526             return result;
527         } finally{
528             pm.done();
529             if (newDeclarationWCs != null){
530                 for (int i= 0; i < newDeclarationWCs.length; i++) {
531                     newDeclarationWCs[i].discardWorkingCopy();
532                 }
533             }
534         }
535     }
536     
537     //Lower memory footprint than batchFindNewOccurrences. Not used because it is too slow.
538
//Final solution is maybe to do searches in chunks of ~ 50 CUs.
539
// private SearchResultGroup[] findNewOccurrences(IMethod[] newMethods, ICompilationUnit[] newDeclarationWCs, IProgressMonitor pm) throws CoreException {
540
// pm.beginTask("", fOccurrences.length * 2); //$NON-NLS-1$
541
//
542
// SearchPattern refsPattern= RefactoringSearchEngine.createOrPattern(newMethods, IJavaSearchConstants.REFERENCES);
543
// SearchParticipant[] searchParticipants= SearchUtils.getDefaultSearchParticipants();
544
// IJavaSearchScope scope= RefactoringScopeFactory.create(newMethods);
545
// MethodOccurenceCollector requestor= new MethodOccurenceCollector(getNewElementName());
546
// SearchEngine searchEngine= new SearchEngine(fWorkingCopyOwner);
547
//
548
// //TODO: should process only references
549
// for (int j= 0; j < fOccurrences.length; j++) { //should be getReferences()
550
// //cut memory peak by holding only one reference CU at a time in memory
551
// ICompilationUnit originalCu= fOccurrences[j].getCompilationUnit();
552
// ICompilationUnit newWc= null;
553
// try {
554
// ICompilationUnit wc= RenameAnalyzeUtil.findWorkingCopyForCu(newDeclarationWCs, originalCu);
555
// if (wc == null) {
556
// newWc= RenameAnalyzeUtil.createNewWorkingCopy(originalCu, fChangeManager, fWorkingCopyOwner,
557
// new SubProgressMonitor(pm, 1));
558
// }
559
// searchEngine.search(refsPattern, searchParticipants, scope, requestor, new SubProgressMonitor(pm, 1));
560
// } finally {
561
// if (newWc != null)
562
// newWc.discardWorkingCopy();
563
// }
564
// }
565
// SearchResultGroup[] newResults= RefactoringSearchEngine.groupByResource(requestor.getResults());
566
// pm.done();
567
// return newResults;
568
// }
569

570     private SearchResultGroup[] batchFindNewOccurrences(IMethod[] wcNewMethods, final IMethod[] wcOldMethods, ICompilationUnit[] newDeclarationWCs, IProgressMonitor pm, RefactoringStatus status) throws CoreException {
571         pm.beginTask("", 2); //$NON-NLS-1$
572

573         SearchPattern refsPattern= RefactoringSearchEngine.createOrPattern(wcNewMethods, IJavaSearchConstants.REFERENCES);
574         SearchParticipant[] searchParticipants= SearchUtils.getDefaultSearchParticipants();
575         IJavaSearchScope scope= RefactoringScopeFactory.create(wcNewMethods);
576         
577         MethodOccurenceCollector requestor;
578         if (getDelegateUpdating()) {
579             // There will be two new matches inside the delegate(s) (the invocation
580
// and the javadoc) which are OK and must not be reported.
581
// Note that except these ocurrences, the delegate bodies are empty
582
// (as they were created this way).
583
requestor= new MethodOccurenceCollector(getNewElementName()) {
584                 public void acceptSearchMatch(ICompilationUnit unit, SearchMatch match) throws CoreException {
585                     for (int i= 0; i < wcOldMethods.length; i++)
586                         if (wcOldMethods[i].equals(match.getElement()))
587                             return;
588                     super.acceptSearchMatch(unit, match);
589                 }
590             };
591         } else
592             requestor= new MethodOccurenceCollector(getNewElementName());
593         
594         SearchEngine searchEngine= new SearchEngine(fWorkingCopyOwner);
595         
596         ArrayList JavaDoc needWCs= new ArrayList JavaDoc();
597         HashSet JavaDoc declaringCUs= new HashSet JavaDoc(newDeclarationWCs.length);
598         for (int i= 0; i < newDeclarationWCs.length; i++)
599             declaringCUs.add(newDeclarationWCs[i].getPrimary());
600         for (int i= 0; i < fOccurrences.length; i++) {
601             ICompilationUnit cu= fOccurrences[i].getCompilationUnit();
602             if (! declaringCUs.contains(cu))
603                 needWCs.add(cu);
604         }
605         ICompilationUnit[] otherWCs= null;
606         try {
607             otherWCs= RenameAnalyzeUtil.createNewWorkingCopies(
608                     (ICompilationUnit[]) needWCs.toArray(new ICompilationUnit[needWCs.size()]),
609                     fChangeManager, fWorkingCopyOwner, new SubProgressMonitor(pm, 1));
610             searchEngine.search(refsPattern, searchParticipants, scope, requestor, new SubProgressMonitor(pm, 1));
611         } finally {
612             pm.done();
613             if (otherWCs != null) {
614                 for (int i= 0; i < otherWCs.length; i++) {
615                     otherWCs[i].discardWorkingCopy();
616                 }
617             }
618         }
619         SearchResultGroup[] newResults= RefactoringSearchEngine.groupByCu(requestor.getResults(), status);
620         return newResults;
621     }
622     
623     private ICompilationUnit[] getDeclarationCUs() {
624         Set JavaDoc cus= new HashSet JavaDoc();
625         for (Iterator JavaDoc iter= fMethodsToRename.iterator(); iter.hasNext();) {
626             IMethod method= (IMethod) iter.next();
627             cus.add(method.getCompilationUnit());
628         }
629         return (ICompilationUnit[]) cus.toArray(new ICompilationUnit[cus.size()]);
630     }
631     
632     private IMethod getMethodInWorkingCopy(IMethod method, String JavaDoc elementName, IType typeWc) throws CoreException{
633         String JavaDoc[] paramTypeSignatures= method.getParameterTypes();
634         return typeWc.getMethod(elementName, paramTypeSignatures);
635     }
636
637     //-------
638
private static IMethod[] classesDeclareMethodName(ITypeHierarchy hier, List JavaDoc classes, IMethod method, String JavaDoc newName) throws CoreException {
639         Set JavaDoc result= new HashSet JavaDoc();
640         IType type= method.getDeclaringType();
641         List JavaDoc subtypes= Arrays.asList(hier.getAllSubtypes(type));
642         
643         int parameterCount= method.getParameterTypes().length;
644         boolean isMethodPrivate= JdtFlags.isPrivate(method);
645         
646         for (Iterator JavaDoc iter= classes.iterator(); iter.hasNext(); ){
647             IType clazz= (IType) iter.next();
648             IMethod[] methods= clazz.getMethods();
649             boolean isSubclass= subtypes.contains(clazz);
650             for (int j= 0; j < methods.length; j++) {
651                 IMethod foundMethod= Checks.findMethod(newName, parameterCount, false, new IMethod[] {methods[j]});
652                 if (foundMethod == null)
653                     continue;
654                 if (isSubclass || type.equals(clazz))
655                     result.add(foundMethod);
656                 else if ((! isMethodPrivate) && (! JdtFlags.isPrivate(methods[j])))
657                     result.add(foundMethod);
658             }
659         }
660         return (IMethod[]) result.toArray(new IMethod[result.size()]);
661     }
662
663     final static IMethod[] hierarchyDeclaresMethodName(IProgressMonitor pm, ITypeHierarchy hierarchy, IMethod method, String JavaDoc newName) throws CoreException {
664         Set JavaDoc result= new HashSet JavaDoc();
665         IType type= method.getDeclaringType();
666         IMethod foundMethod= Checks.findMethod(newName, method.getParameterTypes().length, false, type);
667         if (foundMethod != null)
668             result.add(foundMethod);
669
670         IMethod[] foundInHierarchyClasses= classesDeclareMethodName(hierarchy, Arrays.asList(hierarchy.getAllClasses()), method, newName);
671         if (foundInHierarchyClasses != null)
672             result.addAll(Arrays.asList(foundInHierarchyClasses));
673         
674         IType[] implementingClasses= hierarchy.getImplementingClasses(type);
675         IMethod[] foundInImplementingClasses= classesDeclareMethodName(hierarchy, Arrays.asList(implementingClasses), method, newName);
676         if (foundInImplementingClasses != null)
677             result.addAll(Arrays.asList(foundInImplementingClasses));
678         return (IMethod[]) result.toArray(new IMethod[result.size()]);
679     }
680
681     public Change createChange(IProgressMonitor monitor) throws CoreException {
682         try {
683             final TextChange[] changes= fChangeManager.getAllChanges();
684             final List JavaDoc list= new ArrayList JavaDoc(changes.length);
685             list.addAll(Arrays.asList(changes));
686             String JavaDoc project= null;
687             IJavaProject javaProject= fMethod.getJavaProject();
688             if (javaProject != null)
689                 project= javaProject.getElementName();
690             int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE;
691             try {
692                 if (!Flags.isPrivate(fMethod.getFlags()))
693                     flags|= RefactoringDescriptor.MULTI_CHANGE;
694             } catch (JavaModelException exception) {
695                 JavaPlugin.log(exception);
696             }
697             final IType declaring= fMethod.getDeclaringType();
698             try {
699                 if (declaring.isAnonymous() || declaring.isLocal())
700                     flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
701             } catch (JavaModelException exception) {
702                 JavaPlugin.log(exception);
703             }
704             final String JavaDoc description= Messages.format(RefactoringCoreMessages.RenameMethodProcessor_descriptor_description_short, fMethod.getElementName());
705             final String JavaDoc header= Messages.format(RefactoringCoreMessages.RenameMethodProcessor_descriptor_description, new String JavaDoc[] { JavaElementLabels.getTextLabel(fMethod, JavaElementLabels.ALL_FULLY_QUALIFIED), getNewElementName()});
706             final String JavaDoc comment= new JDTRefactoringDescriptorComment(project, this, header).asString();
707             final RenameJavaElementDescriptor descriptor= new RenameJavaElementDescriptor(IJavaRefactorings.RENAME_METHOD);
708             descriptor.setProject(project);
709             descriptor.setDescription(description);
710             descriptor.setComment(comment);
711             descriptor.setFlags(flags);
712             descriptor.setJavaElement(fMethod);
713             descriptor.setNewName(getNewElementName());
714             descriptor.setUpdateReferences(fUpdateReferences);
715             descriptor.setKeepOriginal(fDelegateUpdating);
716             descriptor.setDeprecateDelegate(fDelegateDeprecation);
717             return new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.RenameMethodProcessor_change_name, (Change[]) list.toArray(new Change[list.size()]));
718         } finally {
719             monitor.done();
720         }
721     }
722
723     private TextChangeManager createChanges(IProgressMonitor pm, RefactoringStatus status) throws CoreException {
724         if (!fIsComposite)
725             fChangeManager.clear();
726         addOccurrences(fChangeManager, pm, status);
727         return fChangeManager;
728     }
729     
730     void addOccurrences(TextChangeManager manager, IProgressMonitor pm, RefactoringStatus status) throws CoreException/*thrown in subtype*/{
731         pm.beginTask("", fOccurrences.length); //$NON-NLS-1$
732
for (int i= 0; i < fOccurrences.length; i++){
733             ICompilationUnit cu= fOccurrences[i].getCompilationUnit();
734             if (cu == null)
735                 continue;
736             
737             SearchMatch[] results= fOccurrences[i].getSearchResults();
738
739             // Split matches into declaration and non-declaration matches
740

741             List JavaDoc declarationsInThisCu= new ArrayList JavaDoc();
742             List JavaDoc referencesInThisCu= new ArrayList JavaDoc();
743              
744             for (int j= 0; j < results.length; j++) {
745                 if (results[j] instanceof MethodDeclarationMatch)
746                     declarationsInThisCu.add(results[j]);
747                 else
748                     referencesInThisCu.add(results[j]);
749             }
750
751             // First, handle the declarations
752
if (declarationsInThisCu.size() > 0) {
753
754                 if (fDelegateUpdating) {
755                     // Update with delegates
756
CompilationUnitRewrite rewrite= new CompilationUnitRewrite(cu);
757                     rewrite.setResolveBindings(true);
758
759                     for (Iterator JavaDoc iter= declarationsInThisCu.iterator(); iter.hasNext();) {
760                         SearchMatch element= (SearchMatch) iter.next();
761                         MethodDeclaration method= ASTNodeSearchUtil.getMethodDeclarationNode((IMethod) element.getElement(), rewrite.getRoot());
762                         DelegateCreator creator= new DelegateMethodCreator();
763                         creator.setDeclareDeprecated(fDelegateDeprecation);
764                         creator.setDeclaration(method);
765                         creator.setSourceRewrite(rewrite);
766                         creator.setNewElementName(getNewElementName());
767                         creator.prepareDelegate();
768                         creator.createEdit();
769                     }
770                     // Need to handle all delegates first as this
771
// creates a completely new change object.
772
TextChange changeForThisCu= rewrite.createChange();
773                     changeForThisCu.setKeepPreviewEdits(true);
774                     manager.manage(cu, changeForThisCu);
775                 }
776
777                 // Update the normal methods
778
for (Iterator JavaDoc iter= declarationsInThisCu.iterator(); iter.hasNext();) {
779                     SearchMatch element= (SearchMatch) iter.next();
780                     simpleUpdate(element, cu, manager.get(cu));
781                 }
782             }
783
784             // Second, handle references
785
if (fUpdateReferences) {
786                 for (Iterator JavaDoc iter= referencesInThisCu.iterator(); iter.hasNext();) {
787                     SearchMatch element= (SearchMatch) iter.next();
788                     simpleUpdate(element, cu, manager.get(cu));
789                 }
790             }
791             
792             pm.worked(1);
793             if (pm.isCanceled())
794                 throw new OperationCanceledException();
795         }
796         pm.done();
797     }
798
799     private void simpleUpdate(SearchMatch element, ICompilationUnit cu, TextChange textChange) {
800         String JavaDoc editName= RefactoringCoreMessages.RenameMethodRefactoring_update_occurrence;
801         ReplaceEdit replaceEdit= createReplaceEdit(element, cu);
802         addTextEdit(textChange, editName, replaceEdit);
803     }
804
805     protected final ReplaceEdit createReplaceEdit(SearchMatch searchResult, ICompilationUnit cu) {
806         if (searchResult.isImplicit()) { // handle Annotation Element references, see bug 94062
807
StringBuffer JavaDoc sb= new StringBuffer JavaDoc(getNewElementName());
808             if (JavaCore.INSERT.equals(cu.getJavaProject().getOption(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_BEFORE_ASSIGNMENT_OPERATOR, true)))
809                 sb.append(' ');
810             sb.append('=');
811             if (JavaCore.INSERT.equals(cu.getJavaProject().getOption(DefaultCodeFormatterConstants.FORMATTER_INSERT_SPACE_AFTER_ASSIGNMENT_OPERATOR, true)))
812                 sb.append(' ');
813             return new ReplaceEdit(searchResult.getOffset(), 0, sb.toString());
814         } else {
815             return new ReplaceEdit(searchResult.getOffset(), searchResult.getLength(), getNewElementName());
816         }
817     }
818
819     public RefactoringStatus initialize(RefactoringArguments arguments) {
820         if (arguments instanceof JavaRefactoringArguments) {
821             fInitialized= true;
822             final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments;
823             final String JavaDoc handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT);
824             if (handle != null) {
825                 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
826                 final String JavaDoc refactoring= getRefactoring().getName();
827                 if (element instanceof IMethod) {
828                     final IMethod method= (IMethod) element;
829                     final IType declaring= method.getDeclaringType();
830                     if (declaring != null && declaring.exists()) {
831                         final IMethod[] methods= declaring.findMethods(method);
832                         if (methods != null && methods.length == 1 && methods[0] != null) {
833                             if (!methods[0].exists())
834                                 return ScriptableRefactoring.createInputFatalStatus(methods[0], refactoring, IJavaRefactorings.RENAME_METHOD);
835                             fMethod= methods[0];
836                             initializeWorkingCopyOwner();
837                         } else
838                             return ScriptableRefactoring.createInputFatalStatus(null, refactoring, IJavaRefactorings.RENAME_METHOD);
839                     } else
840                         return ScriptableRefactoring.createInputFatalStatus(element, refactoring, IJavaRefactorings.RENAME_METHOD);
841                 } else
842                     return ScriptableRefactoring.createInputFatalStatus(element, refactoring, IJavaRefactorings.RENAME_METHOD);
843             } else
844                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT));
845             final String JavaDoc name= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_NAME);
846             if (name != null && !"".equals(name)) //$NON-NLS-1$
847
setNewElementName(name);
848             else
849                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_NAME));
850             final String JavaDoc references= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_REFERENCES);
851             if (references != null) {
852                 fUpdateReferences= Boolean.valueOf(references).booleanValue();
853             } else
854                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_REFERENCES));
855             final String JavaDoc delegate= extended.getAttribute(ATTRIBUTE_DELEGATE);
856             if (delegate != null) {
857                 fDelegateUpdating= Boolean.valueOf(delegate).booleanValue();
858             } else
859                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DELEGATE));
860             final String JavaDoc deprecate= extended.getAttribute(ATTRIBUTE_DEPRECATE);
861             if (deprecate != null) {
862                 fDelegateDeprecation= Boolean.valueOf(deprecate).booleanValue();
863             } else
864                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DEPRECATE));
865         } else
866             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
867         return new RefactoringStatus();
868     }
869
870     protected void addTextEdit(TextChange change, String JavaDoc editName, ReplaceEdit replaceEdit) {
871         if (fIsComposite)
872             TextChangeCompatibility.addTextEdit(change, editName, replaceEdit, fCategorySet);
873         else
874             TextChangeCompatibility.addTextEdit(change, editName, replaceEdit);
875
876     }
877 }
878
Popular Tags