KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > structure > InstanceMethodMover


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

11 package org.eclipse.jdt.internal.corext.refactoring.structure;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.HashSet JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20 import java.util.Set JavaDoc;
21 import java.util.Vector JavaDoc;
22
23 import org.eclipse.text.edits.MultiTextEdit;
24 import org.eclipse.text.edits.RangeMarker;
25 import org.eclipse.text.edits.TextEdit;
26
27 import org.eclipse.core.runtime.CoreException;
28 import org.eclipse.core.runtime.IProgressMonitor;
29
30 import org.eclipse.core.resources.IFile;
31
32 import org.eclipse.jdt.core.ICompilationUnit;
33 import org.eclipse.jdt.core.IJavaProject;
34 import org.eclipse.jdt.core.IType;
35 import org.eclipse.jdt.core.JavaModelException;
36 import org.eclipse.jdt.core.NamingConventions;
37 import org.eclipse.jdt.core.dom.AST;
38 import org.eclipse.jdt.core.dom.ASTNode;
39 import org.eclipse.jdt.core.dom.ASTVisitor;
40 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
41 import org.eclipse.jdt.core.dom.Assignment;
42 import org.eclipse.jdt.core.dom.Block;
43 import org.eclipse.jdt.core.dom.BodyDeclaration;
44 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
45 import org.eclipse.jdt.core.dom.CompilationUnit;
46 import org.eclipse.jdt.core.dom.Expression;
47 import org.eclipse.jdt.core.dom.FieldAccess;
48 import org.eclipse.jdt.core.dom.IBinding;
49 import org.eclipse.jdt.core.dom.IMethodBinding;
50 import org.eclipse.jdt.core.dom.ITypeBinding;
51 import org.eclipse.jdt.core.dom.IVariableBinding;
52 import org.eclipse.jdt.core.dom.MethodDeclaration;
53 import org.eclipse.jdt.core.dom.MethodInvocation;
54 import org.eclipse.jdt.core.dom.Modifier;
55 import org.eclipse.jdt.core.dom.Name;
56 import org.eclipse.jdt.core.dom.PostfixExpression;
57 import org.eclipse.jdt.core.dom.PrefixExpression;
58 import org.eclipse.jdt.core.dom.PrimitiveType;
59 import org.eclipse.jdt.core.dom.QualifiedName;
60 import org.eclipse.jdt.core.dom.ReturnStatement;
61 import org.eclipse.jdt.core.dom.SimpleName;
62 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
63 import org.eclipse.jdt.core.dom.Statement;
64 import org.eclipse.jdt.core.dom.SuperFieldAccess;
65 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
66 import org.eclipse.jdt.core.dom.ThisExpression;
67 import org.eclipse.jdt.core.dom.Type;
68 import org.eclipse.jdt.core.dom.TypeDeclaration;
69 import org.eclipse.jdt.core.dom.VariableDeclaration;
70 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
71
72 import org.eclipse.jface.text.IRegion;
73 import org.eclipse.jface.text.Region;
74
75 import org.eclipse.jdt.internal.corext.Assert;
76 import org.eclipse.jdt.internal.corext.Corext;
77 import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
78 import org.eclipse.jdt.internal.corext.codemanipulation.ImportRewrite;
79 import org.eclipse.jdt.internal.corext.dom.OldASTRewrite;
80 import org.eclipse.jdt.internal.corext.dom.Bindings;
81 import org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor;
82 import org.eclipse.jdt.internal.corext.dom.JavaElementMapper;
83 import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
84 import org.eclipse.jdt.internal.corext.refactoring.Checks;
85 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
86 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
87 import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes;
88 import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
89 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationStateChange;
90 import org.eclipse.jdt.internal.corext.refactoring.structure.InstanceMethodMover.Method.Delegation;
91 import org.eclipse.jdt.internal.corext.refactoring.structure.InstanceMethodMover.Method.MethodEditSession;
92 import org.eclipse.jdt.internal.corext.refactoring.structure.MoveInstanceMethodRefactoring.INewReceiver;
93 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
94 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
95 import org.eclipse.jdt.internal.corext.textmanipulation.TextBuffer;
96 import org.eclipse.jdt.internal.corext.textmanipulation.TextBufferEditor;
97 import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
98 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
99 import org.eclipse.jdt.internal.corext.util.JdtFlags;
100 import org.eclipse.jdt.internal.corext.util.Strings;
101 import org.eclipse.ltk.core.refactoring.Change;
102 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
103 import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
104 import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
105 import org.eclipse.ltk.core.refactoring.TextChange;
106
107 class InstanceMethodMover {
108     
109     private static interface IParameter {
110         public ITypeBinding getType();
111         
112         public String JavaDoc getName();
113     }
114     
115     private static abstract class NewReceiver implements MoveInstanceMethodRefactoring.INewReceiver {
116         private final IJavaProject fDependentProject;
117         
118         //cache:
119
private IType fModelClass;
120         
121         private NewReceiver(IJavaProject dependentProject, CodeGenerationSettings codeGenSettings) {
122             Assert.isNotNull(dependentProject);
123             Assert.isNotNull(codeGenSettings);
124             
125             fDependentProject= dependentProject;
126         }
127         
128         public abstract String JavaDoc getName();
129
130         public ITypeBinding getType() {
131             return getReceiverClass();
132         }
133
134         public boolean isField() {
135             return false;
136         }
137
138         public boolean isParameter() {
139             return false;
140         }
141
142         protected abstract ITypeBinding getReceiverClass();
143
144         protected ICompilationUnit getReceiverClassCU() throws JavaModelException {
145             return JavaModelUtil.toWorkingCopy(getReceiverModelClass().getCompilationUnit());
146         }
147         
148         abstract Expression[] getReferencesIn(Method method);
149         
150         abstract Expression createReferenceForContext(Method context);
151         
152         Change moveMethodToMe(Method method, String JavaDoc newMethodName, String JavaDoc originalReceiverParameterName, boolean inlineDelegator, boolean removeDelegator) throws CoreException {
153             Assert.isNotNull(method);
154             Assert.isNotNull(newMethodName);
155             Assert.isNotNull(originalReceiverParameterName);
156             Assert.isTrue(inlineDelegator || !removeDelegator);
157             Assert.isTrue(Arrays.asList(method.getPossibleNewReceivers()).contains(this));
158
159             TextChangeManager manager= new TextChangeManager();
160             addMovedMethodToMyClass(manager, method, newMethodName, originalReceiverParameterName);
161             replaceOriginalMethodBodyWithDelegation(manager, method, newMethodName);
162
163             return getChange(manager);
164         }
165         
166         private static Change getChange(TextChangeManager manager) {
167             TextChange[] changes= manager.getAllChanges();
168             if (changes.length == 1) {
169                 return changes[0];
170             } else {
171                 return new DynamicValidationStateChange(RefactoringCoreMessages.getString("InstanceMethodMover.move_method"), changes); //$NON-NLS-1$
172
}
173         }
174
175         private void replaceOriginalMethodBodyWithDelegation(TextChangeManager manager, Method originalMethod, String JavaDoc newMethodName) throws CoreException {
176             Method.MethodEditSession methodEditSession= originalMethod.createEditSession();
177             methodEditSession.replaceBodyWithDelegation(
178                 specifyDelegationToNewMethod(originalMethod, newMethodName));
179             TextChange cuChange= manager.get(originalMethod.getDeclaringCU());
180             TextChangeCompatibility.addTextEdit(cuChange, RefactoringCoreMessages.getString("InstanceMethodMover.replace_with_delegation"), methodEditSession.getEdits()); //$NON-NLS-1$
181
}
182         
183         abstract Method.Delegation specifyDelegationToNewMethod(Method originalMethod, String JavaDoc newMethodName);
184         
185         private void addMovedMethodToMyClass(TextChangeManager manager, Method originalMethod, String JavaDoc newMethodName, String JavaDoc originalReceiverParameterName) throws CoreException {
186             List JavaDoc allTypesUsedWithoutQualification= new ArrayList JavaDoc();
187             TextBufferPortion newMethodText= getNewMethodDeclarationText(originalMethod, newMethodName, originalReceiverParameterName, allTypesUsedWithoutQualification);
188             addNewMethodToMyClass(manager, newMethodText.getUnindentedContentIgnoreFirstLine(), allTypesUsedWithoutQualification);
189         }
190         
191         private void addNewMethodToMyClass(TextChangeManager manager, String JavaDoc newMethodText, List JavaDoc allTypesUsedWithoutQualification) throws CoreException {
192             TypeDeclaration myClassDeclaration= getReceiverClassDeclaration();
193             OldASTRewrite rewrite= new OldASTRewrite(myClassDeclaration);
194             BodyDeclaration newMethodNode= (BodyDeclaration) rewrite.createStringPlaceholder(newMethodText, ASTNode.METHOD_DECLARATION);
195             myClassDeclaration.bodyDeclarations().add(newMethodNode);
196             rewrite.markAsInserted(newMethodNode);
197
198             TextBuffer buffer= TextBuffer.create(getReceiverClassCU().getBuffer().getContents());
199             MultiTextEdit edit= new MultiTextEdit();
200             rewrite.rewriteNode(buffer, edit);
201             rewrite.removeModifications();
202             
203             TextChange cuChange= manager.get(getReceiverClassCU());
204             TextChangeCompatibility.addTextEdit(
205                 cuChange,
206                 RefactoringCoreMessages.getString("InstanceMethodMover.create_in_receiver"), edit); //$NON-NLS-1$
207
ImportRewrite importRewrite= createImportRewrite(allTypesUsedWithoutQualification, getReceiverClassCU());
208             TextChangeCompatibility.addTextEdit(
209                 cuChange,
210                 RefactoringCoreMessages.getString("InstanceMethodMover.add_imports"), importRewrite.createEdit(buffer.getDocument())); //$NON-NLS-1$
211
}
212
213         private ImportRewrite createImportRewrite(List JavaDoc types, ICompilationUnit cu) throws CoreException {
214             ImportRewrite importEdit= new ImportRewrite(cu);
215             for(Iterator JavaDoc it= types.iterator(); it.hasNext();)
216                 importEdit.addImport((ITypeBinding) it.next());
217             return importEdit;
218         }
219
220         protected TypeDeclaration getReceiverClassDeclaration() throws JavaModelException {
221             ASTNode result= JavaElementMapper.perform(getReceiverModelClass(), TypeDeclaration.class);
222             Assert.isTrue(result instanceof TypeDeclaration);
223             return (TypeDeclaration) result;
224         }
225         
226         private IType getReceiverModelClass() throws JavaModelException {
227             if(fModelClass == null)
228                 fModelClass= computeReceiverModelClass();
229             return fModelClass;
230         }
231     
232         private boolean isReceiverModelClassAvailable() throws JavaModelException {
233             if(fModelClass == null)
234                 fModelClass= computeReceiverModelClass();
235             return fModelClass != null;
236         }
237         
238         private IType computeReceiverModelClass() throws JavaModelException {
239             return getModelClass(getReceiverClass(), fDependentProject);
240         }
241         
242         private TextBufferPortion getNewMethodDeclarationText(Method method, String JavaDoc newMethodName, String JavaDoc originalReceiverParameterName, List JavaDoc allTypesUsed) throws CoreException {
243             Method.MethodEditSession methodEditSession= method.createEditSession();
244             methodEditSession.changeMethodName(newMethodName);
245             
246             methodEditSession.classQualifyNonInstanceMemberReferences();
247             
248             if(method.hasSelfReferences(this)) {
249                 methodEditSession.addNewFirstParameter(method.getDeclaringClass(), originalReceiverParameterName);
250                 methodEditSession.replaceSelfReferencesWithReferencesToName(originalReceiverParameterName);
251             }
252             
253             methodEditSession.replaceNewReceiverReferencesWithSelfReferences(this);
254             transformNonReferenceMentionsIn(methodEditSession);
255             
256             TextBufferPortion result= methodEditSession.getEdittedMethodText();
257             allTypesUsed.addAll(methodEditSession.getAllTypesUsedWithoutQualificationInEdittedMethod());
258             methodEditSession.clear();
259             return result;
260         }
261         
262         abstract void transformNonReferenceMentionsIn(Method.MethodEditSession methodEditSession);
263                 
264         IParameter[] getMovedMethodParameterDescriptions(final Method originalMethod, final String JavaDoc originalReceiverParameterName) {
265             Assert.isNotNull(originalMethod);
266             Assert.isNotNull(originalReceiverParameterName);
267             
268             IParameter[] originalMethodParams= originalMethod.getParameters();
269             if(!originalMethod.hasSelfReferences(this))
270                 return originalMethodParams;
271             else {
272                 IParameter[] result= new IParameter[1 + originalMethodParams.length];
273                 
274                 result[0]= new IParameter() {
275                     public ITypeBinding getType() {
276                         return originalMethod.getDeclaringClass();
277                     }
278                     public String JavaDoc getName() {
279                         return originalReceiverParameterName;
280                     }
281                 };
282                 
283                 for(int i= 0; i < originalMethodParams.length; i++)
284                     result[i + 1]= originalMethodParams[i];
285                 
286                 return result;
287             }
288         }
289         
290         public int hashCode() {
291             Assert.isTrue(false, "hashing of NewReceiver unsupported");//unless specified by subclass //$NON-NLS-1$
292
return 0;
293         }
294         
295         final RefactoringStatus checkMoveOfMethodToMe(Method method, String JavaDoc newMethodName, String JavaDoc originalReceiverParameterName, boolean inlineDelegator, boolean removeDelegator, Object JavaDoc validationContext) throws JavaModelException {
296             Assert.isNotNull(method);
297             Assert.isNotNull(newMethodName);
298             Assert.isNotNull(originalReceiverParameterName);
299             Assert.isTrue(inlineDelegator || ! removeDelegator);
300         
301             if( ! isReceiverModelClassAvailable())
302                 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.getString("InstanceMethodMover.to_local_localunsupported"), null, Corext.getPluginId(), RefactoringStatusCodes.CANNOT_MOVE_TO_LOCAL, null); //$NON-NLS-1$
303

304             RefactoringStatus result= new RefactoringStatus();
305             checkParameterNames(result, method, originalReceiverParameterName);
306             if (result.hasFatalError())
307                 return result;
308             result.merge(Checks.validateModifiesFiles(getFilesToBeModified(method), validationContext));
309             return result;
310         }
311         
312         private void checkParameterNames(RefactoringStatus result, Method method, String JavaDoc originalReceiverParameterName) {
313             for (Iterator JavaDoc iter= method.getMethodDeclaration().parameters().iterator(); iter.hasNext();) {
314                 SingleVariableDeclaration param= (SingleVariableDeclaration) iter.next();
315                 if (originalReceiverParameterName.equals(param.getName().getIdentifier())){
316                     RefactoringStatusContext context= JavaStatusContext.create(method.getDeclaringCU(), param);
317                     String JavaDoc msg= RefactoringCoreMessages.getFormattedString("InstanceMethodMover.parameter_name_used", new String JavaDoc[]{originalReceiverParameterName}); //$NON-NLS-1$
318
int code= RefactoringStatusCodes.PARAM_NAME_ALREADY_USED;
319                     RefactoringStatusEntry entry= new RefactoringStatusEntry(RefactoringStatus.ERROR, msg, context, Corext.getPluginId(), code, null);
320                     result.addEntry(entry);
321                     return; //cannot conflict with more than 1
322
}
323             }
324         }
325         
326         private IFile[] getFilesToBeModified(Method method) throws JavaModelException {
327             IFile file1= getFile(getReceiverClassCU());
328             IFile file2= getFile(method.getDeclaringCU());
329             if (file1.equals(file2))
330                 return new IFile[]{file1};
331             else
332                 return new IFile[]{file1, file2};
333         }
334         
335         private static IFile getFile(ICompilationUnit cunit) throws JavaModelException {
336             return ResourceUtil.getFile(cunit);
337         }
338
339         public abstract boolean hasFieldsAccessesOtherThanToMe(SimpleName[] fieldAccesses);
340     }
341
342     private static abstract class VariableNewReceiver extends NewReceiver {
343         VariableNewReceiver(IJavaProject dependentProject, CodeGenerationSettings codeGenSettings) {
344             super(dependentProject, codeGenSettings);
345         }
346         
347         protected abstract IVariableBinding getVariable();
348         
349         public IBinding getBinding(){
350             return getVariable();
351         }
352
353         protected final RefactoringStatus checkVariableNotWrittenInMethod(Method method) {
354 // IVariableBinding variable= getVariable();
355
return new RefactoringStatus();
356         }
357
358         protected ITypeBinding getReceiverClass() {
359             return getVariable().getType();
360         }
361         
362         public String JavaDoc getName() {
363             return getVariable().getName();
364         }
365         
366         Expression[] getReferencesIn(Method method) {
367             return method.getVariableReferences(getVariable());
368         }
369     }
370     
371     private static class ParameterNewReceiver extends VariableNewReceiver {
372         private final Parameter fParameter;
373
374         ParameterNewReceiver(Parameter parameter, IJavaProject dependentProject, CodeGenerationSettings codeGenSettings) {
375             super(dependentProject, codeGenSettings);
376             Assert.isNotNull(parameter);
377             Assert.isTrue(parameter.getType().isClass());
378             
379             fParameter= parameter;
380         }
381
382         public boolean isParameter() {
383             return true;
384         }
385         
386         protected IVariableBinding getVariable() {
387             return fParameter.getBinding();
388         }
389
390         Expression createReferenceForContext(Method context) {
391             Assert.isTrue(context == fParameter.getMethod());
392             return fParameter.createReference();
393         }
394         
395         private Parameter getParameter() {
396             return fParameter;
397         }
398         
399         public boolean equals(Object JavaDoc o) {
400             if(o == null)
401                 return false;
402             if(!getClass().equals(o.getClass()))
403                 return false;
404             return getParameter().equals(((ParameterNewReceiver) o).getParameter());
405         }
406         
407         public int hashCode() {
408             return getParameter().hashCode();
409         }
410
411         protected void transformNonReferenceMentionsIn(MethodEditSession methodEditSession) {
412             methodEditSession.removeParameter(getParameter());
413         }
414
415         Delegation specifyDelegationToNewMethod(Method originalMethod, String JavaDoc newMethodName) {
416             Method.Delegation delegation= originalMethod.getPotentialDelegationTo(this);
417             delegation.setCalledMethodName(newMethodName);
418
419             boolean hasSelfReferences= originalMethod.hasSelfReferences(this);
420
421             if(hasSelfReferences)
422                 delegation.passThisAsArgument(0);
423
424             Parameter[] params= originalMethod.getParameters();
425             int argumentIndex= hasSelfReferences ? 1 : 0;
426             for(int parameterIndex= 0; parameterIndex < params.length; parameterIndex++) {
427                 if(!params[parameterIndex].equals(getParameter())) {
428                     delegation.mapParameterToArgument(parameterIndex, argumentIndex);
429                     argumentIndex++;
430                 }
431             }
432
433             return delegation;
434         }
435
436         public boolean hasFieldsAccessesOtherThanToMe(SimpleName[] fieldAccesses) {
437             return fieldAccesses.length != 0;
438         }
439     }
440     
441     private static class FieldNewReceiver extends VariableNewReceiver {
442         private final IVariableBinding fField;
443         
444         FieldNewReceiver(IVariableBinding fieldBinding, IJavaProject dependentProject, CodeGenerationSettings codeGenSettings) {
445             super(dependentProject, codeGenSettings);
446             Assert.isNotNull(fieldBinding);
447             Assert.isTrue(fieldBinding.isField());
448             
449             fField= fieldBinding;
450         }
451         
452         public boolean isField() {
453             return true;
454         }
455         
456         protected IVariableBinding getVariable() {
457             return getField();
458         }
459         
460         private IVariableBinding getField() {
461             return fField;
462         }
463
464         Expression createReferenceForContext(Method context) {
465             Assert.isNotNull(context);
466             return context.createFieldReference(fField);
467         }
468         
469         public boolean equals(Object JavaDoc o) {
470             if(o == null)
471                 return false;
472             if(!getClass().equals(o.getClass()))
473                 return false;
474             return getField().getKey().equals(((FieldNewReceiver) o).getField().getKey());
475         }
476         
477         public int hashCode() {
478             return getField().getKey().hashCode();
479         }
480
481         
482         protected void transformNonReferenceMentionsIn(MethodEditSession methodEditSession) {
483             //A method to be moved to a FieldNewReceiver contains no non-reference mentions of the new receiver
484
}
485     
486         Delegation specifyDelegationToNewMethod(Method originalMethod, String JavaDoc newMethodName) {
487             Method.Delegation delegation= originalMethod.getPotentialDelegationTo(this);
488             delegation.setCalledMethodName(newMethodName);
489
490             boolean hasSelfReferences= originalMethod.hasSelfReferences(this);
491
492             if(hasSelfReferences)
493                 delegation.passThisAsArgument(0);
494
495             int numberOfParams= originalMethod.getParameters().length;
496             for(int parameterIndex= 0; parameterIndex < numberOfParams; parameterIndex++)
497                 delegation.mapParameterToArgument(
498                     parameterIndex,
499                     hasSelfReferences ?
500                         parameterIndex + 1 : parameterIndex
501                 );
502
503             return delegation;
504         }
505
506         public boolean hasFieldsAccessesOtherThanToMe(SimpleName[] fieldAccesses) {
507             //Fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=38310
508
for (int i = 0; i < fieldAccesses.length; i++) {
509                 SimpleName access = fieldAccesses[i];
510                 if (access.resolveBinding() != getField()) {
511                     return true;
512                 }
513             }
514             return false;
515         }
516     }
517     
518     static class Method {
519         static class Delegation {
520             private final NewReceiver fNewReceiver2;//use name other than fNewReceiver to avoid hiding
521

522             private final Method fDelegatingMethod;
523             
524             private String JavaDoc fCalledMethodName;
525             private boolean fPassThis;
526             private int fArgumentToPassThisAs;
527             
528             private final Vector JavaDoc fArgumentToParameterMap= new Vector JavaDoc();
529             
530             private Delegation(Method delegatingMethod, NewReceiver newReceiver) {
531                 Assert.isNotNull(newReceiver);
532                 fNewReceiver2= newReceiver;
533                 fDelegatingMethod= delegatingMethod;
534             }
535             
536             public void setCalledMethodName(String JavaDoc called) {
537                 Assert.isNotNull(called);
538                 fCalledMethodName= called;
539             }
540     
541             public void passThisAsArgument(int argumentIndex) {
542                 Assert.isTrue(argumentIndex >= 0);
543                 notifyOfNewArgument(argumentIndex);
544                 fArgumentToPassThisAs= argumentIndex;
545                 fPassThis= true;
546             }
547     
548             private void notifyOfNewArgument(int argumentIndex) {
549                 if(argumentIndex + 1> fArgumentToParameterMap.size())
550                     fArgumentToParameterMap.setSize(argumentIndex + 1);
551             }
552             
553             private int getNumberOfArguments() {
554                 return fArgumentToParameterMap.size();
555             }
556     
557             public void mapParameterToArgument(int parameterIndex, int argumentIndex) {
558                 Assert.isTrue(parameterIndex >= 0);
559                 Assert.isTrue(parameterIndex < fDelegatingMethod.getParameters().length);
560                 Assert.isTrue(argumentIndex >= 0);
561                 
562                 notifyOfNewArgument(argumentIndex);
563                 fArgumentToParameterMap.set(argumentIndex, new Integer JavaDoc(parameterIndex));
564             }
565             
566             private Method getDelegatingMethod() {
567                 return fDelegatingMethod;
568             }
569             
570             private MethodInvocation createDelegatingInvocation() {
571                 Assert.isTrue(isComplete());
572                 
573                 MethodInvocation invocation= fDelegatingMethod.getAST().newMethodInvocation();
574                 invocation.setExpression(fNewReceiver2.createReferenceForContext(fDelegatingMethod));
575                 invocation.setName(fDelegatingMethod.getAST().newSimpleName(fCalledMethodName));
576                 
577                 Parameter[] params= fDelegatingMethod.getParameters();
578                 for(int i= 0; i < getNumberOfArguments(); i++) {
579                     if(fPassThis && fArgumentToPassThisAs == i)
580                         invocation.arguments().add(fDelegatingMethod.getAST().newThisExpression());
581                     else {
582                         Integer JavaDoc parameterIndex= (Integer JavaDoc) fArgumentToParameterMap.get(i);
583                         Assert.isNotNull(parameterIndex);
584                         Parameter parameter= params[parameterIndex.intValue()];
585                         invocation.arguments().add(fDelegatingMethod.getAST().newSimpleName(parameter.getName()));
586                     }
587                 }
588                 
589                 return invocation;
590             }
591     
592             private boolean isComplete() {
593                 return fCalledMethodName != null
594                        && hasAllArguments();
595             }
596             
597             private boolean hasAllArguments() {
598                 for(int i= 0; i < getNumberOfArguments(); i++)
599                     if(!hasArgument(i))
600                         return false;
601                 return true;
602             }
603             
604             private boolean hasArgument(int i) {
605                 return fArgumentToParameterMap.get(i) != null
606                        || fPassThis && fArgumentToPassThisAs == i;
607                 
608             }
609         }
610         
611         static class MethodEditSession {
612             private final Method fMethod;
613             private final OldASTRewrite fRewrite;
614             
615             private TypeReferences fTypeReferences;
616             
617             private MethodEditSession(Method method) throws JavaModelException {
618                 Assert.isNotNull(method);
619                 fMethod= method;
620                 fRewrite= method.createRewrite();
621                 fTypeReferences= method.getTypeReferences();
622             }
623             
624             public void replaceSelfReferencesWithReferencesToName(String JavaDoc name) {
625                 Assert.isNotNull(name);
626                 
627                 replaceExplicitThisReferencesWith(name);
628                 replaceImplicitThisInFieldAccessesWith(name);
629                 replaceImplicitThisInMethodInvocationsWith(name);
630             }
631     
632             private boolean replaceExplicitThisReferencesWith(String JavaDoc name) {
633                 ThisExpression[] thisReferences= fMethod.getExplicitThisReferences();
634                 for(int i= 0; i < thisReferences.length; i++)
635                     fRewrite.replace(thisReferences[i], thisReferences[i].getAST().newSimpleName(name), null);
636                 return thisReferences.length != 0;
637             }
638     
639             private boolean replaceImplicitThisInFieldAccessesWith(String JavaDoc name) {
640                 SimpleName[] fieldReferences= fMethod.getImplicitThisFieldAccesses();
641                 for(int i= 0; i < fieldReferences.length; i++) {
642                     SimpleName fieldName= fieldReferences[i];
643                     FieldAccess replacement= fieldName.getAST().newFieldAccess();
644                     replacement.setExpression(fieldName.getAST().newSimpleName(name));
645                     replacement.setName(fieldName.getAST().newSimpleName(fieldName.getIdentifier()));
646                     fRewrite.replace(fieldName, replacement, null);
647                 }
648                 return fieldReferences.length != 0;
649             }
650     
651             private boolean replaceImplicitThisInMethodInvocationsWith(String JavaDoc name) {
652                 MethodInvocation[] methodInvocations= fMethod.getImplicitThisMethodInvocations();
653                 for(int i= 0; i < methodInvocations.length; i++) {
654                     MethodInvocation original= methodInvocations[i];
655                     Expression newExpression= original.getAST().newSimpleName(name);
656                     Assert.isTrue(original.getExpression() == null);
657                     original.setExpression(newExpression);
658                     fRewrite.markAsInserted(newExpression);
659                 }
660                 return methodInvocations.length != 0;
661             }
662             
663             public void replaceNewReceiverReferencesWithSelfReferences(NewReceiver newReceiver) {
664                 Expression[] newReceiverReferences= newReceiver.getReferencesIn(fMethod);
665                 for(int i= 0; i < newReceiverReferences.length; i++)
666                     replaceExpressionWithSelfReference(newReceiverReferences[i]);
667             }
668     
669             private void replaceExpressionWithSelfReference(Expression expression) {
670                 Assert.isNotNull(expression);
671                 
672                 ASTNode parent= expression.getParent();
673                 if (parent instanceof MethodInvocation) {
674                     MethodInvocation invocation= (MethodInvocation) parent;
675                     if(expression.equals(invocation.getExpression()))
676                         replaceReceiverWithImplicitThis(invocation);
677                     else if (invocation.arguments().contains(expression))
678                         replaceExpressionWithExplicitThis(expression);
679                     else
680                         Assert.isTrue(false, "expression should be an expression for which, syntactically, \"this\" could by substituted, so not the name in a method invocation."); //$NON-NLS-1$
681
} else if (parent instanceof FieldAccess) {
682                     FieldAccess fieldAccess= (FieldAccess) parent;
683                     if (fieldAccess.getExpression() instanceof ThisExpression) {
684                         Assert.isTrue(expression.equals(fieldAccess.getName()), "expression should syntactically be substitutable by \"this\""); //$NON-NLS-1$
685
replaceExpressionWithSelfReference(fieldAccess); //recursion
686
} else {
687                         Assert.isTrue(expression.equals(fieldAccess.getExpression()), "expression should be an expression for which, syntactically, \"this\" could by substituted, so not the field name in a field access."); //$NON-NLS-1$
688
replaceReceiverWithImplicitThis(fieldAccess);
689                     }
690                 } else if (parent instanceof QualifiedName) {
691                     QualifiedName qualifiedName= (QualifiedName) parent;
692                     Assert.isTrue(isQualifiedNameUsedAsFieldAccessOnObject(qualifiedName, expression), "expression should be an expression for which, syntactically, \"this\" could by substituted."); //$NON-NLS-1$
693
replaceReceiverWithImplicitThis(qualifiedName);
694                 } else
695                     replaceExpressionWithExplicitThis(expression);
696             }
697             
698             private void replaceReceiverWithImplicitThis(MethodInvocation invocation) {
699                 fRewrite.remove(invocation.getExpression(), null);
700             }
701     
702             private void replaceReceiverWithImplicitThis(FieldAccess fieldAccess) {
703                 fRewrite.replace(fieldAccess, fRewrite.createCopyTarget(fieldAccess.getName()), null);
704             }
705             
706             /**
707              * @param fieldAccess A QualifiedName representing a field access
708              */

709             private void replaceReceiverWithImplicitThis(QualifiedName fieldAccess) {
710                 Assert.isTrue(isFieldAccess(fieldAccess));
711                 fRewrite.replace(fieldAccess, fRewrite.createCopyTarget(fieldAccess.getName()), null);
712             }
713     
714             private void replaceExpressionWithExplicitThis(Expression expression) {
715                 fRewrite.replace(expression, expression.getAST().newThisExpression(), null);
716             }
717     
718             private static boolean isQualifiedNameUsedAsFieldAccessOnObject(QualifiedName fieldAccess, Expression object) {
719                 return object.equals(fieldAccess.getQualifier()) && isFieldAccess(fieldAccess);
720             }
721             
722             private static boolean isFieldAccess(QualifiedName qName) {
723                 IBinding binding= qName.resolveBinding();
724                 // TODO: null bindings
725
Assert.isNotNull(binding);
726                 return binding instanceof IVariableBinding && ((IVariableBinding) binding).isField();
727             }
728             
729             public void classQualifyNonInstanceMemberReferences() {
730                 Name[] references= fMethod.findOutermostNonRightHandDotOperandNamesInBody();
731                 for(int i= 0; i < references.length; i++) {
732                     SimpleName leftMost= getLeftmost(references[i]);
733                     if(isNonInstanceMemberReference(leftMost))
734                         classQualify(leftMost);
735                 }
736             }
737     
738             private boolean isNonInstanceMemberReference(SimpleName name) {
739                 if (name.getParent() instanceof ClassInstanceCreation)
740                     return false;
741                 
742                 IBinding binding= name.resolveBinding();
743                 if(binding instanceof ITypeBinding)
744                     return !((ITypeBinding) binding).isLocal();
745                 if(binding instanceof IMethodBinding)
746                     return Modifier.isStatic(((IMethodBinding) binding).getModifiers());
747                 if(binding instanceof IVariableBinding)
748                     return Modifier.isStatic(((IVariableBinding) binding).getModifiers());
749                 return false;
750             }
751             
752             private void classQualify(SimpleName name) {
753                 IBinding nameBinding= name.resolveBinding();
754                 ITypeBinding declaring= getDeclaringClassIfMember(nameBinding);
755                 if(declaring == null)
756                     return;
757     
758                 fRewrite.replace(
759                     name,
760                     name.getAST().newQualifiedName(
761                         getClassNameQualifiedToTopLevel(declaring, name.getAST()),
762                         (SimpleName) fRewrite.createCopyTarget(name)), null);
763                         
764                 fTypeReferences.addOneReference(getTopLevel(declaring));
765                 if(nameBinding instanceof ITypeBinding)
766                     fTypeReferences.removeOneReference((ITypeBinding) nameBinding);
767             }
768             
769             private static ITypeBinding getDeclaringClassIfMember(IBinding binding) {
770                 if(binding instanceof IMethodBinding)
771                     return ((IMethodBinding) binding).getDeclaringClass();
772     
773                 if(binding instanceof IVariableBinding)
774                     return ((IVariableBinding) binding).getDeclaringClass();
775     
776                 if(binding instanceof ITypeBinding)
777                     return ((ITypeBinding) binding).getDeclaringClass();
778     
779                 return null;
780             }
781             
782             private static Name getClassNameQualifiedToTopLevel(ITypeBinding clazz, AST ast) {
783                 Assert.isTrue(!clazz.isAnonymous());
784                 
785                 SimpleName clazzName= ast.newSimpleName(clazz.getName());
786                 if(isTopLevel(clazz))
787                     return clazzName;
788                 
789                 return ast.newQualifiedName(getClassNameQualifiedToTopLevel(clazz.getDeclaringClass(), ast), clazzName);
790             }
791             
792             private static ITypeBinding getTopLevel(ITypeBinding clazz) {
793                 Assert.isTrue(!clazz.isAnonymous());
794                 
795                 ITypeBinding current= clazz;
796                 while(!isTopLevel(current))
797                     current= current.getDeclaringClass();
798                 return current;
799             }
800             
801             /**
802              * Specifically: Does the class have a named declaring class?
803              */

804             private static boolean isTopLevel(ITypeBinding clazz) {
805                 Assert.isNotNull(clazz);
806                 Assert.isTrue(!clazz.isAnonymous());
807                 ITypeBinding declaring= clazz.getDeclaringClass();
808                 return clazz.isLocal() || declaring == null || declaring.isAnonymous();
809             }
810             
811             public void changeMethodName(String JavaDoc newName) {
812                 Assert.isNotNull(newName);
813                 SimpleName originalName= fMethod.getNameNode();
814                 if (! originalName.getIdentifier().equals(newName))
815                     fRewrite.replace(originalName, originalName.getAST().newSimpleName(newName), null);
816             }
817             
818             public void addNewFirstParameter(ITypeBinding parameterType, String JavaDoc parameterName) {
819                 SingleVariableDeclaration newDecl= fMethod.addNewFirstParameter(parameterType, parameterName);
820                 fRewrite.markAsInserted(newDecl);
821                 if(parameterType.isClass() || parameterType.isInterface()) {
822                     Assert.isNotNull(fTypeReferences, "this session has already been destroyed."); //$NON-NLS-1$
823
fTypeReferences.addOneReference(parameterType);
824                 }
825             }
826             
827             public void removeParameter(Parameter parameter) {
828                 fRewrite.remove(fMethod.getParameterDeclaration(parameter), null);
829                 ITypeBinding parameterType= parameter.getType();
830                 if(parameterType.isClass() || parameterType.isInterface()) {
831                     Assert.isNotNull(fTypeReferences, "this session has already been destroyed."); //$NON-NLS-1$
832
fTypeReferences.removeOneReference(parameterType);
833                 }
834             }
835             
836             private Block replaceBody() {
837                 Block originalBody= fMethod.getBody();
838                 Block newBody= originalBody.getAST().newBlock();
839                 fRewrite.replace(originalBody, newBody, null);
840                 return newBody;
841             }
842             
843             public void replaceBodyWithDelegation(Delegation delegation) {
844                 Assert.isTrue(delegation.getDelegatingMethod() == fMethod);
845                 Block newBody= replaceBody();
846                 List JavaDoc statements= newBody.statements();
847                 
848                 MethodInvocation delegatingInvocation= delegation.createDelegatingInvocation();
849                 
850                 Statement delegatingStatement=
851                     fMethod.hasVoidReturnType() ?
852                         createExpressionStatement(delegatingInvocation)
853                         :
854                         createReturnStatement(delegatingInvocation);
855                 statements.add(delegatingStatement);
856             }
857     
858             private Statement createReturnStatement(Expression expression) {
859                 ReturnStatement returnStatement= expression.getAST().newReturnStatement();
860                 returnStatement.setExpression(expression);
861                 return returnStatement;
862             }
863             
864             private Statement createExpressionStatement(Expression expression) {
865                 return expression.getAST().newExpressionStatement(expression);
866             }
867             
868             public TextBufferPortion getEdittedMethodText() throws CoreException {
869                 TextBuffer cuBuffer= fMethod.createDeclaringCUBuffer();
870                 
871                 MultiTextEdit dummy= getEdits(cuBuffer);
872                 
873                 IRegion range= fMethod.createTextRange();
874                 RangeMarker rangeMarker= new RangeMarker(range.getOffset(), range.getLength());
875                 TextEdit[] edits= dummy.removeChildren();
876                 for (int i= 0; i < edits.length; i++)
877                     rangeMarker.addChild(edits[i]);
878                 
879                 MultiTextEdit allEdits= new MultiTextEdit();
880                 allEdits.addChild(rangeMarker);
881                 
882                 TextBufferEditor editor= new TextBufferEditor(cuBuffer);
883                 editor.add(allEdits);
884                 editor.performEdits(null);
885                 
886                 return new TextBufferPortion(cuBuffer, rangeMarker);
887             }
888             
889             public MultiTextEdit getEdits() throws JavaModelException {
890                 return getEdits(fMethod.createDeclaringCUBuffer());
891             }
892             
893             private MultiTextEdit getEdits(TextBuffer buffer) {
894                 MultiTextEdit rootEdit= new MultiTextEdit();
895                 fRewrite.rewriteNode(buffer, rootEdit);
896                 return rootEdit;
897             }
898             
899             public Collection JavaDoc getAllTypesUsedWithoutQualificationInEdittedMethod() {
900                 Assert.isNotNull(fTypeReferences, "this session has already been destroyed."); //$NON-NLS-1$
901
return fTypeReferences.getTypesReferencedWithoutQualification();
902             }
903             
904             public void clear() {
905                 fRewrite.removeModifications();
906                 fTypeReferences= fMethod.getTypeReferences();
907             }
908             
909             public void destroy() {
910                 fRewrite.removeModifications();
911                 fTypeReferences= null;
912             }
913         }
914         
915         private static class TypeReferences extends HierarchicalASTVisitor {
916             private HashMap JavaDoc fTypeKeysToUsageCounts= new HashMap JavaDoc();
917             private HashMap JavaDoc fTypeKeysToATypeBinding= new HashMap JavaDoc();
918             
919             public Collection JavaDoc getTypesReferencedWithoutQualification() {
920                 return fTypeKeysToATypeBinding.values();
921             }
922             
923             public int getNumberOfUnqualifiedReferencesTo(ITypeBinding classOrInterface) {
924                 Assert.isTrue(classOrInterface.isClass() || classOrInterface.isInterface());
925                 
926                 Integer JavaDoc references= getValueFor(classOrInterface);
927                 if(references == null)
928                     return 0;
929                 return references.intValue();
930             }
931             
932             public void addAllReferences(ASTNode tree) {
933                 tree.accept(this);
934             }
935             
936             public void addOneReference(ITypeBinding classOrInterface) {
937                 Assert.isTrue(classOrInterface.isClass() || classOrInterface.isInterface());
938                 registerReference(classOrInterface);
939             }
940             
941             public void removeOneReference(ITypeBinding classOrInterface) {
942                 Assert.isTrue(classOrInterface.isClass() || classOrInterface.isInterface());
943                 
944                 Integer JavaDoc value= getValueFor(classOrInterface);
945                 Assert.isTrue(value != null, "invalid argument"); //$NON-NLS-1$
946

947                 int currentReferences= value.intValue();
948                 Assert.isTrue(currentReferences > 0);
949                 
950                 if(currentReferences == 1)
951                     unmap(classOrInterface);
952                 else
953                     map(
954                         classOrInterface,
955                         new Integer JavaDoc(currentReferences - 1)
956                     );
957             }
958             
959             private void registerReference(ITypeBinding type) {
960                 Integer JavaDoc referencesSoFar= (Integer JavaDoc) fTypeKeysToUsageCounts.get(type.getKey());
961                 map(
962                     type,
963                     referencesSoFar == null ?
964                         new Integer JavaDoc(1)
965                         :
966                         new Integer JavaDoc(referencesSoFar.intValue() + 1)
967                 );
968             }
969             
970             private void map(ITypeBinding binding, Integer JavaDoc value) {
971                 fTypeKeysToUsageCounts.put(binding.getKey(), value);
972                 fTypeKeysToATypeBinding.put(binding.getKey(), binding);
973             }
974             
975             private void unmap(ITypeBinding binding) {
976                 fTypeKeysToUsageCounts.remove(binding.getKey());
977                 fTypeKeysToATypeBinding.remove(binding.getKey());
978             }
979             
980             private Integer JavaDoc getValueFor(ITypeBinding binding) {
981                 return (Integer JavaDoc) fTypeKeysToUsageCounts.get(binding.getKey());
982             }
983     
984             public boolean visit(Name name) {
985                 SimpleName leftmost= getLeftmost(name);
986     
987                 IBinding binding= leftmost.resolveBinding();
988                 if(binding instanceof ITypeBinding)
989                     registerReference((ITypeBinding) binding);
990     
991                 return false;
992             }
993         }
994         
995         private final ICompilationUnit fDeclaringCU;
996         private final MethodDeclaration fMethodNode;
997         private final ITypeBinding fDeclaringClass;
998         private final CodeGenerationSettings fCodeGenSettings;
999         
1000        //cache:
1001
private NewReceiver[] fPossibleNewReceivers;
1002        
1003        static Method create(MethodDeclaration declaration, ICompilationUnit declaringCU, CodeGenerationSettings codeGenSettings) {
1004            ITypeBinding declaringClass= getDeclaringClassBinding(declaration);
1005            if (declaringClass == null) return null;
1006            return new Method(declaration, declaringCU, codeGenSettings, declaringClass);
1007        }
1008        
1009        private Method(MethodDeclaration declaration, ICompilationUnit declaringCU, CodeGenerationSettings codeGenSettings, ITypeBinding declaringClass) {
1010            Assert.isNotNull(declaringCU);
1011            Assert.isTrue(declaringCU.exists());
1012            Assert.isNotNull(declaration);
1013            Assert.isNotNull(codeGenSettings);
1014            Assert.isNotNull(declaringClass);
1015    
1016            fDeclaringCU= declaringCU;
1017            fMethodNode= declaration;
1018            
1019            fDeclaringClass= declaringClass;
1020            fCodeGenSettings= codeGenSettings;
1021        }
1022        
1023        public Expression createFieldReference(IVariableBinding field) {
1024            Assert.isTrue(field.isField());
1025            //TODO: Assert.isTrue(isAncestor(field.getDeclaringClass(), getDeclaringClass()))
1026
//TODO: Assert field not shadowed by field
1027

1028            if(parameterShadows(field))
1029                return createThisFieldAccess(field);
1030    
1031            return createFieldName(field);
1032        }
1033    
1034        private boolean parameterShadows(IVariableBinding field) {
1035            Parameter[] params= getParameters();
1036            for(int i= 0; i < params.length; i++)
1037                if(params[i].getName().equals(field.getName()))
1038                    return true;
1039            return false;
1040        }
1041    
1042        private Expression createThisFieldAccess(IVariableBinding field) {
1043            FieldAccess access= fMethodNode.getAST().newFieldAccess();
1044            access.setExpression(fMethodNode.getAST().newThisExpression());
1045            access.setName(createFieldName(field));
1046            return access;
1047        }
1048        
1049        private SimpleName createFieldName(IVariableBinding field) {
1050            return fMethodNode.getAST().newSimpleName(field.getName());
1051        }
1052        
1053        private Block getBody() {
1054            Block body= fMethodNode.getBody();
1055            Assert.isNotNull(body);
1056            return body;
1057        }
1058        
1059        MethodDeclaration getMethodDeclaration(){
1060            return fMethodNode;
1061        }
1062    
1063        public SingleVariableDeclaration addNewFirstParameter(ITypeBinding parameterType, String JavaDoc parameterName) {
1064            Assert.isNotNull(parameterType);
1065            Assert.isNotNull(parameterName);
1066            Assert.isTrue(parameterType.isClass() || parameterType.isInterface());
1067            
1068            SingleVariableDeclaration newDecl= fMethodNode.getAST().newSingleVariableDeclaration();
1069            newDecl.setType(fMethodNode.getAST().newSimpleType(fMethodNode.getAST().newSimpleName(parameterType.getName())));
1070            newDecl.setName(fMethodNode.getAST().newSimpleName(parameterName));
1071            
1072            fMethodNode.parameters().add(0, newDecl);
1073            return newDecl;
1074        }
1075        
1076        public Delegation getPotentialDelegationTo(NewReceiver newReceiver) {
1077            Assert.isNotNull(newReceiver);
1078            Assert.isTrue(Arrays.asList(getPossibleNewReceivers()).contains(newReceiver));
1079            return new Delegation(this, newReceiver);
1080        }
1081        
1082        private SimpleName getNameNode() {
1083            return fMethodNode.getName();
1084        }
1085    
1086        /**
1087         * <code>variable</code> must be a binding from the same AST that this
1088         * Method is based on.
1089         */

1090        Name[] getVariableReferences(final IVariableBinding variable) {
1091            Assert.isNotNull(variable);
1092            
1093            final List JavaDoc result= new ArrayList JavaDoc();
1094            fMethodNode.accept(
1095                new HierarchicalASTVisitor() {
1096                    public boolean visit(Name name) {
1097                        Assert.isNotNull(name);
1098                        IBinding binding= name.resolveBinding();
1099                        // TODO: assess effect/possibility of null binding
1100
if(binding == null)
1101                            return true;
1102                        if(!(binding instanceof IVariableBinding))
1103                            return true;
1104                            
1105                        if( areSameVariable(variable, (IVariableBinding) binding)
1106                           && !isDeclaredNamePartOfDeclaration(name)
1107                        ) {
1108                            result.add(name);
1109                            return false;
1110                        }
1111                        
1112                        return true;
1113                    }
1114                    
1115                    private boolean isDeclaredNamePartOfDeclaration(Name name) {
1116                        ASTNode parent= name.getParent();
1117                        if(!(parent instanceof VariableDeclaration))
1118                            return false;
1119                        if(parent instanceof VariableDeclarationFragment) {
1120                            VariableDeclarationFragment fragment= (VariableDeclarationFragment) parent;
1121                            return name.equals(fragment.getName());
1122                        } else if(parent instanceof SingleVariableDeclaration) {
1123                            SingleVariableDeclaration decl= (SingleVariableDeclaration) parent;
1124                            return name.equals(decl.getName());
1125                        }
1126                        Assert.isTrue(false); return false;
1127                    }
1128                    
1129                    private boolean areSameVariable(IVariableBinding one, IVariableBinding other) {
1130                        /* it would be nice if there was a general way
1131                         * to compare bindings from different parses,
1132                         * but there isn't. getKey() is null for local
1133                         * variables.
1134                         */

1135                        return one.equals(other);
1136                    }
1137                }
1138            );
1139            return (Name[]) result.toArray(new Name[result.size()]);
1140        }
1141    
1142        private static ITypeBinding getDeclaringClassBinding(MethodDeclaration decl) {
1143            Assert.isNotNull(decl);
1144    
1145            IMethodBinding binding= decl.resolveBinding();
1146            if (binding == null)
1147                return null;
1148            return binding.getDeclaringClass();
1149        }
1150    
1151        public String JavaDoc getName() {
1152            return fMethodNode.getName().getIdentifier();
1153        }
1154    
1155        private ITypeBinding[] getParameterTypes() {
1156            Parameter[] params= getParameters();
1157            
1158            ITypeBinding[] types= new ITypeBinding[params.length];
1159            for(int i= 0; i < params.length; i++)
1160                types[i]= params[i].getType();
1161            return types;
1162        }
1163    
1164        public Parameter[] getParameters() {
1165            List JavaDoc parameters= new ArrayList JavaDoc();
1166            for(Iterator JavaDoc it= fMethodNode.parameters().iterator(); it.hasNext();) {
1167                IVariableBinding paramBinding= ((SingleVariableDeclaration) it.next()).resolveBinding();
1168                if (paramBinding == null)
1169                    return new Parameter[0]; //null bindings are not good
1170

1171                parameters.add(new Parameter(this, paramBinding));
1172            }
1173            return (Parameter[]) parameters.toArray(new Parameter[parameters.size()]);
1174        }
1175    
1176        public ITypeBinding getDeclaringClass() {
1177            return fDeclaringClass;
1178        }
1179        
1180        public ICompilationUnit getDeclaringCU() {
1181            return fDeclaringCU;
1182        }
1183    
1184        private IJavaProject getProject() {
1185            return getDeclaringCU().getJavaProject();
1186        }
1187        
1188        public RefactoringStatus checkCanBeMoved() {
1189            if(isStatic())
1190                return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.getString("InstanceMethodMover.no_static_methods"), null, Corext.getPluginId(), RefactoringStatusCodes.CANNOT_MOVE_STATIC, null); //$NON-NLS-1$
1191
if(isAbstract())
1192                return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.getString("InstanceMethodMover.single_implementation"), null, Corext.getPluginId(), RefactoringStatusCodes.SELECT_METHOD_IMPLEMENTATION, null); //$NON-NLS-1$
1193
if(isNative())
1194                return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.getString("InstanceMethodMover.no_native_methods"), null, Corext.getPluginId(), RefactoringStatusCodes.CANNOT_MOVE_NATIVE, null); //$NON-NLS-1$
1195
if(isSynchronized())
1196                return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.getString("InstanceMethodMover.no_synchronized_methods"), null, Corext.getPluginId(), RefactoringStatusCodes.CANNOT_MOVE_SYNCHRONIZED, null); //$NON-NLS-1$
1197
if(isConstructor())
1198                return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.getString("InstanceMethodMover.no_constructors"), null, Corext.getPluginId(), RefactoringStatusCodes.CANNOT_MOVE_CONSTRUCTOR, null); //$NON-NLS-1$
1199
if(hasSuperReferences())
1200                return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.getString("InstanceMethodMover.uses_super"), null, Corext.getPluginId(), RefactoringStatusCodes.SUPER_REFERENCES_NOT_ALLOWED, null); //$NON-NLS-1$
1201
if(refersToEnclosingInstances())
1202                return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.getString("InstanceMethodMover.refers_enclosing_instances"), null, Corext.getPluginId(), RefactoringStatusCodes.ENCLOSING_INSTANCE_REFERENCES_NOT_ALLOWED, null); //$NON-NLS-1$
1203
if(mayBeDirectlyRecursive())
1204                return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.getString("InstanceMethodMover.potentially_recursive"), null, Corext.getPluginId(), RefactoringStatusCodes.CANNOT_MOVE_RECURSIVE, null); //$NON-NLS-1$
1205

