KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > refactoring > code > InlineConstantRefactoring


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

11 package org.eclipse.jdt.internal.corext.refactoring.code;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19 import java.util.Set JavaDoc;
20 import java.util.StringTokenizer JavaDoc;
21
22 import org.eclipse.text.edits.MalformedTreeException;
23 import org.eclipse.text.edits.RangeMarker;
24 import org.eclipse.text.edits.TextEdit;
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.OperationCanceledException;
31 import org.eclipse.core.runtime.SubProgressMonitor;
32
33 import org.eclipse.jface.text.BadLocationException;
34 import org.eclipse.jface.text.Document;
35 import org.eclipse.jface.text.IDocument;
36 import org.eclipse.jface.text.IRegion;
37 import org.eclipse.jface.text.TextUtilities;
38
39 import org.eclipse.ltk.core.refactoring.Change;
40 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
41 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
42 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
43
44 import org.eclipse.jdt.core.Flags;
45 import org.eclipse.jdt.core.ICompilationUnit;
46 import org.eclipse.jdt.core.IField;
47 import org.eclipse.jdt.core.IJavaElement;
48 import org.eclipse.jdt.core.IJavaProject;
49 import org.eclipse.jdt.core.ISourceRange;
50 import org.eclipse.jdt.core.JavaModelException;
51 import org.eclipse.jdt.core.dom.AST;
52 import org.eclipse.jdt.core.dom.ASTNode;
53 import org.eclipse.jdt.core.dom.ASTParser;
54 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
55 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
56 import org.eclipse.jdt.core.dom.ArrayCreation;
57 import org.eclipse.jdt.core.dom.ArrayInitializer;
58 import org.eclipse.jdt.core.dom.ArrayType;
59 import org.eclipse.jdt.core.dom.Assignment;
60 import org.eclipse.jdt.core.dom.BodyDeclaration;
61 import org.eclipse.jdt.core.dom.CompilationUnit;
62 import org.eclipse.jdt.core.dom.EnumConstantDeclaration;
63 import org.eclipse.jdt.core.dom.Expression;
64 import org.eclipse.jdt.core.dom.FieldAccess;
65 import org.eclipse.jdt.core.dom.FieldDeclaration;
66 import org.eclipse.jdt.core.dom.IBinding;
67 import org.eclipse.jdt.core.dom.IMethodBinding;
68 import org.eclipse.jdt.core.dom.ITypeBinding;
69 import org.eclipse.jdt.core.dom.IVariableBinding;
70 import org.eclipse.jdt.core.dom.ImportDeclaration;
71 import org.eclipse.jdt.core.dom.MethodInvocation;
72 import org.eclipse.jdt.core.dom.Modifier;
73 import org.eclipse.jdt.core.dom.Name;
74 import org.eclipse.jdt.core.dom.ParenthesizedExpression;
75 import org.eclipse.jdt.core.dom.QualifiedName;
76 import org.eclipse.jdt.core.dom.SimpleName;
77 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
78 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
79 import org.eclipse.jdt.core.dom.Type;
80 import org.eclipse.jdt.core.dom.TypeDeclarationStatement;
81 import org.eclipse.jdt.core.dom.VariableDeclaration;
82 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
83 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
84 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
85 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
86 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
87 import org.eclipse.jdt.core.search.IJavaSearchConstants;
88 import org.eclipse.jdt.core.search.SearchMatch;
89 import org.eclipse.jdt.core.search.SearchPattern;
90
91 import org.eclipse.jdt.internal.corext.Corext;
92 import org.eclipse.jdt.internal.corext.codemanipulation.ImportReferencesCollector;
93 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
94 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
95 import org.eclipse.jdt.internal.corext.dom.HierarchicalASTVisitor;
96 import org.eclipse.jdt.internal.corext.dom.NodeFinder;
97 import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory;
98 import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment;
99 import org.eclipse.jdt.internal.corext.refactoring.Checks;
100 import org.eclipse.jdt.internal.corext.refactoring.IRefactoringSearchRequestor;
101 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
102 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor;
103 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
104 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
105 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
106 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2;
107 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
108 import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes;
109 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange;
110 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
111 import org.eclipse.jdt.internal.corext.refactoring.structure.ASTNodeSearchUtil;
112 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
113 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
114 import org.eclipse.jdt.internal.corext.refactoring.util.TightSourceRangeComputer;
115 import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
116 import org.eclipse.jdt.internal.corext.util.Messages;
117 import org.eclipse.jdt.internal.corext.util.Strings;
118
119 import org.eclipse.jdt.ui.JavaElementLabels;
120
121 import org.eclipse.jdt.internal.ui.JavaPlugin;
122
123 public class InlineConstantRefactoring extends ScriptableRefactoring {
124
125     private static final String JavaDoc ATTRIBUTE_REPLACE= "replace"; //$NON-NLS-1$
126
private static final String JavaDoc ATTRIBUTE_REMOVE= "remove"; //$NON-NLS-1$
127

128     private static class InlineTargetCompilationUnit {
129
130         private static class InitializerTraversal extends HierarchicalASTVisitor {
131         
132             private static boolean areInSameType(ASTNode one, ASTNode other) {
133                 ASTNode onesContainer= getContainingTypeDeclaration(one);
134                 ASTNode othersContainer= getContainingTypeDeclaration(other);
135         
136                 if (onesContainer == null || othersContainer == null)
137                     return false;
138         
139                 ITypeBinding onesContainerBinding= getTypeBindingForTypeDeclaration(onesContainer);
140                 ITypeBinding othersContainerBinding= getTypeBindingForTypeDeclaration(othersContainer);
141         
142                 Assert.isNotNull(onesContainerBinding);
143                 Assert.isNotNull(othersContainerBinding);
144         
145                 String JavaDoc onesKey= onesContainerBinding.getKey();
146                 String JavaDoc othersKey= othersContainerBinding.getKey();
147         
148                 if (onesKey == null || othersKey == null)
149                     return false;
150         
151                 return onesKey.equals(othersKey);
152             }
153         
154             private static boolean isStaticAccess(SimpleName memberName) {
155                 IBinding binding= memberName.resolveBinding();
156                 Assert.isTrue(binding instanceof IVariableBinding || binding instanceof IMethodBinding || binding instanceof ITypeBinding);
157         
158                 if (binding instanceof ITypeBinding)
159                     return true;
160         
161                 if (binding instanceof IVariableBinding)
162                     return ((IVariableBinding) binding).isField();
163         
164                 int modifiers= binding.getModifiers();
165                 return Modifier.isStatic(modifiers);
166             }
167         
168             private static ASTNode getContainingTypeDeclaration(ASTNode node) {
169                 while (node != null && !(node instanceof AbstractTypeDeclaration) && !(node instanceof AnonymousClassDeclaration)) {
170                     node= node.getParent();
171                 }
172                 return node;
173             }
174         
175             private static ITypeBinding getTypeBindingForTypeDeclaration(ASTNode declaration) {
176                 if (declaration instanceof AnonymousClassDeclaration)
177                     return ((AnonymousClassDeclaration) declaration).resolveBinding();
178         
179                 if (declaration instanceof AbstractTypeDeclaration)
180                     return ((AbstractTypeDeclaration) declaration).resolveBinding();
181         
182                 Assert.isTrue(false);
183                 return null;
184             }
185         
186             private final Expression fInitializer;
187             private ASTRewrite fInitializerRewrite;
188             private final HashSet JavaDoc fStaticImportsInInitializer2;
189         
190             // cache:
191
private Set JavaDoc fNamesDeclaredLocallyAtNewLocation;
192         
193             private final Expression fNewLocation;
194             private final HashSet JavaDoc fStaticImportsInReference;
195             private final CompilationUnitRewrite fNewLocationCuRewrite;
196         
197             public InitializerTraversal(Expression initializer, HashSet JavaDoc staticImportsInInitializer, Expression newLocation, HashSet JavaDoc staticImportsInReference, CompilationUnitRewrite newLocationCuRewrite) {
198                 fInitializer= initializer;
199                 fInitializerRewrite= ASTRewrite.create(initializer.getAST());
200                 fStaticImportsInInitializer2= staticImportsInInitializer;
201                 
202                 fNewLocation= newLocation;
203                 fStaticImportsInReference= staticImportsInReference;
204                 fNewLocationCuRewrite= newLocationCuRewrite;
205         
206                 perform(initializer);
207             }
208         
209             /**
210              * @param scope not a TypeDeclaration
211              * @return Set containing Strings representing simple names
212              */

213             private Set JavaDoc getLocallyDeclaredNames(BodyDeclaration scope) {
214                 Assert.isTrue(!(scope instanceof AbstractTypeDeclaration));
215         
216                 final Set JavaDoc result= new HashSet JavaDoc();
217         
218                 if (scope instanceof FieldDeclaration)
219                     return result;
220         
221                 scope.accept(new HierarchicalASTVisitor() {
222         
223                     public boolean visit(AbstractTypeDeclaration node) {
224                         Assert.isTrue(node.getParent() instanceof TypeDeclarationStatement);
225         
226                         result.add(node.getName().getIdentifier());
227                         return false;
228                     }
229         
230                     public boolean visit(AnonymousClassDeclaration anonDecl) {
231                         return false;
232                     }
233         
234                     public boolean visit(VariableDeclaration varDecl) {
235                         result.add(varDecl.getName().getIdentifier());
236                         return false;
237                     }
238                 });
239                 return result;
240             }
241         
242             public ASTRewrite getInitializerRewrite() {
243                 return fInitializerRewrite;
244             }
245         
246             private void perform(Expression initializer) {
247                 initializer.accept(this);
248                 if (initializer instanceof MethodInvocation || initializer instanceof SuperMethodInvocation) {
249                     addExplicitTypeArgumentsIfNecessary(initializer);
250                 }
251             }
252             
253             private void addExplicitTypeArgumentsIfNecessary(Expression invocation) {
254                 if (Invocations.isResolvedTypeInferredFromExpectedType(invocation)) {
255                     ASTNode referenceContext= fNewLocation.getParent();
256                     if (! (referenceContext instanceof VariableDeclarationFragment
257                             || referenceContext instanceof SingleVariableDeclaration
258                             || referenceContext instanceof Assignment)) {
259                         IMethodBinding methodBinding= Invocations.resolveBinding(invocation);
260                         ITypeBinding[] typeArguments= methodBinding.getTypeArguments();
261                         ListRewrite typeArgsRewrite= fInitializerRewrite.getListRewrite(invocation, Invocations.getTypeArgumentsProperty(invocation));
262                         for (int i= 0; i < typeArguments.length; i++) {
263                             Type typeArgument= fNewLocationCuRewrite.getImportRewrite().addImport(typeArguments[i], fNewLocationCuRewrite.getAST());
264                             fNewLocationCuRewrite.getImportRemover().registerAddedImports(typeArgument);
265                             typeArgsRewrite.insertLast(typeArgument, null);
266                         }
267                     }
268                 }
269             }
270             
271             public boolean visit(FieldAccess fieldAccess) {
272                 fieldAccess.getExpression().accept(this);
273                 return false;
274             }
275         
276             public boolean visit(MethodInvocation invocation) {
277                 if (invocation.getExpression() == null)
278                     qualifyUnqualifiedMemberNameIfNecessary(invocation.getName());
279                 else
280                     invocation.getExpression().accept(this);
281         
282                 for (Iterator JavaDoc it= invocation.arguments().iterator(); it.hasNext();)
283                     ((Expression) it.next()).accept(this);
284         
285                 return false;
286             }
287         
288             public boolean visit(Name name) {
289                 SimpleName leftmost= getLeftmost(name);
290         
291                 IBinding leftmostBinding= leftmost.resolveBinding();
292                 if (leftmostBinding instanceof IVariableBinding || leftmostBinding instanceof IMethodBinding || leftmostBinding instanceof ITypeBinding) {
293                     if (shouldUnqualify(leftmost))
294                         unqualifyMemberName(leftmost);
295                     else
296                         qualifyUnqualifiedMemberNameIfNecessary(leftmost);
297                 }
298         
299                 if (leftmostBinding instanceof ITypeBinding) {
300                     String JavaDoc addedImport= fNewLocationCuRewrite.getImportRewrite().addImport((ITypeBinding) leftmostBinding);
301                     fNewLocationCuRewrite.getImportRemover().registerAddedImport(addedImport);
302                 }
303                 
304                 return false;
305             }
306             
307             private void qualifyUnqualifiedMemberNameIfNecessary(SimpleName memberName) {
308                 if (shouldQualify(memberName))
309                     qualifyMemberName(memberName);
310             }
311         
312             private boolean shouldUnqualify(SimpleName memberName) {
313                 if (areInSameType(memberName, fNewLocation))
314                     return ! mayBeShadowedByLocalDeclaration(memberName);
315                 
316                 return false;
317             }
318         
319             private void unqualifyMemberName(SimpleName memberName) {
320                 if (doesParentQualify(memberName))
321                     fInitializerRewrite.replace(memberName.getParent(), memberName, null);
322             }
323
324             private boolean shouldQualify(SimpleName memberName) {
325                 if (! areInSameType(fInitializer, fNewLocation))
326                     return true;
327         
328                 return mayBeShadowedByLocalDeclaration(memberName);
329             }
330             
331             private boolean mayBeShadowedByLocalDeclaration(SimpleName memberName) {
332                 return getNamesDeclaredLocallyAtNewLocation().contains(memberName.getIdentifier());
333             }
334         
335             private Set JavaDoc getNamesDeclaredLocallyAtNewLocation() {
336                 if (fNamesDeclaredLocallyAtNewLocation != null)
337                     return fNamesDeclaredLocallyAtNewLocation;
338         
339                 BodyDeclaration enclosingBodyDecl= (BodyDeclaration) ASTNodes.getParent(fNewLocation, BodyDeclaration.class);
340                 Assert.isTrue(!(enclosingBodyDecl instanceof AbstractTypeDeclaration));
341         
342                 return fNamesDeclaredLocallyAtNewLocation= getLocallyDeclaredNames(enclosingBodyDecl);
343             }
344         
345             private void qualifyMemberName(SimpleName memberName) {
346                 if (isStaticAccess(memberName)) {
347                     IBinding memberBinding= memberName.resolveBinding();
348                     
349                     if (memberBinding instanceof IVariableBinding || memberBinding instanceof IMethodBinding) {
350                         if (fStaticImportsInReference.contains(fNewLocation)) { // use static import if reference location used static import
351
importStatically(memberName, memberBinding);
352                             return;
353                         } else if (fStaticImportsInInitializer2.contains(memberName)) { // use static import if already imported statically in initializer
354
importStatically(memberName, memberBinding);
355                             return;
356                         }
357                     }
358                     qualifyToTopLevelClass(memberName); //otherwise: qualify and import non-static
359
}
360             }
361         
362             private void importStatically(SimpleName toImport, IBinding binding) {
363                 String JavaDoc newName= fNewLocationCuRewrite.getImportRewrite().addStaticImport(binding);
364                 fNewLocationCuRewrite.getImportRemover().registerAddedStaticImport(binding);
365                 
366                 Name newReference= ASTNodeFactory.newName(fInitializerRewrite.getAST(), newName);
367                 fInitializerRewrite.replace(toImport, newReference, null);
368             }
369             
370             private void qualifyToTopLevelClass(SimpleName toQualify) {
371                 ITypeBinding declaringClass= getDeclaringClassBinding(toQualify);
372                 if (declaringClass == null)
373                     return;
374                 
375                 Type newQualification= fNewLocationCuRewrite.getImportRewrite().addImport(declaringClass, fInitializerRewrite.getAST());
376                 fNewLocationCuRewrite.getImportRemover().registerAddedImports(newQualification);
377                 
378                 SimpleName newToQualify= (SimpleName) fInitializerRewrite.createMoveTarget(toQualify);
379                 Type newType= fInitializerRewrite.getAST().newQualifiedType(newQualification, newToQualify);
380                 fInitializerRewrite.replace(toQualify, newType, null);
381             }
382             
383             private static ITypeBinding getDeclaringClassBinding(SimpleName memberName) {
384         
385                 IBinding binding= memberName.resolveBinding();
386                 if (binding instanceof IMethodBinding)
387                     return ((IMethodBinding) binding).getDeclaringClass();
388         
389                 if (binding instanceof IVariableBinding)
390                     return ((IVariableBinding) binding).getDeclaringClass();
391         
392                 if (binding instanceof ITypeBinding)
393                     return ((ITypeBinding) binding).getDeclaringClass();
394         
395                 Assert.isTrue(false);
396                 return null;
397         
398             }
399         
400         }
401         
402         private final Expression fInitializer;
403         private final ICompilationUnit fInitializerUnit;
404         private final VariableDeclarationFragment fOriginalDeclaration;
405         
406         /** The references in this compilation unit, represented as AST Nodes in the parsed representation of the compilation unit */
407         private final Expression[] fReferences;
408         private final VariableDeclarationFragment fDeclarationToRemove;
409         private final CompilationUnitRewrite fCuRewrite;
410         private final TightSourceRangeComputer fSourceRangeComputer;
411         private final HashSet JavaDoc fStaticImportsInInitializer;
412         private final boolean fIs15;
413         
414         private InlineTargetCompilationUnit(CompilationUnitRewrite cuRewrite, Name[] references, InlineConstantRefactoring refactoring, HashSet JavaDoc staticImportsInInitializer) throws JavaModelException {
415             fInitializer= refactoring.getInitializer();
416             fInitializerUnit= refactoring.getDeclaringCompilationUnit();
417             
418             fCuRewrite= cuRewrite;
419             fSourceRangeComputer= new TightSourceRangeComputer();
420             fCuRewrite.getASTRewrite().setTargetSourceRangeComputer(fSourceRangeComputer);
421             if (refactoring.getRemoveDeclaration() && refactoring.getReplaceAllReferences() && cuRewrite.getCu().equals(fInitializerUnit))
422                 fDeclarationToRemove= refactoring.getDeclaration();
423             else
424                 fDeclarationToRemove= null;
425             
426             fOriginalDeclaration= refactoring.getDeclaration();
427             
428             fReferences= new Expression[references.length];
429             for (int i= 0; i < references.length; i++)
430                 fReferences[i]= getQualifiedReference(references[i]);
431             
432             fIs15= JavaModelUtil.is50OrHigher(cuRewrite.getCu().getJavaProject());
433             fStaticImportsInInitializer= fIs15 ? staticImportsInInitializer : new HashSet JavaDoc(0);
434         }
435
436         private static Expression getQualifiedReference(Name fieldName) {
437             if (doesParentQualify(fieldName))
438                 return (Expression) fieldName.getParent();
439
440             return fieldName;
441         }
442
443         private static boolean doesParentQualify(Name fieldName) {
444             ASTNode parent= fieldName.getParent();
445             Assert.isNotNull(parent);
446
447             if (parent instanceof FieldAccess && ((FieldAccess) parent).getName() == fieldName)
448                 return true;
449
450             if (parent instanceof QualifiedName && ((QualifiedName) parent).getName() == fieldName)
451                 return true;
452
453             if (parent instanceof MethodInvocation && ((MethodInvocation) parent).getName() == fieldName)
454                 return true;
455
456             return false;
457         }
458
459         public CompilationUnitChange getChange() throws CoreException {
460             for (int i= 0; i < fReferences.length; i++)
461                 inlineReference(fReferences[i]);
462             
463             removeConstantDeclarationIfNecessary();
464             
465             return fCuRewrite.createChange();
466         }
467
468         private void inlineReference(Expression reference) throws CoreException {
469             ASTNode importDecl= ASTNodes.getParent(reference, ImportDeclaration.class);
470             if (importDecl != null)
471                 return; // don't inline into static imports
472

473             String JavaDoc modifiedInitializer= prepareInitializerForLocation(reference);
474             if (modifiedInitializer == null)
475                 return;
476
477             TextEditGroup msg= fCuRewrite.createGroupDescription(RefactoringCoreMessages.InlineConstantRefactoring_Inline);
478             Expression newReference= (Expression) fCuRewrite.getASTRewrite().createStringPlaceholder(modifiedInitializer, reference.getNodeType());
479
480             if (fInitializer instanceof ArrayInitializer) {
481                 ArrayCreation arrayCreation= fCuRewrite.getAST().newArrayCreation();
482                 ArrayType arrayType= (ArrayType) ASTNodeFactory.newType(fCuRewrite.getAST(), fOriginalDeclaration);
483                 arrayCreation.setType(arrayType);
484
485                 ArrayInitializer newArrayInitializer= (ArrayInitializer) fCuRewrite.getASTRewrite().createStringPlaceholder(modifiedInitializer,
486                         ASTNode.ARRAY_INITIALIZER);
487                 arrayCreation.setInitializer(newArrayInitializer);
488                 newReference= arrayCreation;
489
490                 ITypeBinding typeToAddToImport= ASTNodes.getType(fOriginalDeclaration).resolveBinding();
491                 fCuRewrite.getImportRewrite().addImport(typeToAddToImport);
492                 fCuRewrite.getImportRemover().registerAddedImport(typeToAddToImport.getName());
493             }
494
495             if (shouldParenthesizeSubstitute(fInitializer, reference)) {
496                 ParenthesizedExpression parenthesized= fCuRewrite.getAST().newParenthesizedExpression();
497                 parenthesized.setExpression(newReference);
498                 newReference= parenthesized;
499             }
500             fCuRewrite.getASTRewrite().replace(reference, newReference, msg);
501             fSourceRangeComputer.addTightSourceNode(reference);
502             fCuRewrite.getImportRemover().registerRemovedNode(reference);
503         }
504
505         private String JavaDoc prepareInitializerForLocation(Expression location) throws CoreException {
506             HashSet JavaDoc staticImportsInReference= new HashSet JavaDoc();
507             final IJavaProject project= fCuRewrite.getCu().getJavaProject();
508             if (fIs15)
509                 location.accept(new ImportReferencesCollector(project, null, new ArrayList JavaDoc(), staticImportsInReference));
510             InitializerTraversal traversal= new InitializerTraversal(fInitializer, fStaticImportsInInitializer, location, staticImportsInReference, fCuRewrite);
511             ASTRewrite initializerRewrite= traversal.getInitializerRewrite();
512             IDocument document= new Document(fInitializerUnit.getBuffer().getContents()); // could reuse document when generating and applying undo edits
513

514             final RangeMarker marker= new RangeMarker(fInitializer.getStartPosition(), fInitializer.getLength());
515             TextEdit[] rewriteEdits= initializerRewrite.rewriteAST(document, fInitializerUnit.getJavaProject().getOptions(true)).removeChildren();
516             marker.addChildren(rewriteEdits);
517             try {
518                 marker.apply(document, TextEdit.UPDATE_REGIONS);
519                 String JavaDoc rewrittenInitializer= document.get(marker.getOffset(), marker.getLength());
520                 IRegion region= document.getLineInformation(document.getLineOfOffset(marker.getOffset()));
521                 int oldIndent= Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), project);
522                 return Strings.changeIndent(rewrittenInitializer, oldIndent, project, "", TextUtilities.getDefaultLineDelimiter(document)); //$NON-NLS-1$
523
} catch (MalformedTreeException e) {
524                 JavaPlugin.log(e);
525             } catch (BadLocationException e) {
526                 JavaPlugin.log(e);
527             }
528             return fInitializerUnit.getBuffer().getText(fInitializer.getStartPosition(), fInitializer.getLength());
529         }
530
531         private static boolean shouldParenthesizeSubstitute(Expression substitute, Expression location) {
532             if (substitute instanceof Assignment) // for esthetic reasons
533
return true;
534             else
535                 return ASTNodes.substituteMustBeParenthesized(substitute, location);
536         }
537         
538         private void removeConstantDeclarationIfNecessary() throws CoreException {
539             if (fDeclarationToRemove == null)
540                 return;
541             
542             FieldDeclaration parentDeclaration= (FieldDeclaration) fDeclarationToRemove.getParent();
543             ASTNode toRemove;
544             if (parentDeclaration.fragments().size() == 1)
545                 toRemove= parentDeclaration;
546             else
547                 toRemove= fDeclarationToRemove;
548
549             TextEditGroup msg= fCuRewrite.createGroupDescription(RefactoringCoreMessages.InlineConstantRefactoring_remove_declaration);
550             fCuRewrite.getASTRewrite().remove(toRemove, msg);
551             fCuRewrite.getImportRemover().registerRemovedNode(toRemove);
552         }
553     }
554
555     // ---- End InlineTargetCompilationUnit ----------------------------------------------------------------------------------------------
556

