KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > sef > SelfEncapsulateFieldRefactoring


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  * jens.lukowski@gmx.de - contributed code to convert prefix and postfix
11  * expressions into a combination of setter and getter calls.
12  * Dmitry Stalnov (dstalnov@fusionone.com) - contributed fix for
13  * bug Encapsulate field can fail when two variables in one variable declaration (see
14  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=51540).
15  *******************************************************************************/

16 package org.eclipse.jdt.internal.corext.refactoring.sef;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.HashMap JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Map JavaDoc;
23
24 import org.eclipse.text.edits.MultiTextEdit;
25 import org.eclipse.text.edits.TextEditGroup;
26
27 import org.eclipse.core.runtime.Assert;
28 import org.eclipse.core.runtime.CoreException;
29 import org.eclipse.core.runtime.IProgressMonitor;
30 import org.eclipse.core.runtime.IStatus;
31 import org.eclipse.core.runtime.OperationCanceledException;
32 import org.eclipse.core.runtime.SubProgressMonitor;
33
34 import org.eclipse.core.resources.IFile;
35
36 import org.eclipse.ltk.core.refactoring.Change;
37 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
38 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
39 import org.eclipse.ltk.core.refactoring.TextChange;
40 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
41 import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker;
42
43 import org.eclipse.jdt.core.Flags;
44 import org.eclipse.jdt.core.ICompilationUnit;
45 import org.eclipse.jdt.core.IField;
46 import org.eclipse.jdt.core.IJavaElement;
47 import org.eclipse.jdt.core.IJavaProject;
48 import org.eclipse.jdt.core.ISourceRange;
49 import org.eclipse.jdt.core.IType;
50 import org.eclipse.jdt.core.JavaConventions;
51 import org.eclipse.jdt.core.JavaCore;
52 import org.eclipse.jdt.core.JavaModelException;
53 import org.eclipse.jdt.core.NamingConventions;
54 import org.eclipse.jdt.core.compiler.IProblem;
55 import org.eclipse.jdt.core.dom.AST;
56 import org.eclipse.jdt.core.dom.ASTNode;
57 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
58 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
59 import org.eclipse.jdt.core.dom.Assignment;
60 import org.eclipse.jdt.core.dom.Block;
61 import org.eclipse.jdt.core.dom.BodyDeclaration;
62 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
63 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
64 import org.eclipse.jdt.core.dom.CompilationUnit;
65 import org.eclipse.jdt.core.dom.Expression;
66 import org.eclipse.jdt.core.dom.FieldAccess;
67 import org.eclipse.jdt.core.dom.FieldDeclaration;
68 import org.eclipse.jdt.core.dom.IMethodBinding;
69 import org.eclipse.jdt.core.dom.ITypeBinding;
70 import org.eclipse.jdt.core.dom.IVariableBinding;
71 import org.eclipse.jdt.core.dom.Javadoc;
72 import org.eclipse.jdt.core.dom.Message;
73 import org.eclipse.jdt.core.dom.MethodDeclaration;
74 import org.eclipse.jdt.core.dom.Modifier;
75 import org.eclipse.jdt.core.dom.ReturnStatement;
76 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
77 import org.eclipse.jdt.core.dom.Type;
78 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
79 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
80 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
81 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
82 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
83 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
84 import org.eclipse.jdt.core.search.IJavaSearchConstants;
85 import org.eclipse.jdt.core.search.SearchPattern;
86
87 import org.eclipse.jdt.internal.corext.codemanipulation.GetterSetterUtil;
88 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
89 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
90 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
91 import org.eclipse.jdt.internal.corext.dom.Bindings;
92 import org.eclipse.jdt.internal.corext.dom.ModifierRewrite;
93 import org.eclipse.jdt.internal.corext.dom.NodeFinder;
94 import org.eclipse.jdt.internal.corext.refactoring.Checks;
95 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor;
96 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
97 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
98 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
99 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
100 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine;
101 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
102 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
103 import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring;
104 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
105 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
106 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
107 import org.eclipse.jdt.internal.corext.util.JdtFlags;
108 import org.eclipse.jdt.internal.corext.util.Messages;
109
110 import org.eclipse.jdt.ui.CodeGeneration;
111 import org.eclipse.jdt.ui.JavaElementLabels;
112
113 import org.eclipse.jdt.internal.ui.JavaPlugin;
114 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
115
116 /**
117  * Encapsulates a field into getter and setter calls.
118  */