1206            if (getPossibleNewReceivers().length == 0)
1207                return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.getString("InstanceMethodMover.cannot_be_moved"), null, Corext.getPluginId(), RefactoringStatusCodes.NO_NEW_RECEIVERS, null); //$NON-NLS-1$
1208
return new RefactoringStatus();
1209        }
1210    
1211        private boolean hasSuperReferences() {
1212            class SuperReferenceChecker extends ASTVisitor {
1213                private boolean fSuperReferencesFound= false;
1214    
1215                public boolean superReferencesFound() {
1216                    return fSuperReferencesFound;
1217                }
1218    
1219                public boolean visit(AnonymousClassDeclaration node) {
1220                    return false; //Fix for bug 35452
1221
}
1222
1223                public boolean visit(TypeDeclaration node) {
1224                    return false; //Fix for bug 35452
1225
}
1226
1227                public boolean visit(SuperFieldAccess node) {
1228                    fSuperReferencesFound= true;
1229                    return false;
1230                }
1231    
1232                public boolean visit(SuperMethodInvocation node) {
1233                    fSuperReferencesFound= true;
1234                    return false;
1235                }
1236            }
1237            
1238            SuperReferenceChecker checker= new SuperReferenceChecker();
1239            fMethodNode.accept(checker);
1240            return checker.superReferencesFound();
1241        }
1242    
1243        private boolean isStatic() {
1244            return Modifier.isStatic(getModifiers());
1245        }
1246        
1247        private boolean isNative() {
1248            return Modifier.isNative(getModifiers());
1249        }
1250        
1251        private boolean isConstructor() {
1252            IMethodBinding binding= fMethodNode.resolveBinding();
1253            //TODO: null bindings
1254
Assert.isNotNull(binding);
1255            return binding.isConstructor();
1256        }
1257        
1258        private boolean isSynchronized() {
1259            return Modifier.isSynchronized(getModifiers());
1260        }
1261        
1262        private boolean isAbstract() {
1263            return getDeclaringClass().isInterface() || Modifier.isAbstract(getModifiers());
1264        }
1265        
1266        private boolean refersToEnclosingInstances() {
1267            class EnclosingInstanceReferenceChecker extends ASTVisitor {
1268                private boolean fEnclosingInstanceReferencesFound= false;
1269    
1270                public boolean enclosingInstanceReferencesFound() {
1271                    return fEnclosingInstanceReferencesFound;
1272                }
1273    
1274                public boolean visit(ThisExpression node) {
1275                    if(node.getQualifier() != null)
1276                        fEnclosingInstanceReferencesFound= true;
1277                    return false;
1278                }
1279            }
1280            
1281            EnclosingInstanceReferenceChecker checker= new EnclosingInstanceReferenceChecker();
1282            fMethodNode.accept(checker);
1283            return checker.enclosingInstanceReferencesFound();
1284        }
1285        
1286        private boolean mayBeDirectlyRecursive() {
1287            Assert.isTrue(!hasSuperReferences());
1288            
1289            class RecursionChecker extends ASTVisitor {
1290                private boolean fMethodMayBeRecursive= false;
1291                
1292                public boolean mayBeRecursive() {
1293                    fMethodNode.accept(this);
1294                    return fMethodMayBeRecursive;
1295                }
1296                
1297                public boolean visit(MethodInvocation invocation) {
1298                    IMethodBinding binding= invocation.resolveMethodBinding();
1299                    if (binding == null){
1300                        fMethodMayBeRecursive= true;
1301                        return false;
1302                    }
1303                        
1304                    if(!isSelfSend(invocation))
1305                        return true;
1306                    
1307                    if(hasSameSignature(binding)){
1308                        fMethodMayBeRecursive= true;
1309                        return false;
1310                    }
1311                    
1312                    return true;
1313                }
1314                
1315                private boolean hasSameSignature(IMethodBinding other) {
1316                    if(!getName().equals(other.getName()))
1317                        return false;
1318                    return hasSameParameterTypes(other);
1319                }
1320                
1321                private boolean hasSameParameterTypes(IMethodBinding other) {
1322                    ITypeBinding[] mine= getParameterTypes();
1323                    ITypeBinding[] others= other.getParameterTypes();
1324                    if(mine.length != others.length)
1325                        return false;
1326                        
1327                    for(int i= 0; i < mine.length; i++)
1328                        if(!mine[i].getKey().equals(others[i].getKey()))
1329                            return false;
1330                            
1331                    return true;
1332                }
1333                
1334                private boolean isSelfSend(MethodInvocation invocation) {
1335                    if(isStatic(invocation))
1336                        return false;
1337    
1338                    Expression receiver= invocation.getExpression();
1339                    return receiver == null
1340                            || receiver instanceof ThisExpression;
1341                }
1342                
1343                private boolean isStatic(MethodInvocation invocation) {
1344                    return JdtFlags.isStatic(invocation.resolveMethodBinding());
1345                }
1346            }
1347            
1348            RecursionChecker checker= new RecursionChecker();
1349            return checker.mayBeRecursive();
1350        }
1351        
1352        private int getModifiers() {
1353            return getBinding().getModifiers();
1354        }
1355        
1356        public NewReceiver[] getPossibleNewReceivers() {
1357            if(fPossibleNewReceivers == null)
1358                fPossibleNewReceivers= findPossibleNewReceivers();
1359            return fPossibleNewReceivers;
1360        }
1361    
1362        private NewReceiver[] findPossibleNewReceivers() {
1363            List JavaDoc newReceivers= new ArrayList JavaDoc();
1364        
1365            addPossibleParameterNewReceivers(newReceivers);
1366            addPossibleFieldNewReceivers(newReceivers);
1367        
1368            return (NewReceiver[]) newReceivers.toArray(new NewReceiver[newReceivers.size()]);
1369        }
1370    
1371        private static boolean canAddAsPossibleNewReceiver(ITypeBinding type){
1372            return type.isClass() && type.isFromSource();
1373        }
1374        
1375        private void addPossibleParameterNewReceivers(List JavaDoc target) {
1376            Assert.isNotNull(target);
1377    
1378            Parameter[] parameters= getParameters();
1379            for(int i= 0; i < parameters.length; i++) {
1380                if(canAddAsPossibleNewReceiver(parameters[i].getType()))
1381                    target.add(new ParameterNewReceiver(parameters[i], getProject(), fCodeGenSettings));
1382            }
1383        }
1384    
1385        private void addPossibleFieldNewReceivers(List JavaDoc target) {
1386            Assert.isNotNull(target);
1387            IVariableBinding[] fields= findFieldsOfSelfReadButNotWritten();
1388            for(int i= 0; i < fields.length; i++) {
1389                if (canAddAsPossibleNewReceiver(fields[i].getType()))
1390                    target.add(new FieldNewReceiver(fields[i], getProject(), fCodeGenSettings));
1391            }
1392        }
1393    
1394        private IVariableBinding[] findFieldsOfSelfReadButNotWritten() {
1395            Collection JavaDoc result= keepFieldsNotWritten(findReferencedFieldsOfSelf());
1396            return (IVariableBinding[]) result.toArray(new IVariableBinding[result.size()]);
1397        }
1398    
1399        /**
1400         * @return Set of keys obtained by calling <code>a.getKey()</code> on a
1401         * VariableBinding instance <code>a</code>
1402         */

