KickJava   Java API By Example, From Geeks To Geeks.

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


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

11 package org.eclipse.jdt.internal.corext.refactoring.rename;
12
13 import java.util.StringTokenizer JavaDoc;
14
15 import org.eclipse.text.edits.MultiTextEdit;
16 import org.eclipse.text.edits.ReplaceEdit;
17 import org.eclipse.text.edits.TextEdit;
18 import org.eclipse.text.edits.TextEditGroup;
19
20 import org.eclipse.core.runtime.Assert;
21 import org.eclipse.core.runtime.CoreException;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.OperationCanceledException;
24
25 import org.eclipse.core.resources.IFile;
26
27 import org.eclipse.ltk.core.refactoring.Change;
28 import org.eclipse.ltk.core.refactoring.GroupCategorySet;
29 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
30 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
31 import org.eclipse.ltk.core.refactoring.TextChange;
32 import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
33 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
34 import org.eclipse.ltk.core.refactoring.participants.RenameArguments;
35
36 import org.eclipse.jdt.core.ICompilationUnit;
37 import org.eclipse.jdt.core.IJavaElement;
38 import org.eclipse.jdt.core.IJavaProject;
39 import org.eclipse.jdt.core.ILocalVariable;
40 import org.eclipse.jdt.core.IMethod;
41 import org.eclipse.jdt.core.ISourceRange;
42 import org.eclipse.jdt.core.JavaModelException;
43 import org.eclipse.jdt.core.dom.ASTNode;
44 import org.eclipse.jdt.core.dom.CompilationUnit;
45 import org.eclipse.jdt.core.dom.Initializer;
46 import org.eclipse.jdt.core.dom.MethodDeclaration;
47 import org.eclipse.jdt.core.dom.VariableDeclaration;
48 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
49 import org.eclipse.jdt.core.refactoring.descriptors.RenameLocalVariableDescriptor;
50
51 import org.eclipse.jdt.internal.corext.dom.NodeFinder;
52 import org.eclipse.jdt.internal.corext.refactoring.Checks;
53 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor;
54 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
55 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
56 import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
57 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
58 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange;
59 import org.eclipse.jdt.internal.corext.refactoring.changes.RefactoringDescriptorChange;
60 import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility;
61 import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring;
62 import org.eclipse.jdt.internal.corext.refactoring.participants.JavaProcessors;
63 import org.eclipse.jdt.internal.corext.refactoring.rename.RenameAnalyzeUtil.LocalAnalyzePackage;
64 import org.eclipse.jdt.internal.corext.refactoring.tagging.IReferenceUpdating;
65 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
66 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
67 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager;
68 import org.eclipse.jdt.internal.corext.util.Messages;
69
70 import org.eclipse.jdt.ui.JavaElementLabels;
71
72 import org.eclipse.jdt.internal.ui.JavaPlugin;
73 import org.eclipse.jdt.internal.ui.refactoring.RefactoringSaveHelper;
74
75 public class RenameLocalVariableProcessor extends JavaRenameProcessor implements IReferenceUpdating {
76
77     private ILocalVariable fLocalVariable;
78     private ICompilationUnit fCu;
79     
80     //the following fields are set or modified after the construction
81
private boolean fUpdateReferences;
82     private String JavaDoc fCurrentName;
83     private String JavaDoc fNewName;
84     private CompilationUnit fCompilationUnitNode;
85     private VariableDeclaration fTempDeclarationNode;
86     private TextChange fChange;
87     
88     private boolean fIsComposite;
89     private GroupCategorySet fCategorySet;
90     private TextChangeManager fChangeManager;
91     private RenameAnalyzeUtil.LocalAnalyzePackage fLocalAnalyzePackage;
92
93     public static final String JavaDoc IDENTIFIER= "org.eclipse.jdt.ui.renameLocalVariableProcessor"; //$NON-NLS-1$
94

95     /**
96      * Creates a new rename local variable processor.
97      * @param localVariable the local variable, or <code>null</code> if invoked by scripting
98      */

99     public RenameLocalVariableProcessor(ILocalVariable localVariable) {
100         fLocalVariable= localVariable;
101         fUpdateReferences= true;
102         if (localVariable != null)
103             fCu= (ICompilationUnit) localVariable.getAncestor(IJavaElement.COMPILATION_UNIT);
104         fNewName= ""; //$NON-NLS-1$
105
fIsComposite= false;
106     }
107     
108     /**
109      * Creates a new rename local variable processor.
110      * <p>
111      * This constructor is only used by <code>RenameTypeProcessor</code>.
112      * </p>
113      *
114      * @param localVariable the local variable
115      * @param manager the change manager
116      * @param node the compilation unit node
117      * @param categorySet the group category set
118      */

119     RenameLocalVariableProcessor(ILocalVariable localVariable, TextChangeManager manager, CompilationUnit node, GroupCategorySet categorySet) {
120         this(localVariable);
121         fChangeManager= manager;
122         fCategorySet= categorySet;
123         fCompilationUnitNode= node;
124         fIsComposite= true;
125     }
126     
127     /*
128      * @see org.eclipse.jdt.internal.corext.refactoring.rename.JavaRenameProcessor#getAffectedProjectNatures()
129      */

130     protected final String JavaDoc[] getAffectedProjectNatures() throws CoreException {
131         return JavaProcessors.computeAffectedNatures(fLocalVariable);
132     }
133     
134     /*
135      * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getElements()
136      */

137     public Object JavaDoc[] getElements() {
138         return new Object JavaDoc[] { fLocalVariable };
139     }
140     
141     /*
142      * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getIdentifier()
143      */

144     public String JavaDoc getIdentifier() {
145         return IDENTIFIER;
146     }
147     
148     /*
149      * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#getProcessorName()
150      */

151     public String JavaDoc getProcessorName() {
152         return RefactoringCoreMessages.RenameTempRefactoring_rename;
153     }
154     
155     /*
156      * @see org.eclipse.ltk.core.refactoring.participants.RefactoringProcessor#isApplicable()
157      */

158     public boolean isApplicable() throws CoreException {
159         return RefactoringAvailabilityTester.isRenameAvailable(fLocalVariable);
160     }
161     
162     /*
163      * @see org.eclipse.jdt.internal.corext.refactoring.tagging.IReferenceUpdating#canEnableUpdateReferences()
164      */

165     public boolean canEnableUpdateReferences() {
166         return true;
167     }
168
169     /*
170      * @see org.eclipse.jdt.internal.corext.refactoring.rename.JavaRenameProcessor#getUpdateReferences()
171      */

172     public boolean getUpdateReferences() {
173         return fUpdateReferences;
174     }
175
176     /*
177      * @see org.eclipse.jdt.internal.corext.refactoring.tagging.IReferenceUpdating#setUpdateReferences(boolean)
178      */

179     public void setUpdateReferences(boolean updateReferences) {
180         fUpdateReferences= updateReferences;
181     }
182     
183     /*
184      * @see org.eclipse.jdt.internal.corext.refactoring.tagging.INameUpdating#getCurrentElementName()
185      */

186     public String JavaDoc getCurrentElementName() {
187         return fCurrentName;
188     }
189
190     /*
191      * @see org.eclipse.jdt.internal.corext.refactoring.tagging.INameUpdating#getNewElementName()
192      */

193     public String JavaDoc getNewElementName() {
194         return fNewName;
195     }
196
197     /*
198      * @see org.eclipse.jdt.internal.corext.refactoring.tagging.INameUpdating#setNewElementName(java.lang.String)
199      */

200     public void setNewElementName(String JavaDoc newName) {
201         Assert.isNotNull(newName);
202         fNewName= newName;
203     }
204
205     /*
206      * @see org.eclipse.jdt.internal.corext.refactoring.tagging.INameUpdating#getNewElement()
207      */

208     public Object JavaDoc getNewElement() {
209         return null; //cannot create an ILocalVariable
210
}
211
212     public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
213         initAST();
214         if (fTempDeclarationNode == null || fTempDeclarationNode.resolveBinding() == null)
215             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.RenameTempRefactoring_must_select_local);
216         if (! Checks.isDeclaredIn(fTempDeclarationNode, MethodDeclaration.class)
217          && ! Checks.isDeclaredIn(fTempDeclarationNode, Initializer.class))
218             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.RenameTempRefactoring_only_in_methods_and_initializers);
219                 
220         initNames();
221         return new RefactoringStatus();
222     }
223
224     private void initAST() throws JavaModelException {
225         if (!fIsComposite)
226             fCompilationUnitNode= RefactoringASTParser.parseWithASTProvider(fCu, true, null);
227         ISourceRange sourceRange= fLocalVariable.getNameRange();
228         ASTNode name= NodeFinder.perform(fCompilationUnitNode, sourceRange);
229         if (name == null)
230             return;
231         if (name.getParent() instanceof VariableDeclaration)
232             fTempDeclarationNode= (VariableDeclaration) name.getParent();
233     }
234     
235     private void initNames(){
236         fCurrentName= fTempDeclarationNode.getName().getIdentifier();
237     }
238     
239     protected RenameModifications computeRenameModifications() throws CoreException {
240         RenameModifications result= new RenameModifications();
241         result.rename(fLocalVariable, new RenameArguments(getNewElementName(), getUpdateReferences()));
242         return result;
243     }
244     
245     protected IFile[] getChangedFiles() throws CoreException {
246         return new IFile[] {ResourceUtil.getFile(fCu)};
247     }
248     
249     public int getSaveMode() {
250         return RefactoringSaveHelper.SAVE_NOTHING;
251     }
252     
253     protected RefactoringStatus doCheckFinalConditions(IProgressMonitor pm, CheckConditionsContext context)
254             throws CoreException, OperationCanceledException {
255         try {
256             pm.beginTask("", 1); //$NON-NLS-1$
257

258             RefactoringStatus result= checkNewElementName(fNewName);
259             if (result.hasFatalError())
260                 return result;
261             createEdits();
262             if (!fIsComposite) {
263                 LocalAnalyzePackage[] localAnalyzePackages= new RenameAnalyzeUtil.LocalAnalyzePackage[] { fLocalAnalyzePackage };
264                 result.merge(RenameAnalyzeUtil.analyzeLocalRenames(localAnalyzePackages, fChange, fCompilationUnitNode, true));
265             }
266             return result;
267         } finally {
268             pm.done();
269             if (fIsComposite) {
270                 // end of life cycle for this processor
271
fChange= null;
272                 fCompilationUnitNode= null;
273                 fTempDeclarationNode= null;
274             }
275         }
276     }
277         
278     /*
279      * @see org.eclipse.jdt.internal.corext.refactoring.tagging.INameUpdating#checkNewElementName(java.lang.String)
280      */