557     private static SimpleName getLeftmost(Name name) {
558         if (name instanceof SimpleName)
559             return (SimpleName) name;
560
561         return getLeftmost(((QualifiedName) name).getQualifier());
562     }
563
564     private int fSelectionStart;
565     private int fSelectionLength;
566     
567     private ICompilationUnit fSelectionCu;
568     private CompilationUnitRewrite fSelectionCuRewrite;
569     private Name fSelectedConstantName;
570     
571     private IField fField;
572     private CompilationUnitRewrite fDeclarationCuRewrite;
573     private VariableDeclarationFragment fDeclaration;
574     private boolean fDeclarationSelected;
575     private boolean fDeclarationSelectedChecked= false;
576     private boolean fInitializerAllStaticFinal;
577     private boolean fInitializerChecked= false;
578
579     private boolean fRemoveDeclaration= false;
580     private boolean fReplaceAllReferences= true;
581
582     private CompilationUnitChange[] fChanges;
583     
584     /**
585      * Creates a new inline constant refactoring.
586      * <p>
587      * This constructor is only used by <code>DelegateCreator</code>.
588      * </p>
589      *
590      * @param field the field to inline
591      */

592     public InlineConstantRefactoring(IField field) {
593         Assert.isNotNull(field);
594         Assert.isTrue(!field.isBinary());
595         fField= field;
596     }
597
598     /**
599      * Creates a new inline constant refactoring.
600      * @param unit the compilation unit, or <code>null</code> if invoked by scripting
601      * @param node the compilation unit node, or <code>null</code> if invoked by scripting
602      * @param selectionStart
603      * @param selectionLength
604      */