1403        private Set JavaDoc getKeysOfAllWrittenFields() {
1404            final HashSet JavaDoc writtenFieldKeys= new HashSet JavaDoc();
1405            
1406            fMethodNode.accept(
1407                new ASTVisitor() {
1408                    public boolean visit(Assignment assignment) {
1409                        reportExpressionModified(assignment.getLeftHandSide());
1410                        return true;
1411                    }
1412    
1413                    public boolean visit(PostfixExpression node) {
1414                        reportExpressionModified(node.getOperand());
1415                        return true;
1416                    }
1417    
1418                    public boolean visit(PrefixExpression node) {
1419                        reportExpressionModified(node.getOperand());
1420                        return false;
1421                    }
1422    
1423                    private void reportExpressionModified(Expression exp) {
1424                        IVariableBinding field
1425                            = getFieldBindingIfField(exp);
1426                        if(field != null)
1427                            reportFieldWritten(field);
1428                    }
1429    
1430                    private void reportFieldWritten(IVariableBinding field) {
1431                        Assert.isTrue(field.isField());
1432                        writtenFieldKeys.add(field.getKey());
1433                    }
1434                    
1435                    private IVariableBinding getFieldBindingIfField(Expression exp) {
1436                        if(exp instanceof FieldAccess)
1437                            return (IVariableBinding) ((FieldAccess) exp).getName().resolveBinding();
1438                        if(exp instanceof Name) {
1439                            IBinding binding= ((Name) exp).resolveBinding();
1440                            if(binding instanceof IVariableBinding) {
1441                                IVariableBinding variable= (IVariableBinding) binding;
1442                                if(variable.isField())
1443                                    return variable;
1444                            }
1445                        }
1446                        return null;
1447                    }
1448                }
1449            );
1450            return writtenFieldKeys;
1451        }
1452    
1453        private Collection JavaDoc keepFieldsNotWritten(Collection JavaDoc fields) {
1454            Set JavaDoc writtenFieldKeys= getKeysOfAllWrittenFields();
1455            
1456            Collection JavaDoc result= new ArrayList JavaDoc();
1457            for(Iterator JavaDoc it= fields.iterator(); it.hasNext();) {
1458                IVariableBinding field= (IVariableBinding) it.next();
1459                Assert.isTrue(field.isField());
1460                if(!writtenFieldKeys.contains(field.getKey()))
1461                    result.add(field);
1462            }
1463            return result;
1464        }
1465                
1466        private Collection JavaDoc findReferencedFieldsOfSelf() {
1467            final Set JavaDoc fieldKeys= new HashSet JavaDoc();
1468            final List JavaDoc result= new ArrayList JavaDoc();
1469            
1470            fMethodNode.accept(
1471                new ASTVisitor() {
1472                    public boolean visit(FieldAccess node) {
1473                        if(node.getExpression() instanceof ThisExpression) {
1474                            IVariableBinding field= (IVariableBinding) node.getName().resolveBinding();
1475                            if(field != null)
1476                                fieldFound(field);
1477                        }
1478                        return true;
1479                    }
1480    
1481                    public boolean visit(SimpleName name) {
1482                        IBinding binding= name.resolveBinding();
1483                        if(binding != null)
1484                            if(isImplicitThisFieldAccess(name))
1485                                fieldFound((IVariableBinding) binding);
1486                        return false;
1487                    }
1488                    
1489                    private void fieldFound(IVariableBinding field) {
1490                        Assert.isTrue(field.isField());
1491                        if(!fieldKeys.contains(field.getKey())) {
1492                            fieldKeys.add(field.getKey());
1493                            result.add(field);
1494                        }
1495                    }
1496                }
1497            );
1498            return result;
1499        }
1500        
1501        private TextBuffer createDeclaringCUBuffer() throws JavaModelException {
1502            return TextBuffer.create(getDeclaringCU().getBuffer().getContents());
1503        }
1504        
1505        private IRegion createTextRange() {
1506            return new Region(fMethodNode.getStartPosition(), fMethodNode.getLength());
1507        }
1508        
1509        private OldASTRewrite createRewrite() {
1510            return new OldASTRewrite(fMethodNode);
1511        }
1512        
1513        public MethodEditSession createEditSession() throws JavaModelException {
1514            return new MethodEditSession(this);
1515        }
1516        
1517        private ThisExpression[] getExplicitThisReferences() {
1518            final List JavaDoc result= new ArrayList JavaDoc();
1519            fMethodNode.accept(
1520                new ASTVisitor() {
1521                    public boolean visit(ThisExpression node) {
1522                        result.add(node);
1523                        return false;
1524                    }
1525                }
1526            );
1527            return (ThisExpression[]) result.toArray(new ThisExpression[result.size()]);
1528        }
1529        
1530        private MethodInvocation[] getImplicitThisMethodInvocations() {
1531            final List JavaDoc result= new ArrayList JavaDoc();
1532            fMethodNode.accept(
1533                new ASTVisitor() {
1534                    public boolean visit(MethodInvocation invocation) {
1535                        if (invocation.resolveMethodBinding() == null)
1536                            return true;
1537                        if(isImplicitThisMethodInvocation(invocation))
1538                            result.add(invocation);
1539                        return true;
1540                    }
1541                    
1542                    private boolean isImplicitThisMethodInvocation(MethodInvocation invocation) {
1543                        return ! isInvokedMethodStatic(invocation)
1544                               && invocation.getExpression() == null;
1545                    }
1546                    
1547                    private boolean isInvokedMethodStatic(MethodInvocation invocation) {
1548                        return JdtFlags.isStatic(invocation.resolveMethodBinding());
1549                    }
1550                }
1551            );
1552            return (MethodInvocation[]) result.toArray(new MethodInvocation[result.size()]);
1553        }
1554    
1555        private SimpleName[] getImplicitThisFieldAccesses() {
1556            final List JavaDoc result= new ArrayList JavaDoc();
1557            fMethodNode.accept(
1558                new ASTVisitor() {
1559                    public boolean visit(SimpleName name) {
1560                        if(isImplicitThisFieldAccess(name))
1561                            result.add(name);
1562                        return false;
1563                    }
1564                }
1565            );
1566            return (SimpleName[]) result.toArray(new SimpleName[result.size()]);
1567        }
1568    
1569        public boolean hasSelfReferences(NewReceiver newReceiver) {
1570            return getExplicitThisReferences().length != 0
1571                   || getImplicitThisMethodInvocations().length != 0
1572                   || newReceiver.hasFieldsAccessesOtherThanToMe(getImplicitThisFieldAccesses());
1573        }
1574        
1575        private MethodDeclaration getDeclaration() {
1576            return fMethodNode;
1577        }
1578        
1579        private IMethodBinding getBinding() {
1580            IMethodBinding binding= fMethodNode.resolveBinding();
1581            // TODO: null bindings
1582
Assert.isNotNull(binding);
1583            return binding;
1584        }
1585        
1586        public ITypeBinding getReturnType() {
1587            return getBinding().getReturnType();
1588        }
1589        
1590        public boolean hasVoidReturnType() {
1591            Type returnType= fMethodNode.getReturnType();
1592            if(!(returnType instanceof PrimitiveType))
1593                return false;
1594            return PrimitiveType.VOID.equals(((PrimitiveType) returnType).getPrimitiveTypeCode());
1595        }
1596    
1597        public SimpleName createParameterReference(Parameter parameter) {
1598            Assert.isTrue(parameter.getMethod() == this);
1599            return fMethodNode.getAST().newSimpleName(parameter.getName());
1600        }
1601        
1602        private AST getAST() {
1603            return fMethodNode.getAST();
1604        }
1605    
1606    
1607        private SingleVariableDeclaration getParameterDeclaration(Parameter parameter) {
1608            for(Iterator JavaDoc decls= fMethodNode.parameters().iterator(); decls.hasNext();) {
1609                SingleVariableDeclaration parameterDeclaration= (SingleVariableDeclaration) decls.next();
1610                if(parameter.getBinding().equals(parameterDeclaration.resolveBinding()))
1611                    return parameterDeclaration;
1612            }
1613            Assert.isTrue(false, "Parameter must be a parameter to this method."); //$NON-NLS-1$
1614
return null;
1615        }
1616    
1617        private TypeReferences getTypeReferences() {
1618            TypeReferences result= new TypeReferences();
1619            result.addAllReferences(fMethodNode);
1620            return result;
1621        }
1622        
1623        private Name[] findOutermostNonRightHandDotOperandNamesInBody() {
1624            final List JavaDoc result= new ArrayList JavaDoc();
1625            fMethodNode.getBody().accept(
1626                new HierarchicalASTVisitor() {
1627                    public boolean visit(Name name) {
1628                        if(!isRightDotOperand(name))
1629                            result.add(name);
1630                        return false;
1631                    }
1632                }
1633            );
1634            return (Name[]) result.toArray(new Name[result.size()]);
1635        }
1636        
1637        public boolean equals(Object JavaDoc o) {
1638            if(o == null)
1639                return false;
1640            if(!getClass().equals(o.getClass()))
1641                return false;
1642            return getDeclaration().equals(((Method) o).getDeclaration());
1643        }
1644        
1645        // general static helpers:
1646