281     public RefactoringStatus checkNewElementName(String JavaDoc newName) throws JavaModelException {
282         RefactoringStatus result= Checks.checkFieldName(newName);
283         if (! Checks.startsWithLowerCase(newName))
284             if (fIsComposite) {
285                 final String JavaDoc nameOfParent= (fLocalVariable.getParent() instanceof IMethod) ? fLocalVariable.getParent().getElementName() : RefactoringCoreMessages.JavaElementUtil_initializer;
286                 final String JavaDoc nameOfType= fLocalVariable.getAncestor(IJavaElement.TYPE).getElementName();
287                 result.addWarning(Messages.format(RefactoringCoreMessages.RenameTempRefactoring_lowercase2, new String JavaDoc[] { newName, nameOfParent, nameOfType }));
288             } else {
289                 result.addWarning(RefactoringCoreMessages.RenameTempRefactoring_lowercase);
290             }
291         return result;
292     }
293         
294     private void createEdits() {
295         TextEdit declarationEdit= createRenameEdit(fTempDeclarationNode.getName().getStartPosition());
296         TextEdit[] allRenameEdits= getAllRenameEdits(declarationEdit);
297         
298         TextEdit[] allUnparentedRenameEdits= new TextEdit[allRenameEdits.length];
299         TextEdit unparentedDeclarationEdit= null;
300         
301         fChange= new CompilationUnitChange(RefactoringCoreMessages.RenameTempRefactoring_rename, fCu);
302         MultiTextEdit rootEdit= new MultiTextEdit();
303         fChange.setEdit(rootEdit);
304         fChange.setKeepPreviewEdits(true);
305
306         for (int i= 0; i < allRenameEdits.length; i++) {
307             if (fIsComposite) {
308                 // Add a copy of the text edit (text edit may only have one
309
// parent) to keep problem reporting code clean
310
TextChangeCompatibility.addTextEdit(fChangeManager.get(fCu), RefactoringCoreMessages.RenameTempRefactoring_changeName, allRenameEdits[i].copy(), fCategorySet);
311                 
312                 // Add a separate copy for problem reporting
313
allUnparentedRenameEdits[i]= allRenameEdits[i].copy();
314                 if (allRenameEdits[i].equals(declarationEdit))
315                     unparentedDeclarationEdit= allUnparentedRenameEdits[i];
316             }
317             rootEdit.addChild(allRenameEdits[i]);
318             fChange.addTextEditGroup(new TextEditGroup(RefactoringCoreMessages.RenameTempRefactoring_changeName, allRenameEdits[i]));
319         }
320
321         // store information for analysis
322
if (fIsComposite) {
323             fLocalAnalyzePackage= new RenameAnalyzeUtil.LocalAnalyzePackage(unparentedDeclarationEdit, allUnparentedRenameEdits);
324         } else
325             fLocalAnalyzePackage= new RenameAnalyzeUtil.LocalAnalyzePackage(declarationEdit, allRenameEdits);
326     }
327     
328     private TextEdit[] getAllRenameEdits(TextEdit declarationEdit) {
329         if (! fUpdateReferences)
330             return new TextEdit[] { declarationEdit };
331         
332         TempOccurrenceAnalyzer fTempAnalyzer= new TempOccurrenceAnalyzer(fTempDeclarationNode, true);
333         fTempAnalyzer.perform();
334         int[] referenceOffsets= fTempAnalyzer.getReferenceAndJavadocOffsets();
335
336         TextEdit[] allRenameEdits= new TextEdit[referenceOffsets.length + 1];
337         for (int i= 0; i < referenceOffsets.length; i++)
338             allRenameEdits[i]= createRenameEdit(referenceOffsets[i]);
339         allRenameEdits[referenceOffsets.length]= declarationEdit;
340         return allRenameEdits;
341     }
342
343     private TextEdit createRenameEdit(int offset) {
344         return new ReplaceEdit(offset, fCurrentName.length(), fNewName);
345     }
346
347     public Change createChange(IProgressMonitor monitor) throws CoreException {
348         try {
349             monitor.beginTask(RefactoringCoreMessages.RenameTypeProcessor_creating_changes, 1);
350             Change change= fChange;
351             if (change != null) {
352                 final ISourceRange range= fLocalVariable.getNameRange();
353                 String JavaDoc project= null;
354                 IJavaProject javaProject= fCu.getJavaProject();
355                 if (javaProject != null)
356                     project= javaProject.getElementName();
357                 final String JavaDoc header= Messages.format(RefactoringCoreMessages.RenameLocalVariableProcessor_descriptor_description, new String JavaDoc[] { fCurrentName, JavaElementLabels.getElementLabel(fLocalVariable.getParent(), JavaElementLabels.ALL_FULLY_QUALIFIED), fNewName});
358                 final String JavaDoc description= Messages.format(RefactoringCoreMessages.RenameLocalVariableProcessor_descriptor_description_short, fCurrentName);
359                 final String JavaDoc comment= new JDTRefactoringDescriptorComment(project, this, header).asString();
360                 final RenameLocalVariableDescriptor descriptor= new RenameLocalVariableDescriptor();
361                 descriptor.setProject(project);
362                 descriptor.setDescription(description);
363                 descriptor.setComment(comment);
364                 descriptor.setFlags(RefactoringDescriptor.NONE);
365                 descriptor.setCompilationUnit(fCu);
366                 descriptor.setNewName(getNewElementName());
367                 descriptor.setSelection(range);
368                 descriptor.setUpdateReferences(fUpdateReferences);
369                 final RefactoringDescriptorChange result= new RefactoringDescriptorChange(descriptor, RefactoringCoreMessages.RenameTempRefactoring_rename, new Change[] { change});
370                 result.markAsSynthetic();
371                 change= result;
372             }
373             return change;
374         } finally {
375             monitor.done();
376         }
377     }
378
379     public RefactoringStatus initialize(RefactoringArguments arguments) {
380         if (arguments instanceof JavaRefactoringArguments) {
381             final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments;
382             final String JavaDoc handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT);
383             if (handle != null) {
384                 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
385                 if (element != null && element.exists()) {
386                     if (element.getElementType() == IJavaElement.COMPILATION_UNIT) {
387                         fCu= (ICompilationUnit) element;
388                     } else if (element.getElementType() == IJavaElement.LOCAL_VARIABLE) {
389                         fLocalVariable= (ILocalVariable) element;
390                         fCu= (ICompilationUnit) fLocalVariable.getAncestor(IJavaElement.COMPILATION_UNIT);
391                         if (fCu == null)
392                             return ScriptableRefactoring.createInputFatalStatus(element, getRefactoring().getName(), IJavaRefactorings.RENAME_LOCAL_VARIABLE);
393                     } else
394                         return ScriptableRefactoring.createInputFatalStatus(element, getRefactoring().getName(), IJavaRefactorings.RENAME_LOCAL_VARIABLE);
395                 } else
396                     return ScriptableRefactoring.createInputFatalStatus(element, getRefactoring().getName(), IJavaRefactorings.RENAME_LOCAL_VARIABLE);
397             } else
398                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT));
399             final String JavaDoc name= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_NAME);
400             if (name != null && !"".equals(name)) //$NON-NLS-1$
401
setNewElementName(name);
402             else
403                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_NAME));
404             if (fCu != null && fLocalVariable == null) {
405                 final String JavaDoc selection= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION);
406                 if (selection != null) {
407                     int offset= -1;
408                     int length= -1;
409                     final StringTokenizer JavaDoc tokenizer= new StringTokenizer JavaDoc(selection);
410                     if (tokenizer.hasMoreTokens())
411                         offset= Integer.valueOf(tokenizer.nextToken()).intValue();
412                     if (tokenizer.hasMoreTokens())
413                         length= Integer.valueOf(tokenizer.nextToken()).intValue();
414                     if (offset >= 0 && length >= 0) {
415                         try {
416                             final IJavaElement[] elements= fCu.codeSelect(offset, length);
417                             if (elements != null) {
418                                 for (int index= 0; index < elements.length; index++) {
419                                     final IJavaElement element= elements[index];
420                                     if (element instanceof ILocalVariable)
421                                         fLocalVariable= (ILocalVariable) element;
422                                 }
423                             }
424                             if (fLocalVariable == null)
425                                 return ScriptableRefactoring.createInputFatalStatus(null, getRefactoring().getName(), IJavaRefactorings.RENAME_LOCAL_VARIABLE);
426                         } catch (JavaModelException exception) {
427                             JavaPlugin.log(exception);
428                         }
429                     } else
430                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object JavaDoc[] { selection, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION}));
431                 } else
432                     return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION));
433             }
434             final String JavaDoc references= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_REFERENCES);
435             if (references != null) {
436                 fUpdateReferences= Boolean.valueOf(references).booleanValue();
437             } else
438                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_REFERENCES));
439         } else
440             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
441         return new RefactoringStatus();
442     }
443
444     public RenameAnalyzeUtil.LocalAnalyzePackage getLocalAnalyzePackage() {
445         return fLocalAnalyzePackage;
446     }
447 }
448
Popular Tags