605     public InlineConstantRefactoring(ICompilationUnit unit, CompilationUnit node, int selectionStart, int selectionLength) {
606         Assert.isTrue(selectionStart >= 0);
607         Assert.isTrue(selectionLength >= 0);
608         fSelectionCu= unit;
609         fSelectionStart= selectionStart;
610         fSelectionLength= selectionLength;
611         if (unit != null)
612             initialize(unit, node);
613     }
614
615     private void initialize(ICompilationUnit cu, CompilationUnit node) {
616         fSelectionCuRewrite= new CompilationUnitRewrite(cu, node);
617         fSelectedConstantName= findConstantNameNode();
618     }
619
620     private Name findConstantNameNode() {
621         ASTNode node= NodeFinder.perform(fSelectionCuRewrite.getRoot(), fSelectionStart, fSelectionLength);
622         if (node == null)
623             return null;
624         if (node instanceof FieldAccess)
625             node= ((FieldAccess) node).getName();
626         if (node.getParent() instanceof EnumConstantDeclaration)
627             return null;
628         if (!(node instanceof Name))
629             return null;
630         Name name= (Name) node;
631         IBinding binding= name.resolveBinding();
632         if (!(binding instanceof IVariableBinding))
633             return null;
634         IVariableBinding variableBinding= (IVariableBinding) binding;
635         if (!variableBinding.isField() || variableBinding.isEnumConstant())
636             return null;
637         int modifiers= binding.getModifiers();
638         if (! (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)))
639             return null;
640
641         return name;
642     }
643
644     public RefactoringStatus checkStaticFinalConstantNameSelected() {
645         if (fSelectedConstantName == null)
646             return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.InlineConstantRefactoring_static_final_field, null, Corext.getPluginId(), RefactoringStatusCodes.NOT_STATIC_FINAL_SELECTED, null);
647
648         return new RefactoringStatus();
649     }
650
651     public String JavaDoc getName() {
652         return RefactoringCoreMessages.InlineConstantRefactoring_name;
653     }
654
655     public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
656         try {
657             pm.beginTask("", 3); //$NON-NLS-1$
658

659             if (!fSelectionCu.isStructureKnown())
660                 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.InlineConstantRefactoring_syntax_errors, null, Corext.getPluginId(), RefactoringStatusCodes.SYNTAX_ERRORS, null);
661
662             RefactoringStatus result= checkStaticFinalConstantNameSelected();
663             if (result.hasFatalError())
664                 return result;
665             
666             result.merge(findField());
667             if (result.hasFatalError())
668                 return result;
669             pm.worked(1);
670
671             result.merge(findDeclaration());
672             if (result.hasFatalError())
673                 return result;
674             pm.worked(1);
675
676             result.merge(checkInitializer());
677             if (result.hasFatalError())
678                 return result;
679             pm.worked(1);
680
681             return result;
682             
683         } finally {
684             pm.done();
685         }
686     }
687
688     private RefactoringStatus findField() throws JavaModelException {
689         fField= (IField) ((IVariableBinding) fSelectedConstantName.resolveBinding()).getJavaElement();
690         if (fField != null && ! fField.exists())
691             return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.InlineConstantRefactoring_local_anonymous_unsupported, null, Corext.getPluginId(), RefactoringStatusCodes.LOCAL_AND_ANONYMOUS_NOT_SUPPORTED, null);
692         
693         return null;
694     }
695     private RefactoringStatus findDeclaration() throws JavaModelException {
696         fDeclarationSelectedChecked= true;
697         fDeclarationSelected= false;
698         ASTNode parent= fSelectedConstantName.getParent();
699         if (parent instanceof VariableDeclarationFragment) {
700             VariableDeclarationFragment parentDeclaration= (VariableDeclarationFragment) parent;
701             if (parentDeclaration.getName() == fSelectedConstantName) {
702                 fDeclarationSelected= true;
703                 fDeclarationCuRewrite= fSelectionCuRewrite;
704                 fDeclaration= (VariableDeclarationFragment) fSelectedConstantName.getParent();
705                 return null;
706             }
707         }
708         
709         VariableDeclarationFragment declaration= (VariableDeclarationFragment) fSelectionCuRewrite.getRoot().findDeclaringNode(fSelectedConstantName.resolveBinding());
710         if (declaration != null) {
711             fDeclarationCuRewrite= fSelectionCuRewrite;
712             fDeclaration= declaration;
713             return null;
714         }
715
716         if (fField.getCompilationUnit() == null)
717             return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.InlineConstantRefactoring_binary_file, null, Corext.getPluginId(), RefactoringStatusCodes.DECLARED_IN_CLASSFILE, null);
718         
719         fDeclarationCuRewrite= new CompilationUnitRewrite(fField.getCompilationUnit());
720         fDeclaration= ASTNodeSearchUtil.getFieldDeclarationFragmentNode(fField, fDeclarationCuRewrite.getRoot());
721         return null;
722     }
723
724     private RefactoringStatus checkInitializer() {
725         Expression initializer= getInitializer();
726         if (initializer == null)
727             return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.InlineConstantRefactoring_blank_finals, null, Corext.getPluginId(), RefactoringStatusCodes.CANNOT_INLINE_BLANK_FINAL, null);
728
729         fInitializerAllStaticFinal= ConstantChecks.isStaticFinalConstant((IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(initializer));
730         fInitializerChecked= true;
731         return new RefactoringStatus();
732     }
733
734     private VariableDeclarationFragment getDeclaration() throws JavaModelException {
735         return fDeclaration;
736     }
737
738     private Expression getInitializer() {
739         return fDeclaration.getInitializer();
740     }
741     
742     private ICompilationUnit getDeclaringCompilationUnit() throws JavaModelException {
743         return fField.getCompilationUnit();
744     }
745
746     public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
747         RefactoringStatus result= new RefactoringStatus();
748         pm.beginTask("", 3); //$NON-NLS-1$
749