1647        private static SimpleName getLeftmost(Name name) {
1648            if(name instanceof SimpleName)
1649                return (SimpleName) name;
1650    
1651            return getLeftmost(((QualifiedName) name).getQualifier());
1652        }
1653        
1654        private static boolean isImplicitThisFieldAccess(SimpleName name) {
1655            return isInstanceFieldAccess(name) && !isRightDotOperand(name);
1656        }
1657    
1658        /**
1659         * Is the name preceded by a dot?
1660         */

1661        private static boolean isRightDotOperand(Name name) {
1662            ASTNode parent = name.getParent();
1663            if(parent instanceof QualifiedName && ((QualifiedName)parent).getName().equals(name))
1664                return true;
1665                
1666            if(parent instanceof FieldAccess && ((FieldAccess)parent).getName().equals(name))
1667                return true;
1668            
1669            if(parent instanceof SuperFieldAccess)
1670                return true;
1671            
1672            if(parent instanceof MethodInvocation) {
1673                MethodInvocation invocation= (MethodInvocation) parent;
1674                return invocation.getExpression() != null && invocation.getName().equals(name);
1675            }
1676            
1677            return false;
1678        }
1679    
1680        private static boolean isInstanceFieldAccess(SimpleName name) {
1681            IBinding binding= name.resolveBinding();
1682            // TODO: null bindings assumed OK
1683

1684            if(!(binding instanceof IVariableBinding))
1685                return false;
1686    
1687            IVariableBinding variableBinding= (IVariableBinding) binding;
1688            if(!variableBinding.isField())
1689                return false;
1690    
1691            return !Modifier.isStatic(variableBinding.getModifiers());
1692        }
1693    }
1694
1695    private static class Parameter implements IParameter {
1696        private final Method fMethod;
1697        private final IVariableBinding fBinding;
1698
1699        private Parameter(Method method, IVariableBinding binding) {
1700            Assert.isNotNull(method);
1701            Assert.isNotNull(binding);
1702            Assert.isTrue(!binding.isField());
1703
1704            fMethod= method;
1705            fBinding= binding;
1706        }
1707
1708        public String JavaDoc getName() {
1709            return fBinding.getName();
1710        }
1711
1712        public ITypeBinding getType() {
1713            return fBinding.getType();
1714        }
1715
1716        public Method getMethod() {
1717            return fMethod;
1718        }
1719
1720        public boolean isFinal() {
1721            return Modifier.isFinal(fBinding.getModifiers());
1722        }
1723        
1724        public SimpleName createReference() {
1725            return fMethod.createParameterReference(this);
1726        }
1727
1728        public IVariableBinding getBinding() {
1729            return fBinding;
1730        }
1731        
1732        public boolean equals(Object JavaDoc o) {
1733            if(o == null)
1734                return false;
1735            if(!getClass().equals((o.getClass())))
1736                return false;
1737            Parameter otherParam= (Parameter) o;
1738            return getName().equals(otherParam.getName())
1739                   && getMethod().equals(otherParam.getMethod());
1740        }
1741    }
1742    
1743    private static class TextBufferPortion {
1744        private final TextBuffer fBuffer;
1745        private final RangeMarker fMarker;
1746        
1747        TextBufferPortion(TextBuffer buffer, RangeMarker marker) {
1748            Assert.isNotNull(buffer);
1749            Assert.isNotNull(marker);
1750            fBuffer= buffer;
1751            fMarker= marker;
1752        }
1753        
1754        public String JavaDoc getContent() {
1755            return fBuffer.getContent(fMarker.getOffset(), fMarker.getLength());
1756        }
1757        
1758        public String JavaDoc getUnindentedContentIgnoreFirstLine() {
1759            return Strings.changeIndent(
1760                fBuffer.getContent(fMarker.getOffset(), fMarker.getLength()),
1761                fBuffer.getLineIndent(fBuffer.getLineOfOffset(fMarker.getOffset()), CodeFormatterUtil.getTabWidth()),
1762                CodeFormatterUtil.getTabWidth(),
1763                "", //$NON-NLS-1$
1764
fBuffer.getLineDelimiter()
1765            );
1766        }
1767    }
1768    
1769    private final Method fMethodToMove;
1770
1771    private NewReceiver fNewReceiver;
1772    
1773    private String JavaDoc fNewMethodName;
1774    private String JavaDoc fOriginalReceiverParameterName;
1775    
1776    private boolean fInlineDelegator;
1777    private boolean fRemoveDelegator;
1778    
1779    public static InstanceMethodMover create(MethodDeclaration declaration, ICompilationUnit declarationCU, CodeGenerationSettings codeGenSettings) {
1780        Method method= Method.create(declaration, declarationCU, codeGenSettings);
1781        if (method == null) return null;
1782        return new InstanceMethodMover(method);
1783    }
1784
1785    private InstanceMethodMover(Method method) {
1786        Assert.isNotNull(method);
1787        fMethodToMove= method;
1788        
1789        fInlineDelegator= true; //default
1790
fRemoveDelegator= true; //default
1791
fNewMethodName= fMethodToMove.getName(); //default;
1792
fOriginalReceiverParameterName= guessOriginalReceiverParameterName(); //default
1793
}
1794
1795    private String JavaDoc guessOriginalReceiverParameterName() {
1796        ITypeBinding type= fMethodToMove.getDeclaringClass();
1797        String JavaDoc typeName= getQualifiedName(type);
1798        if (typeName.length() == 0)
1799            return ""; //$NON-NLS-1$
1800
String JavaDoc[] candidates= NamingConventions.suggestArgumentNames(fMethodToMove.getProject(),
1801                "", typeName, type.getDimensions(), getExcludedParameterNames()); //$NON-NLS-1$
1802
if (candidates.length > 0)
1803            return candidates[0];
1804        return ""; //$NON-NLS-1$
1805
}
1806
1807    private static String JavaDoc getQualifiedName(ITypeBinding typeBinding) {
1808        if (typeBinding.isAnonymous())
1809            return getQualifiedName(typeBinding.getSuperclass());
1810        if (! typeBinding.isArray())
1811            return typeBinding.getQualifiedName();
1812        else
1813            return typeBinding.getElementType().getQualifiedName();
1814    }
1815
1816    private String JavaDoc[] getExcludedParameterNames() {
1817        ArrayList JavaDoc names= new ArrayList JavaDoc();
1818        MethodDeclaration methodDeclaration= fMethodToMove.getMethodDeclaration();
1819        
1820        List JavaDoc params= methodDeclaration.parameters();
1821        for (int i= 0; i < params.size(); i++) {
1822            names.add(((SingleVariableDeclaration) params.get(i)).getName().getIdentifier());
1823        }
1824        
1825        Block body= methodDeclaration.getBody();
1826        if (body != null) { //protect from abstract methods (not checked up to here)
1827
IBinding[] variableBindings= new ScopeAnalyzer(((CompilationUnit) methodDeclaration.getRoot())).
1828                    getDeclarationsAfter(body.getStartPosition(), ScopeAnalyzer.VARIABLES);
1829            for (int i= 0; i < variableBindings.length; i++) {
1830                names.add(variableBindings[i].getName());
1831            }
1832        }
1833        return (String JavaDoc[]) names.toArray(new String JavaDoc[names.size()]);
1834    }
1835
1836    public INewReceiver[] getPossibleNewReceivers() {
1837        return fMethodToMove.getPossibleNewReceivers();
1838    }
1839
1840    /**
1841     * @param chosen Must be a element of the result
1842     * of a call to getPossibleNewReceivers()
1843     */