119 public class SelfEncapsulateFieldRefactoring extends ScriptableRefactoring {
120
121     private static final String JavaDoc ATTRIBUTE_VISIBILITY= "visibility"; //$NON-NLS-1$
122
private static final String JavaDoc ATTRIBUTE_GETTER= "getter"; //$NON-NLS-1$
123
private static final String JavaDoc ATTRIBUTE_SETTER= "setter"; //$NON-NLS-1$
124
private static final String JavaDoc ATTRIBUTE_INSERTION= "insertion"; //$NON-NLS-1$
125
private static final String JavaDoc ATTRIBUTE_COMMENTS= "comments"; //$NON-NLS-1$
126
private static final String JavaDoc ATTRIBUTE_DECLARING= "declaring"; //$NON-NLS-1$
127

128     private IField fField;
129     private TextChangeManager fChangeManager;
130     
131     private CompilationUnit fRoot;
132     private VariableDeclarationFragment fFieldDeclaration;
133     private ASTRewrite fRewriter;
134     private ImportRewrite fImportRewrite;
135
136     private int fVisibility= -1;
137     private String JavaDoc fGetterName;
138     private String JavaDoc fSetterName;
139     private String JavaDoc fArgName;
140     private boolean fSetterMustReturnValue;
141     private int fInsertionIndex; // -1 represents as first method.
142
private boolean fEncapsulateDeclaringClass;
143     private boolean fGenerateJavadoc;
144     
145     private List JavaDoc fUsedReadNames;
146     private List JavaDoc fUsedModifyNames;
147     private boolean fConsiderVisibility=true;
148     
149     private static final String JavaDoc NO_NAME= ""; //$NON-NLS-1$
150

151     /**
152      * Creates a new self encapsulate field refactoring.
153      * @param field the field, or <code>null</code> if invoked by scripting
154      * @throws JavaModelException
155      */

156     public SelfEncapsulateFieldRefactoring(IField field) throws JavaModelException {
157         fEncapsulateDeclaringClass= true;
158         fChangeManager= new TextChangeManager();
159         fField= field;
160         if (field != null)
161             initialize(field);
162     }
163
164     private void initialize(IField field) throws JavaModelException {
165         fGetterName= GetterSetterUtil.getGetterName(field, null);
166         fSetterName= GetterSetterUtil.getSetterName(field, null);
167         fArgName= NamingConventions.removePrefixAndSuffixForFieldName(field.getJavaProject(), field.getElementName(), field.getFlags());
168         checkArgName();
169     }
170     
171     public IField getField() {
172         return fField;
173     }
174
175     public String JavaDoc getGetterName() {
176         return fGetterName;
177     }
178         
179     public void setGetterName(String JavaDoc name) {
180         fGetterName= name;
181         Assert.isNotNull(fGetterName);
182     }
183
184     public String JavaDoc getSetterName() {
185         return fSetterName;
186     }
187     
188     public void setSetterName(String JavaDoc name) {
189         fSetterName= name;
190         Assert.isNotNull(fSetterName);
191     }
192     
193     public void setInsertionIndex(int index) {
194         fInsertionIndex= index;
195     }
196     
197     public int getVisibility() {
198         return fVisibility;
199     }
200     
201     public void setVisibility(int visibility) {
202         fVisibility= visibility;
203     }
204     
205     public void setEncapsulateDeclaringClass(boolean encapsulateDeclaringClass) {
206         fEncapsulateDeclaringClass= encapsulateDeclaringClass;
207     }
208
209     public boolean getEncapsulateDeclaringClass() {
210         return fEncapsulateDeclaringClass;
211     }
212     
213     public boolean getGenerateJavadoc() {
214         return fGenerateJavadoc;
215     }
216     
217     public void setGenerateJavadoc(boolean value) {
218         fGenerateJavadoc= value;
219     }
220
221     //----activation checking ----------------------------------------------------------
222

223     public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
224         if (fVisibility < 0)
225             fVisibility= (fField.getFlags() & (Flags.AccPublic | Flags.AccProtected | Flags.AccPrivate));
226         RefactoringStatus result= new RefactoringStatus();
227         result.merge(Checks.checkAvailability(fField));
228         if (result.hasFatalError())
229             return result;
230         fRoot= new RefactoringASTParser(AST.JLS3).parse(fField.getCompilationUnit(), true, pm);
231         ISourceRange sourceRange= fField.getNameRange();
232         ASTNode node= NodeFinder.perform(fRoot, sourceRange.getOffset(), sourceRange.getLength());
233         if (node == null) {
234             return mappingErrorFound(result, node);
235         }
236         fFieldDeclaration= (VariableDeclarationFragment)ASTNodes.getParent(node, VariableDeclarationFragment.class);
237         if (fFieldDeclaration == null) {
238             return mappingErrorFound(result, node);
239         }
240         if (fFieldDeclaration.resolveBinding() == null) {
241             if (!processCompilerError(result, node))
242                 result.addFatalError(RefactoringCoreMessages.SelfEncapsulateField_type_not_resolveable);
243             return result;
244         }
245         computeUsedNames();
246         fRewriter= ASTRewrite.create(fRoot.getAST());
247         return result;
248     }
249
250     private RefactoringStatus mappingErrorFound(RefactoringStatus result, ASTNode node) {
251         if (node != null && (node.getFlags() & ASTNode.MALFORMED) != 0 && processCompilerError(result, node))
252             return result;
253         result.addFatalError(getMappingErrorMessage());
254         return result;
255     }
256
257     private boolean processCompilerError(RefactoringStatus result, ASTNode node) {
258         Message[] messages= ASTNodes.getMessages(node, ASTNodes.INCLUDE_ALL_PARENTS);
259         if (messages.length == 0)
260             return false;
261         result.addFatalError(Messages.format(
262             RefactoringCoreMessages.SelfEncapsulateField_compiler_errors_field,
263             new String JavaDoc[] { fField.getElementName(), messages[0].getMessage()}));
264         return true;
265     }
266
267     private String JavaDoc getMappingErrorMessage() {
268         return Messages.format(
269             RefactoringCoreMessages.SelfEncapsulateField_cannot_analyze_selected_field,
270             new String JavaDoc[] {fField.getElementName()});
271     }
272
273     //---- Input checking ----------------------------------------------------------
274