750         try {
751             List JavaDoc/*<CompilationUnitChange>*/changes= new ArrayList JavaDoc();
752             HashSet JavaDoc staticImportsInInitializer= new HashSet JavaDoc();
753             ImportReferencesCollector importReferencesCollector= new ImportReferencesCollector(fField.getJavaProject(), null, new ArrayList JavaDoc(), staticImportsInInitializer);
754             getInitializer().accept(importReferencesCollector);
755             
756             if (getReplaceAllReferences()) {
757                 SearchResultGroup[] searchResultGroups= findReferences(pm, result);
758                 for (int i= 0; i < searchResultGroups.length; i++) {
759                     if (pm.isCanceled())
760                         throw new OperationCanceledException();
761                     SearchResultGroup group= searchResultGroups[i];
762                     ICompilationUnit cu= group.getCompilationUnit();
763
764                     CompilationUnitRewrite cuRewrite= getCuRewrite(cu);
765                     Name[] references= extractReferenceNodes(group.getSearchResults(), cuRewrite.getRoot());
766                     InlineTargetCompilationUnit targetCompilationUnit= new InlineTargetCompilationUnit(
767                             cuRewrite, references, this, staticImportsInInitializer);
768                     changes.add(targetCompilationUnit.getChange());
769                 }
770
771             } else {
772                 Assert.isTrue(! isDeclarationSelected());
773                 InlineTargetCompilationUnit targetForOnlySelectedReference= new InlineTargetCompilationUnit(
774                         fSelectionCuRewrite, new Name[] { fSelectedConstantName }, this, staticImportsInInitializer);
775                 changes.add(targetForOnlySelectedReference.getChange());
776             }
777
778             if (result.hasFatalError())
779                 return result;
780
781             if (getRemoveDeclaration() && getReplaceAllReferences()) {
782                 boolean declarationRemoved= false;
783                 for (Iterator JavaDoc iter= changes.iterator(); iter.hasNext();) {
784                     CompilationUnitChange change= (CompilationUnitChange) iter.next();
785                     if (change.getCompilationUnit().equals(fDeclarationCuRewrite.getCu())) {
786                         declarationRemoved= true;
787                         break;
788                     }
789                 }
790                 if (! declarationRemoved) {
791                     InlineTargetCompilationUnit targetForDeclaration= new InlineTargetCompilationUnit(fDeclarationCuRewrite, new Name[0], this, staticImportsInInitializer);
792                     CompilationUnitChange change= targetForDeclaration.getChange();
793                     if (change != null)
794                         changes.add(change);
795                 }
796             }
797
798             ICompilationUnit[] cus= new ICompilationUnit[changes.size()];
799             for (int i= 0; i < changes.size(); i++) {
800                 CompilationUnitChange change= (CompilationUnitChange) changes.get(i);
801                 cus[i]= change.getCompilationUnit();
802             }
803             result.merge(Checks.validateModifiesFiles(ResourceUtil.getFiles(cus), getValidationContext()));
804
805             pm.worked(1);
806
807             fChanges= (CompilationUnitChange[]) changes.toArray(new CompilationUnitChange[changes.size()]);
808
809             return result;
810             
811         } finally {
812             fSelectionCuRewrite= null;
813             fSelectedConstantName= null;
814             fDeclarationCuRewrite= null;
815             fDeclaration= null;
816             pm.done();
817         }
818     }
819
820     private Name[] extractReferenceNodes(SearchMatch[] searchResults, CompilationUnit cuNode) {
821         Name[] references= new Name[searchResults.length];
822         for (int i= 0; i < searchResults.length; i++)
823             references[i]= (Name) NodeFinder.perform(cuNode, searchResults[i].getOffset(), searchResults[i].getLength());
824         return references;
825     }
826
827     private CompilationUnitRewrite getCuRewrite(ICompilationUnit cu) {
828         CompilationUnitRewrite cuRewrite;
829         if (cu.equals(fSelectionCu)) {
830             cuRewrite= fSelectionCuRewrite;
831         } else if (cu.equals(fField.getCompilationUnit())) {
832             cuRewrite= fDeclarationCuRewrite;
833         } else {
834             cuRewrite= new CompilationUnitRewrite(cu);
835         }
836         return cuRewrite;
837     }
838
839     private SearchResultGroup[] findReferences(IProgressMonitor pm, RefactoringStatus status) throws JavaModelException {
840         final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(fField, IJavaSearchConstants.REFERENCES));
841         engine.setFiltering(true, true);
842         engine.setScope(RefactoringScopeFactory.create(fField));
843         engine.setStatus(status);
844         engine.setRequestor(new IRefactoringSearchRequestor() {
845             public SearchMatch acceptSearchMatch(SearchMatch match) {
846                 return match.isInsideDocComment() ? null : match;
847             }
848         });
849         engine.searchPattern(new SubProgressMonitor(pm, 1));
850         return (SearchResultGroup[]) engine.getResults();
851     }
852
853     public Change createChange(IProgressMonitor pm) throws CoreException {
854         try {
855             pm.beginTask(RefactoringCoreMessages.InlineConstantRefactoring_preview, 2);
856             final Map JavaDoc arguments= new HashMap JavaDoc();
857             String JavaDoc project= null;
858             IJavaProject javaProject= fSelectionCu.getJavaProject();
859             if (javaProject != null)
860                 project= javaProject.getElementName();
861             int flags= RefactoringDescriptor.STRUCTURAL_CHANGE | JavaRefactoringDescriptor.JAR_REFACTORING | JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
862             try {
863                 if (!Flags.isPrivate(fField.getFlags()))
864                     flags|= RefactoringDescriptor.MULTI_CHANGE;
865             } catch (JavaModelException exception) {
866                 JavaPlugin.log(exception);
867             }
868             final String JavaDoc description= Messages.format(RefactoringCoreMessages.InlineConstantRefactoring_descriptor_description_short, fField.getElementName());
869             final String JavaDoc header= Messages.format(RefactoringCoreMessages.InlineConstantRefactoring_descriptor_description, new String JavaDoc[] { JavaElementLabels.getElementLabel(fField, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getElementLabel(fField.getParent(), JavaElementLabels.ALL_FULLY_QUALIFIED)});
870             final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
871             comment.addSetting(Messages.format(RefactoringCoreMessages.InlineConstantRefactoring_original_pattern, JavaElementLabels.getElementLabel(fField, JavaElementLabels.ALL_FULLY_QUALIFIED)));
872             if (fRemoveDeclaration)
873                 comment.addSetting(RefactoringCoreMessages.InlineConstantRefactoring_remove_declaration);
874             if (fReplaceAllReferences)
875                 comment.addSetting(RefactoringCoreMessages.InlineConstantRefactoring_replace_references);
876             final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.INLINE_CONSTANT, project, description, comment.asString(), arguments, flags);
877             arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fSelectionCu));
878             arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION, new Integer JavaDoc(fSelectionStart).toString() + " " + new Integer JavaDoc(fSelectionLength).toString()); //$NON-NLS-1$
879
arguments.put(ATTRIBUTE_REMOVE, Boolean.valueOf(fRemoveDeclaration).toString());
880             arguments.put(ATTRIBUTE_REPLACE, Boolean.valueOf(fReplaceAllReferences).toString());
881             return new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.InlineConstantRefactoring_inline, fChanges);
882         } finally {
883             pm.done();
884             fChanges= null;
885         }
886     }
887
888     private void checkInvariant() {
889         if (isDeclarationSelected())
890             Assert.isTrue(fReplaceAllReferences);
891     }
892
893     public boolean getRemoveDeclaration() {
894         return fRemoveDeclaration;
895     }
896
897     public boolean getReplaceAllReferences() {
898         checkInvariant();
899         return fReplaceAllReferences;
900     }
901
902     public boolean isDeclarationSelected() {
903         Assert.isTrue(fDeclarationSelectedChecked);
904         return fDeclarationSelected;
905     }
906
907     public boolean isInitializerAllStaticFinal() {
908         Assert.isTrue(fInitializerChecked);
909         return fInitializerAllStaticFinal;
910     }
911
912     public void setRemoveDeclaration(boolean removeDeclaration) {
913         fRemoveDeclaration= removeDeclaration;
914     }
915
916     public void setReplaceAllReferences(boolean replaceAllReferences) {
917         fReplaceAllReferences= replaceAllReferences;
918         checkInvariant();
919     }
920
921     public RefactoringStatus initialize(final RefactoringArguments arguments) {
922         if (arguments instanceof JavaRefactoringArguments) {
923             final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments;
924             final String JavaDoc selection= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION);
925             if (selection != null) {
926                 int offset= -1;
927                 int length= -1;
928                 final StringTokenizer JavaDoc tokenizer= new StringTokenizer JavaDoc(selection);
929                 if (tokenizer.hasMoreTokens())
930                     offset= Integer.valueOf(tokenizer.nextToken()).intValue();
931                 if (tokenizer.hasMoreTokens())
932                     length= Integer.valueOf(tokenizer.nextToken()).intValue();
933                 if (offset >= 0 && length >= 0) {
934                     fSelectionStart= offset;
935                     fSelectionLength= length;
936                 } else
937                     return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object JavaDoc[] { selection, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION}));
938             }
939             final String JavaDoc handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT);
940             if (handle != null) {
941                 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
942                 if (element == null || !element.exists())
943                     return createInputFatalStatus(element, IJavaRefactorings.INLINE_CONSTANT);
944                 else {
945                     if (element instanceof ICompilationUnit) {
946                         fSelectionCu= (ICompilationUnit) element;
947                         if (selection == null)
948                             return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION));
949                     } else if (element instanceof IField) {
950                         final IField field= (IField) element;
951                         try {
952                             final ISourceRange range= field.getNameRange();
953                             if (range != null) {
954                                 fSelectionStart= range.getOffset();
955                                 fSelectionLength= range.getLength();
956                             } else
957                                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, IJavaRefactorings.INLINE_CONSTANT));
958                         } catch (JavaModelException exception) {
959                             return createInputFatalStatus(element, IJavaRefactorings.INLINE_CONSTANT);
960                         }
961                         fSelectionCu= field.getCompilationUnit();
962                     } else
963                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object JavaDoc[] { handle, JDTRefactoringDescriptor.ATTRIBUTE_INPUT}));
964                     final ASTParser parser= ASTParser.newParser(AST.JLS3);
965                     parser.setResolveBindings(true);
966                     parser.setSource(fSelectionCu);
967                     final CompilationUnit unit= (CompilationUnit) parser.createAST(null);
968                     initialize(fSelectionCu, unit);
969                     if (checkStaticFinalConstantNameSelected().hasFatalError())
970                         return createInputFatalStatus(element, IJavaRefactorings.INLINE_CONSTANT);
971                 }
972             } else
973                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT));
974             final String JavaDoc replace= extended.getAttribute(ATTRIBUTE_REPLACE);
975             if (replace != null) {
976                 fReplaceAllReferences= Boolean.valueOf(replace).booleanValue();
977             } else
978                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REPLACE));
979             final String JavaDoc remove= extended.getAttribute(ATTRIBUTE_REMOVE);
980             if (remove != null)
981                 fRemoveDeclaration= Boolean.valueOf(remove).booleanValue();
982             else
983                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REMOVE));
984         } else
985             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
986         return new RefactoringStatus();
987     }
988 }
989
Popular Tags