1844    public void chooseNewReceiver(INewReceiver chosen) {
1845        Assert.isTrue(Arrays.asList(getPossibleNewReceivers()).contains(chosen));
1846        fNewReceiver= (NewReceiver) chosen;
1847    }
1848    
1849    public String JavaDoc getNewMethodName() {
1850        return fNewMethodName;
1851    }
1852    
1853    public void setNewMethodName(String JavaDoc newMethodName) {
1854        Assert.isNotNull(newMethodName);
1855        fNewMethodName= newMethodName;
1856    }
1857
1858    public String JavaDoc getOriginalReceiverParameterName() {
1859        return fOriginalReceiverParameterName;
1860    }
1861    
1862    public void setOriginalReceiverParameterName(String JavaDoc originalReceiverParameterName) {
1863        Assert.isNotNull(originalReceiverParameterName);
1864        fOriginalReceiverParameterName= originalReceiverParameterName;
1865    }
1866
1867    public void setInlineDelegator(boolean inlineDelegator) {
1868        fInlineDelegator= inlineDelegator;
1869        checkInvariant();
1870    }
1871
1872    public void setRemoveDelegator(boolean removeDelegator) {
1873        fRemoveDelegator= removeDelegator;
1874        checkInvariant();
1875    }
1876    
1877    public boolean getInlineDelegator() {
1878        return fInlineDelegator;
1879    }
1880    
1881    public boolean getRemoveDelegator() {
1882        return fRemoveDelegator;
1883    }
1884
1885    private void checkInvariant() {
1886        if(fRemoveDelegator)
1887            Assert.isTrue(fInlineDelegator);
1888    }
1889    
1890    private static IType getModelClass(ITypeBinding clazz, IJavaProject dependentProject) throws JavaModelException {
1891        Assert.isTrue(clazz.isClass());
1892        IType modelClass= Bindings.findType(clazz, dependentProject);
1893        if(modelClass == null || !modelClass.exists())
1894            return null;
1895            
1896        Assert.isTrue(modelClass.isClass());
1897        return modelClass;
1898    }
1899
1900    public RefactoringStatus checkInitialState() {
1901        return fMethodToMove.checkCanBeMoved();
1902    }
1903
1904    public final RefactoringStatus checkInput(IProgressMonitor pm, Object JavaDoc validationContext) throws JavaModelException {
1905        pm.beginTask("", 1); //$NON-NLS-1$
1906
try{
1907            Assert.isNotNull(fNewReceiver, "New receiver must be chosen before checkInput(..) is called."); //$NON-NLS-1$
1908
return fNewReceiver.checkMoveOfMethodToMe(fMethodToMove, fNewMethodName,
1909                fOriginalReceiverParameterName, fInlineDelegator,
1910                fRemoveDelegator, validationContext);
1911        }finally{
1912            pm.done();
1913        }
1914    }
1915
1916    public Change createChange(IProgressMonitor pm) throws CoreException {
1917        try{
1918            pm.beginTask("", 1); //$NON-NLS-1$
1919
return fNewReceiver.moveMethodToMe(fMethodToMove, fNewMethodName, fOriginalReceiverParameterName, fInlineDelegator, fRemoveDelegator);
1920        }finally{
1921            pm.done();
1922        }
1923    }
1924}
1925
Popular Tags