275     public RefactoringStatus checkMethodNames() {
276         return checkMethodNames(isUsingLocalGetter(),isUsingLocalSetter());
277     }
278     
279     public RefactoringStatus checkMethodNames(boolean usingLocalGetter, boolean usingLocalSetter) {
280         RefactoringStatus result= new RefactoringStatus();
281         IType declaringType= fField.getDeclaringType();
282         checkName(result, fGetterName, fUsedReadNames, declaringType, usingLocalGetter, fField);
283         checkName(result, fSetterName, fUsedModifyNames, declaringType, usingLocalSetter, fField);
284         return result;
285     }
286     
287     private static void checkName(RefactoringStatus status, String JavaDoc name, List JavaDoc usedNames, IType type, boolean reUseExistingField, IField field) {
288         if ("".equals(name)) { //$NON-NLS-1$
289
status.addFatalError(RefactoringCoreMessages.Checks_Choose_name);
290             return;
291         }
292         boolean isStatic=false;
293         try {
294             isStatic= Flags.isStatic(field.getFlags());
295         } catch (JavaModelException e) {
296         }
297         status.merge(Checks.checkMethodName(name));
298         for (Iterator JavaDoc iter= usedNames.iterator(); iter.hasNext(); ) {
299             IMethodBinding method= (IMethodBinding)iter.next();
300             String JavaDoc selector= method.getName();
301             if (selector.equals(name)) {
302                 if (!reUseExistingField) {
303                     status.addFatalError(Messages.format(RefactoringCoreMessages.SelfEncapsulateField_method_exists, new String JavaDoc[] { BindingLabelProvider.getBindingLabel(method, JavaElementLabels.ALL_FULLY_QUALIFIED), type.getElementName() }));
304                 } else {
305                     boolean methodIsStatic= Modifier.isStatic(method.getModifiers());
306                     if (methodIsStatic && !isStatic)
307                         status.addWarning(Messages.format(RefactoringCoreMessages.SelfEncapsulateFieldRefactoring_static_method_but_nonstatic_field, new String JavaDoc[] { method.getName(), field.getElementName() }));
308                     if (!methodIsStatic && isStatic)
309                         status.addFatalError(Messages.format(RefactoringCoreMessages.SelfEncapsulateFieldRefactoring_nonstatic_method_but_static_field, new String JavaDoc[] { method.getName(), field.getElementName() }));
310                     return;
311                 }
312
313             }
314         }
315         if (reUseExistingField)
316             status.addFatalError(Messages.format(
317                 RefactoringCoreMessages.SelfEncapsulateFieldRefactoring_methoddoesnotexist_status_fatalError,
318                 new String JavaDoc[] {name, type.getElementName()}));
319     }
320
321     public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
322         RefactoringStatus result= new RefactoringStatus();
323         fChangeManager.clear();
324         pm.beginTask(NO_NAME, 12);
325         pm.setTaskName(RefactoringCoreMessages.SelfEncapsulateField_checking_preconditions);
326         boolean usingLocalGetter=isUsingLocalGetter();
327         boolean usingLocalSetter=isUsingLocalSetter();
328         result.merge(checkMethodNames(usingLocalGetter,usingLocalSetter));
329         pm.worked(1);
330         if (result.hasFatalError())
331             return result;
332         pm.setTaskName(RefactoringCoreMessages.SelfEncapsulateField_searching_for_cunits);
333         final SubProgressMonitor subPm= new SubProgressMonitor(pm, 5);
334         ICompilationUnit[] affectedCUs= RefactoringSearchEngine.findAffectedCompilationUnits(
335             SearchPattern.createPattern(fField, IJavaSearchConstants.REFERENCES),
336             RefactoringScopeFactory.create(fField, fConsiderVisibility),
337             subPm,
338             result, true);
339         
340         checkInHierarchy(result, usingLocalGetter, usingLocalSetter);
341         if (result.hasFatalError())
342             return result;
343             
344         pm.setTaskName(RefactoringCoreMessages.SelfEncapsulateField_analyzing);
345         IProgressMonitor sub= new SubProgressMonitor(pm, 5);
346         sub.beginTask(NO_NAME, affectedCUs.length);
347         IVariableBinding fieldIdentifier= fFieldDeclaration.resolveBinding();
348         ITypeBinding declaringClass=
349             ((AbstractTypeDeclaration)ASTNodes.getParent(fFieldDeclaration, AbstractTypeDeclaration.class)).resolveBinding();
350         List JavaDoc ownerDescriptions= new ArrayList JavaDoc();
351         ICompilationUnit owner= fField.getCompilationUnit();
352         fImportRewrite= StubUtility.createImportRewrite(fRoot, true);
353         
354         for (int i= 0; i < affectedCUs.length; i++) {
355             ICompilationUnit unit= affectedCUs[i];
356             sub.subTask(unit.getElementName());
357             CompilationUnit root= null;
358             ASTRewrite rewriter= null;
359             ImportRewrite importRewrite;
360             List JavaDoc descriptions;
361             if (owner.equals(unit)) {
362                 root= fRoot;
363                 rewriter= fRewriter;
364                 importRewrite= fImportRewrite;
365                 descriptions= ownerDescriptions;
366             } else {
367                 root= new RefactoringASTParser(AST.JLS3).parse(unit, true);
368                 rewriter= ASTRewrite.create(root.getAST());
369                 descriptions= new ArrayList JavaDoc();
370                 importRewrite= StubUtility.createImportRewrite(root, true);
371             }
372             checkCompileErrors(result, root, unit);
373             AccessAnalyzer analyzer= new AccessAnalyzer(this, unit, fieldIdentifier, declaringClass, rewriter, importRewrite);
374             root.accept(analyzer);
375             result.merge(analyzer.getStatus());
376             if (!fSetterMustReturnValue)
377                 fSetterMustReturnValue= analyzer.getSetterMustReturnValue();
378             if (result.hasFatalError()) {
379                 fChangeManager.clear();
380                 return result;
381             }
382             descriptions.addAll(analyzer.getGroupDescriptions());
383             if (!owner.equals(unit))
384                 createEdits(unit, rewriter, descriptions, importRewrite);
385             sub.worked(1);
386             if (pm.isCanceled())
387                 throw new OperationCanceledException();
388         }
389         ownerDescriptions.addAll(addGetterSetterChanges(fRoot, fRewriter, owner.findRecommendedLineSeparator(),usingLocalSetter, usingLocalGetter));
390         createEdits(owner, fRewriter, ownerDescriptions, fImportRewrite);
391
392         sub.done();
393         IFile[] filesToBeModified= ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits());
394         result.merge(Checks.validateModifiesFiles(filesToBeModified, getValidationContext()));
395         if (result.hasFatalError())
396             return result;
397         ResourceChangeChecker.checkFilesToBeChanged(filesToBeModified, new SubProgressMonitor(pm, 1));
398         return result;
399     }
400
401     private void createEdits(ICompilationUnit unit, ASTRewrite rewriter, List JavaDoc groups, ImportRewrite importRewrite) throws CoreException {
402         TextChange change= fChangeManager.get(unit);
403         MultiTextEdit root= new MultiTextEdit();
404         change.setEdit(root);
405         root.addChild(importRewrite.rewriteImports(null));
406         root.addChild(rewriter.rewriteAST());
407         for (Iterator JavaDoc iter= groups.iterator(); iter.hasNext();) {
408             change.addTextEditGroup((TextEditGroup)iter.next());
409         }
410     }
411
412     public Change createChange(IProgressMonitor pm) throws CoreException {
413         final Map JavaDoc arguments= new HashMap JavaDoc();
414         String JavaDoc project= null;
415         IJavaProject javaProject= fField.getJavaProject();
416         if (javaProject != null)
417             project= javaProject.getElementName();
418         int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE;
419         final IType declaring= fField.getDeclaringType();
420         try {
421             if (declaring.isAnonymous() || declaring.isLocal())
422                 flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
423         } catch (JavaModelException exception) {
424             JavaPlugin.log(exception);
425         }
426         final String JavaDoc description= Messages.format(RefactoringCoreMessages.SelfEncapsulateField_descriptor_description_short, fField.getElementName());
427         final String JavaDoc header= Messages.format(RefactoringCoreMessages.SelfEncapsulateFieldRefactoring_descriptor_description, new String JavaDoc[] { JavaElementLabels.getElementLabel(fField, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getElementLabel(declaring, JavaElementLabels.ALL_FULLY_QUALIFIED)});
428         final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
429         comment.addSetting(Messages.format(RefactoringCoreMessages.SelfEncapsulateField_original_pattern, JavaElementLabels.getElementLabel(fField, JavaElementLabels.ALL_FULLY_QUALIFIED)));
430         comment.addSetting(Messages.format(RefactoringCoreMessages.SelfEncapsulateField_getter_pattern, fGetterName));
431         comment.addSetting(Messages.format(RefactoringCoreMessages.SelfEncapsulateField_setter_pattern, fSetterName));
432         String JavaDoc visibility= JdtFlags.getVisibilityString(fVisibility);
433         if ("".equals(visibility)) //$NON-NLS-1$
434
visibility= RefactoringCoreMessages.SelfEncapsulateField_default_visibility;
435         comment.addSetting(Messages.format(RefactoringCoreMessages.SelfEncapsulateField_visibility_pattern, visibility));
436         if (fEncapsulateDeclaringClass)
437             comment.addSetting(RefactoringCoreMessages.SelfEncapsulateField_use_accessors);
438         else
439             comment.addSetting(RefactoringCoreMessages.SelfEncapsulateField_do_not_use_accessors);
440         if (fGenerateJavadoc)
441             comment.addSetting(RefactoringCoreMessages.SelfEncapsulateField_generate_comments);
442         final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.ENCAPSULATE_FIELD, project, description, comment.asString(), arguments, flags);
443         arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fField));
444         arguments.put(ATTRIBUTE_VISIBILITY, new Integer JavaDoc(fVisibility).toString());
445         arguments.put(ATTRIBUTE_INSERTION, new Integer JavaDoc(fInsertionIndex).toString());
446         arguments.put(ATTRIBUTE_SETTER, fSetterName);
447         arguments.put(ATTRIBUTE_GETTER, fGetterName);
448         arguments.put(ATTRIBUTE_COMMENTS, Boolean.valueOf(fGenerateJavadoc).toString());
449         arguments.put(ATTRIBUTE_DECLARING, Boolean.valueOf(fEncapsulateDeclaringClass).toString());
450         final DynamicValidationRefactoringChange result= new DynamicValidationRefactoringChange(descriptor, getName());
451         TextChange[] changes= fChangeManager.getAllChanges();
452         pm.beginTask(NO_NAME, changes.length);
453         pm.setTaskName(RefactoringCoreMessages.SelfEncapsulateField_create_changes);
454         for (int i= 0; i < changes.length; i++) {
455             result.add(changes[i]);
456             pm.worked(1);
457         }
458         pm.done();
459         return result;
460     }
461
462     public String JavaDoc getName() {
463         return RefactoringCoreMessages.SelfEncapsulateField_name;
464     }
465     
466     //---- Helper methods -------------------------------------------------------------
467

468     private void checkCompileErrors(RefactoringStatus result, CompilationUnit root, ICompilationUnit element) {
469         IProblem[] messages= root.getProblems();
470         for (int i= 0; i < messages.length; i++) {
471             IProblem problem= messages[i];
472             if (!isIgnorableProblem(problem)) {
473                 result.addError(Messages.format(
474                         RefactoringCoreMessages.SelfEncapsulateField_compiler_errors_update,
475                         element.getElementName()), JavaStatusContext.create(element));
476                 return;
477             }
478         }
479     }
480     
481     private void checkInHierarchy(RefactoringStatus status, boolean usingLocalGetter, boolean usingLocalSetter) {
482         AbstractTypeDeclaration declaration= (AbstractTypeDeclaration)ASTNodes.getParent(fFieldDeclaration, AbstractTypeDeclaration.class);
483         ITypeBinding type= declaration.resolveBinding();
484         if (type != null) {
485             ITypeBinding fieldType= fFieldDeclaration.resolveBinding().getType();
486             checkMethodInHierarchy(type, fGetterName, fieldType, new ITypeBinding[0], status, usingLocalGetter);
487             checkMethodInHierarchy(type, fSetterName, fFieldDeclaration.getAST().resolveWellKnownType("void"), //$NON-NLS-1$
488
new ITypeBinding[] {fieldType}, status, usingLocalSetter);
489         }
490     }
491     
492     public static void checkMethodInHierarchy(ITypeBinding type, String JavaDoc methodName, ITypeBinding returnType, ITypeBinding[] parameters, RefactoringStatus result, boolean reUseMethod) {
493         IMethodBinding method= Bindings.findMethodInHierarchy(type, methodName, parameters);
494         if (method != null) {
495             boolean returnTypeClash= false;
496             ITypeBinding methodReturnType= method.getReturnType();
497             if (returnType != null && methodReturnType != null) {
498                 String JavaDoc returnTypeKey= returnType.getKey();
499                 String JavaDoc methodReturnTypeKey= methodReturnType.getKey();
500                 if (returnTypeKey == null && methodReturnTypeKey == null) {
501                     returnTypeClash= returnType != methodReturnType;
502                 } else if (returnTypeKey != null && methodReturnTypeKey != null) {
503                     returnTypeClash= !returnTypeKey.equals(methodReturnTypeKey);
504                 }
505             }
506             ITypeBinding dc= method.getDeclaringClass();
507             if (returnTypeClash) {
508                 result.addError(Messages.format(RefactoringCoreMessages.Checks_methodName_returnTypeClash,
509                     new Object JavaDoc[] {methodName, dc.getName()}),
510                     JavaStatusContext.create(method));
511             } else {
512                 if (!reUseMethod)
513                     result.addError(Messages.format(RefactoringCoreMessages.Checks_methodName_overrides,
514                         new Object JavaDoc[] {methodName, dc.getName()}),
515                         JavaStatusContext.create(method));
516             }
517         } else {
518             if (reUseMethod){
519                 result.addError(Messages.format(RefactoringCoreMessages.SelfEncapsulateFieldRefactoring_nosuchmethod_status_fatalError,
520                         new Object JavaDoc[] {methodName}),
521                         JavaStatusContext.create(method));
522             }
523         }
524     }
525     
526     private void computeUsedNames() {
527         fUsedReadNames= new ArrayList JavaDoc(0);
528         fUsedModifyNames= new ArrayList JavaDoc(0);
529         IVariableBinding binding= fFieldDeclaration.resolveBinding();
530         ITypeBinding type= binding.getType();
531         IMethodBinding[] methods= binding.getDeclaringClass().getDeclaredMethods();
532         for (int i= 0; i < methods.length; i++) {
533             IMethodBinding method= methods[i];
534             ITypeBinding[] parameters= methods[i].getParameterTypes();
535             if (parameters == null || parameters.length == 0) {
536                 fUsedReadNames.add(method);
537             } else if (parameters.length == 1 && parameters[0] == type) {
538                 fUsedModifyNames.add(method);
539             }
540         }
541     }
542
543     private List JavaDoc addGetterSetterChanges(CompilationUnit root, ASTRewrite rewriter, String JavaDoc lineDelimiter, boolean usingLocalSetter, boolean usingLocalGetter) throws CoreException {
544         List JavaDoc result= new ArrayList JavaDoc(2);
545         AST ast= root.getAST();
546         FieldDeclaration decl= (FieldDeclaration)ASTNodes.getParent(fFieldDeclaration, ASTNode.FIELD_DECLARATION);
547         int position= 0;
548         int numberOfMethods= 0;
549         List JavaDoc members= ASTNodes.getBodyDeclarations(decl.getParent());
550         for (Iterator JavaDoc iter= members.iterator(); iter.hasNext();) {
551             BodyDeclaration element= (BodyDeclaration)iter.next();
552             if (element.getNodeType() == ASTNode.METHOD_DECLARATION) {
553                 if (fInsertionIndex == -1) {
554                     break;
555                 } else if (fInsertionIndex == numberOfMethods) {
556                     position++;
557                     break;
558                 }
559                 numberOfMethods++;
560             }
561             position++;
562         }
563         TextEditGroup description;
564         ListRewrite rewrite= fRewriter.getListRewrite(decl.getParent(), getBodyDeclarationsProperty(decl.getParent()));
565         if (!JdtFlags.isFinal(fField) && !usingLocalSetter) {
566             description= new TextEditGroup(RefactoringCoreMessages.SelfEncapsulateField_add_setter);
567             result.add(description);
568             rewrite.insertAt(createSetterMethod(ast, rewriter, lineDelimiter), position++, description);
569         }
570         if (!usingLocalGetter){
571             description= new TextEditGroup(RefactoringCoreMessages.SelfEncapsulateField_add_getter);
572             result.add(description);
573             rewrite.insertAt(createGetterMethod(ast, rewriter, lineDelimiter), position, description);
574         }
575         if (!JdtFlags.isPrivate(fField))
576             result.add(makeDeclarationPrivate(rewriter, decl));
577         return result;
578     }
579
580     private TextEditGroup makeDeclarationPrivate(ASTRewrite rewriter, FieldDeclaration decl) {
581         AST ast= rewriter.getAST();
582         TextEditGroup description= new TextEditGroup(RefactoringCoreMessages.SelfEncapsulateField_change_visibility);
583         if (decl.fragments().size() > 1) {
584             //TODO: doesn't work for cases like this: int field1, field2= field1, field3= field2; // keeping refs to field
585
rewriter.remove(fFieldDeclaration, description);
586             ChildListPropertyDescriptor descriptor= getBodyDeclarationsProperty(decl.getParent());
587             VariableDeclarationFragment newField= (VariableDeclarationFragment) rewriter.createCopyTarget(fFieldDeclaration);
588             FieldDeclaration fieldDecl= ast.newFieldDeclaration(newField);
589             fieldDecl.setType((Type)rewriter.createCopyTarget(decl.getType()));
590             fieldDecl.modifiers().addAll(ASTNodeFactory.newModifiers(ast, Modifier.PRIVATE));
591             rewriter.getListRewrite(decl.getParent(), descriptor).insertAfter(fieldDecl, decl, description);
592         } else {
593             ModifierRewrite.create(rewriter, decl).setVisibility(Modifier.PRIVATE, description);
594         }
595         return description;
596     }
597
598     private ChildListPropertyDescriptor getBodyDeclarationsProperty(ASTNode declaration) {
599         if (declaration instanceof AnonymousClassDeclaration)
600             return AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY;
601         else if (declaration instanceof AbstractTypeDeclaration)
602             return ((AbstractTypeDeclaration) declaration).getBodyDeclarationsProperty();
603         Assert.isTrue(false);
604         return null;
605     }
606
607     private MethodDeclaration createSetterMethod(AST ast, ASTRewrite rewriter, String JavaDoc lineDelimiter) throws CoreException {
608         FieldDeclaration field= (FieldDeclaration)ASTNodes.getParent(fFieldDeclaration, FieldDeclaration.class);
609         Type type= field.getType();
610         MethodDeclaration result= ast.newMethodDeclaration();
611         result.setName(ast.newSimpleName(fSetterName));
612         result.modifiers().addAll(ASTNodeFactory.newModifiers(ast, createModifiers()));
613         if (fSetterMustReturnValue) {
614             result.setReturnType2((Type)rewriter.createCopyTarget(type));
615         }
616         SingleVariableDeclaration param= ast.newSingleVariableDeclaration();
617         result.parameters().add(param);
618         param.setName(ast.newSimpleName(fArgName));
619         param.setType((Type)rewriter.createCopyTarget(type));
620         
621         Block block= ast.newBlock();
622         result.setBody(block);
623         Assignment ass= ast.newAssignment();
624         ass.setLeftHandSide(createFieldAccess(ast));
625         ass.setRightHandSide(ast.newSimpleName(fArgName));
626         if (fSetterMustReturnValue) {
627             ReturnStatement rs= ast.newReturnStatement();
628             rs.setExpression(ass);
629             block.statements().add(rs);
630         } else {
631             block.statements().add(ast.newExpressionStatement(ass));
632         }
633         
634         if (fGenerateJavadoc) {
635             String JavaDoc string= CodeGeneration.getSetterComment(
636                 fField.getCompilationUnit() , getTypeName(field.getParent()), fSetterName,
637                 fField.getElementName(), ASTNodes.asString(type), fArgName,
638                 NamingConventions.removePrefixAndSuffixForFieldName(fField.getJavaProject(), fField.getElementName(), fField.getFlags()),
639                 lineDelimiter);
640             if (string != null) {
641                 Javadoc javadoc= (Javadoc)fRewriter.createStringPlaceholder(string, ASTNode.JAVADOC);
642                 result.setJavadoc(javadoc);
643             }
644         }
645         return result;
646     }
647     
648     private MethodDeclaration createGetterMethod(AST ast, ASTRewrite rewriter, String JavaDoc lineDelimiter) throws CoreException {
649         FieldDeclaration field= (FieldDeclaration)ASTNodes.getParent(fFieldDeclaration, FieldDeclaration.class);
650         Type type= field.getType();
651         MethodDeclaration result= ast.newMethodDeclaration();
652         result.setName(ast.newSimpleName(fGetterName));
653         result.modifiers().addAll(ASTNodeFactory.newModifiers(ast, createModifiers()));
654         result.setReturnType2((Type)rewriter.createCopyTarget(type));
655         
656         Block block= ast.newBlock();
657         result.setBody(block);
658         ReturnStatement rs= ast.newReturnStatement();
659         rs.setExpression(ast.newSimpleName(fField.getElementName()));
660         block.statements().add(rs);
661         if (fGenerateJavadoc) {
662             String JavaDoc string= CodeGeneration.getGetterComment(
663                 fField.getCompilationUnit() , getTypeName(field.getParent()), fGetterName,
664                 fField.getElementName(), ASTNodes.asString(type),
665                 NamingConventions.removePrefixAndSuffixForFieldName(fField.getJavaProject(), fField.getElementName(), fField.getFlags()),
666                 lineDelimiter);
667             if (string != null) {
668                 Javadoc javadoc= (Javadoc)fRewriter.createStringPlaceholder(string, ASTNode.JAVADOC);
669                 result.setJavadoc(javadoc);
670             }
671         }
672         return result;
673     }
674
675     private int createModifiers() throws JavaModelException {
676         int result= 0;
677         if (Flags.isPublic(fVisibility))
678             result |= Modifier.PUBLIC;
679         else if (Flags.isProtected(fVisibility))
680             result |= Modifier.PROTECTED;
681         else if (Flags.isPrivate(fVisibility))
682             result |= Modifier.PRIVATE;
683         if (JdtFlags.isStatic(fField))
684             result |= Modifier.STATIC;
685         return result;
686     }
687     
688     private Expression createFieldAccess(AST ast) throws JavaModelException {
689         String JavaDoc fieldName= fField.getElementName();
690         if (fArgName.equals(fieldName)) {
691             if (JdtFlags.isStatic(fField)) {
692                 return ast.newQualifiedName(
693                     ast.newSimpleName(fField.getDeclaringType().getElementName()),
694                     ast.newSimpleName(fieldName));
695             } else {
696                 FieldAccess result= ast.newFieldAccess();
697                 result.setExpression(ast.newThisExpression());
698                 result.setName(ast.newSimpleName(fieldName));
699                 return result;
700             }
701         } else {
702             return ast.newSimpleName(fieldName);
703         }
704     }
705     
706     private void checkArgName() {
707         String JavaDoc fieldName= fField.getElementName();
708         boolean isStatic= true;
709         try {
710             isStatic= JdtFlags.isStatic(fField);
711         } catch(JavaModelException e) {
712         }
713         IJavaProject project= fField.getJavaProject();
714         String JavaDoc sourceLevel= project.getOption(JavaCore.COMPILER_SOURCE, true);
715         String JavaDoc compliance= project.getOption(JavaCore.COMPILER_COMPLIANCE, true);
716         
717         if ((isStatic && fArgName.equals(fieldName) && fieldName.equals(fField.getDeclaringType().getElementName()))
718             || JavaConventions.validateIdentifier(fArgName, sourceLevel, compliance).getSeverity() == IStatus.ERROR)
719             fArgName= "_" + fArgName; //$NON-NLS-1$
720
}
721     
722     private String JavaDoc getTypeName(ASTNode type) {
723         if (type instanceof AbstractTypeDeclaration) {
724             return ((AbstractTypeDeclaration)type).getName().getIdentifier();
725         } else if (type instanceof AnonymousClassDeclaration) {
726             ClassInstanceCreation node= (ClassInstanceCreation)ASTNodes.getParent(type, ClassInstanceCreation.class);
727             return ASTNodes.asString(node.getType());
728         }
729         Assert.isTrue(false, "Should not happen"); //$NON-NLS-1$
730
return null;
731     }
732
733     public RefactoringStatus initialize(RefactoringArguments arguments) {
734         if (arguments instanceof JavaRefactoringArguments) {
735             final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments;
736             final String JavaDoc handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT);
737             if (handle != null) {
738                 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
739                 if (element == null || !element.exists() || element.getElementType() != IJavaElement.FIELD)
740                     return createInputFatalStatus(element, IJavaRefactorings.ENCAPSULATE_FIELD);
741                 else {
742                     fField= (IField) element;
743                     try {
744                         initialize(fField);
745                     } catch (JavaModelException exception) {
746                         return createInputFatalStatus(element, IJavaRefactorings.ENCAPSULATE_FIELD);
747                     }
748                 }
749             } else
750                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT));
751             String JavaDoc name= extended.getAttribute(ATTRIBUTE_GETTER);
752             if (name != null && !"".equals(name)) //$NON-NLS-1$
753
fGetterName= name;
754             else
755                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_GETTER));
756             name= extended.getAttribute(ATTRIBUTE_SETTER);
757             if (name != null && !"".equals(name)) //$NON-NLS-1$
758
fSetterName= name;
759             else
760                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_SETTER));
761             final String JavaDoc encapsulate= extended.getAttribute(ATTRIBUTE_DECLARING);
762             if (encapsulate != null) {
763                 fEncapsulateDeclaringClass= Boolean.valueOf(encapsulate).booleanValue();
764             } else
765                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DECLARING));
766             final String JavaDoc matches= extended.getAttribute(ATTRIBUTE_COMMENTS);
767             if (matches != null) {
768                 fGenerateJavadoc= Boolean.valueOf(matches).booleanValue();
769             } else
770                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_COMMENTS));
771             final String JavaDoc visibility= extended.getAttribute(ATTRIBUTE_VISIBILITY);
772             if (visibility != null && !"".equals(visibility)) {//$NON-NLS-1$
773
int flag= 0;
774                 try {
775                     flag= Integer.parseInt(visibility);
776                 } catch (NumberFormatException JavaDoc exception) {
777                     return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_VISIBILITY));
778                 }
779                 fVisibility= flag;
780             }
781             final String JavaDoc insertion= extended.getAttribute(ATTRIBUTE_INSERTION);
782             if (insertion != null && !"".equals(insertion)) {//$NON-NLS-1$
783
int index= 0;
784                 try {
785                     index= Integer.parseInt(insertion);
786                 } catch (NumberFormatException JavaDoc exception) {
787                     return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_INSERTION));
788                 }
789                 fInsertionIndex= index;
790             }
791         } else
792             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
793         return new RefactoringStatus();
794     }
795
796     public boolean isUsingLocalGetter() {
797         IType declaringType= fField.getDeclaringType();
798         return checkName(fGetterName, fUsedReadNames, declaringType);
799     }
800
801     public boolean isUsingLocalSetter() {
802         IType declaringType= fField.getDeclaringType();
803         return checkName(fSetterName, fUsedModifyNames, declaringType);
804     }
805     
806     private static boolean checkName(String JavaDoc name, List JavaDoc usedNames, IType type) {
807         for (Iterator JavaDoc iter= usedNames.iterator(); iter.hasNext(); ) {
808             IMethodBinding method= (IMethodBinding)iter.next();
809             String JavaDoc selector= method.getName();
810             if (selector.equals(name)) {
811                 return true;
812             }
813         }
814         return false;
815     }
816     
817     private boolean isIgnorableProblem(IProblem problem) {
818         if (problem.getID() == IProblem.NotVisibleField)
819             return true;
820         return false;
821     }
822
823     public boolean isConsiderVisibility() {
824         return fConsiderVisibility;
825     }
826
827     public void setConsiderVisibility(boolean considerVisibility) {
828         fConsiderVisibility= considerVisibility;
829     }
830
831
832 }
833
Popular Tags