KickJava   Java API By Example, From Geeks To Geeks.

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


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.Arrays JavaDoc;
15 import java.util.Collection JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19 import java.util.Map JavaDoc;
20 import java.util.StringTokenizer JavaDoc;
21
22 import org.eclipse.text.edits.TextEditGroup;
23
24 import org.eclipse.core.runtime.Assert;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.core.runtime.NullProgressMonitor;
28 import org.eclipse.core.runtime.SubProgressMonitor;
29
30 import org.eclipse.ltk.core.refactoring.Change;
31 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
32 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
33 import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
34 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
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.JavaModelException;
40 import org.eclipse.jdt.core.compiler.IProblem;
41 import org.eclipse.jdt.core.dom.AST;
42 import org.eclipse.jdt.core.dom.ASTNode;
43 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
44 import org.eclipse.jdt.core.dom.BodyDeclaration;
45 import org.eclipse.jdt.core.dom.CompilationUnit;
46 import org.eclipse.jdt.core.dom.Expression;
47 import org.eclipse.jdt.core.dom.ExpressionStatement;
48 import org.eclipse.jdt.core.dom.FieldAccess;
49 import org.eclipse.jdt.core.dom.FieldDeclaration;
50 import org.eclipse.jdt.core.dom.ITypeBinding;
51 import org.eclipse.jdt.core.dom.Initializer;
52 import org.eclipse.jdt.core.dom.Javadoc;
53 import org.eclipse.jdt.core.dom.MethodDeclaration;
54 import org.eclipse.jdt.core.dom.Modifier;
55 import org.eclipse.jdt.core.dom.Name;
56 import org.eclipse.jdt.core.dom.NullLiteral;
57 import org.eclipse.jdt.core.dom.QualifiedName;
58 import org.eclipse.jdt.core.dom.SimpleName;
59 import org.eclipse.jdt.core.dom.SwitchCase;
60 import org.eclipse.jdt.core.dom.Type;
61 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
62 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
63 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
64 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
65 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
66
67 import org.eclipse.jdt.internal.corext.Corext;
68 import org.eclipse.jdt.internal.corext.SourceRange;
69 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
70 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
71 import org.eclipse.jdt.internal.corext.dom.Bindings;
72 import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
73 import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory;
74 import org.eclipse.jdt.internal.corext.dom.fragments.IASTFragment;
75 import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment;
76 import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
77 import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup;
78 import org.eclipse.jdt.internal.corext.refactoring.Checks;
79 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor;
80 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
81 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
82 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
83 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStringStatusContext;
84 import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes;
85 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange;
86 import org.eclipse.jdt.internal.corext.refactoring.changes.RefactoringDescriptorChange;
87 import org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringAnalyzeUtil;
88 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
89 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
90 import org.eclipse.jdt.internal.corext.util.JdtFlags;
91 import org.eclipse.jdt.internal.corext.util.Messages;
92
93 import org.eclipse.jdt.ui.CodeGeneration;
94 import org.eclipse.jdt.ui.JavaElementLabels;
95
96 import org.eclipse.jdt.internal.ui.JavaPlugin;
97 import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
98 import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
99 import org.eclipse.jdt.internal.ui.text.correction.ModifierCorrectionSubProcessor;
100 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
101
102 public class ExtractConstantRefactoring extends ScriptableRefactoring {
103
104     private static final String JavaDoc ATTRIBUTE_REPLACE= "replace"; //$NON-NLS-1$
105
private static final String JavaDoc ATTRIBUTE_QUALIFY= "qualify"; //$NON-NLS-1$
106
private static final String JavaDoc ATTRIBUTE_VISIBILITY= "visibility"; //$NON-NLS-1$
107

108     private static final String JavaDoc MODIFIER= "static final"; //$NON-NLS-1$
109

110     private static final String JavaDoc KEY_NAME= "name"; //$NON-NLS-1$
111
private static final String JavaDoc KEY_TYPE= "type"; //$NON-NLS-1$
112

113     private CompilationUnitRewrite fCuRewrite;
114     private int fSelectionStart;
115     private int fSelectionLength;
116     private ICompilationUnit fCu;
117
118     private IExpressionFragment fSelectedExpression;
119     private Type fConstantTypeCache;
120     private boolean fReplaceAllOccurrences= true; //default value
121
private boolean fQualifyReferencesWithDeclaringClassName= false; //default value
122

123     private String JavaDoc fVisibility= JdtFlags.VISIBILITY_STRING_PRIVATE; //default value
124
private boolean fTargetIsInterface= false;
125     private String JavaDoc fConstantName;
126     private String JavaDoc[] fExcludedVariableNames;
127
128     private boolean fSelectionAllStaticFinal;
129     private boolean fAllStaticFinalCheckPerformed= false;
130     
131     private List JavaDoc fBodyDeclarations;
132     
133     //Constant Declaration Location
134
private BodyDeclaration fToInsertAfter;
135     private boolean fInsertFirst;
136     
137     private CompilationUnitChange fChange;
138     private String JavaDoc[] fGuessedConstNames;
139     
140     private LinkedProposalModel fLinkedProposalModel;
141
142     /**
143      * Creates a new extract constant refactoring
144      * @param unit the compilation unit, or <code>null</code> if invoked by scripting
145      * @param selectionStart
146      * @param selectionLength
147      */

148     public ExtractConstantRefactoring(ICompilationUnit unit, int selectionStart, int selectionLength) {
149         Assert.isTrue(selectionStart >= 0);
150         Assert.isTrue(selectionLength >= 0);
151         fSelectionStart= selectionStart;
152         fSelectionLength= selectionLength;
153         fCu= unit;
154         fCuRewrite= null;
155         fLinkedProposalModel= null;
156         fConstantName= ""; //$NON-NLS-1$
157
}
158     
159     public ExtractConstantRefactoring(CompilationUnit astRoot, int selectionStart, int selectionLength) {
160         Assert.isTrue(selectionStart >= 0);
161         Assert.isTrue(selectionLength >= 0);
162         Assert.isTrue(astRoot.getTypeRoot() instanceof ICompilationUnit);
163         
164         fSelectionStart= selectionStart;
165         fSelectionLength= selectionLength;
166         fCu= (ICompilationUnit) astRoot.getTypeRoot();
167         fCuRewrite= new CompilationUnitRewrite(fCu, astRoot);
168         fLinkedProposalModel= null;
169         fConstantName= ""; //$NON-NLS-1$
170
}
171         
172     public void setLinkedProposalModel(LinkedProposalModel linkedProposalModel) {
173         fLinkedProposalModel= linkedProposalModel;
174     }
175     
176     public String JavaDoc getName() {
177         return RefactoringCoreMessages.ExtractConstantRefactoring_name;
178     }
179
180     public boolean replaceAllOccurrences() {
181         return fReplaceAllOccurrences;
182     }
183
184     public void setReplaceAllOccurrences(boolean replaceAllOccurrences) {
185         fReplaceAllOccurrences= replaceAllOccurrences;
186     }
187     
188     public void setVisibility(String JavaDoc am) {
189         Assert.isTrue(
190             am == JdtFlags.VISIBILITY_STRING_PRIVATE || am == JdtFlags.VISIBILITY_STRING_PROTECTED || am == JdtFlags.VISIBILITY_STRING_PACKAGE || am == JdtFlags.VISIBILITY_STRING_PUBLIC
191         );
192         fVisibility= am;
193     }
194     
195     public String JavaDoc getVisibility() {
196         return fVisibility;
197     }
198     
199     public boolean getTargetIsInterface() {
200         return fTargetIsInterface;
201     }
202
203     public boolean qualifyReferencesWithDeclaringClassName() {
204         return fQualifyReferencesWithDeclaringClassName;
205     }
206     
207     public void setQualifyReferencesWithDeclaringClassName(boolean qualify) {
208         fQualifyReferencesWithDeclaringClassName= qualify;
209     }
210     
211     public String JavaDoc guessConstantName() throws JavaModelException {
212         String JavaDoc[] proposals= guessConstantNames();
213         if (proposals.length > 0)
214             return proposals[0];
215         else
216             return fConstantName;
217     }
218     
219     /**
220      * @return proposed variable names (may be empty, but not null).
221      * The first proposal should be used as "best guess" (if it exists).
222      */

223     public String JavaDoc[] guessConstantNames() {
224         if (fGuessedConstNames == null) {
225             try {
226                 Expression expression= getSelectedExpression().getAssociatedExpression();
227                 if (expression != null) {
228                     ITypeBinding binding= expression.resolveTypeBinding();
229                     fGuessedConstNames= StubUtility.getVariableNameSuggestions(StubUtility.CONSTANT_FIELD, fCu.getJavaProject(), binding, expression, Arrays.asList(getExcludedVariableNames()));
230                 }
231             } catch (JavaModelException e) {
232             }
233             if (fGuessedConstNames == null)
234                 fGuessedConstNames= new String JavaDoc[0];
235         }
236         return fGuessedConstNames;
237     }
238     
239     
240     private String JavaDoc[] getExcludedVariableNames() {
241         if (fExcludedVariableNames == null) {
242             try {
243                 IExpressionFragment expr= getSelectedExpression();
244                 Collection JavaDoc takenNames= new ScopeAnalyzer(fCuRewrite.getRoot()).getUsedVariableNames(expr.getStartPosition(), expr.getLength());
245                 fExcludedVariableNames= (String JavaDoc[]) takenNames.toArray(new String JavaDoc[takenNames.size()]);
246             } catch (JavaModelException e) {
247                 fExcludedVariableNames= new String JavaDoc[0];
248             }
249         }
250         return fExcludedVariableNames;
251     }
252         
253     public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
254         try {
255             pm.beginTask("", 7); //$NON-NLS-1$
256

257             RefactoringStatus result= Checks.validateEdit(fCu, getValidationContext());
258             if (result.hasFatalError())
259                 return result;
260             pm.worked(1);
261             
262             if (fCuRewrite == null) {
263                 CompilationUnit cuNode= RefactoringASTParser.parseWithASTProvider(fCu, true, new SubProgressMonitor(pm, 3));
264                 fCuRewrite= new CompilationUnitRewrite(fCu, cuNode);
265             } else {
266                 pm.worked(3);
267             }
268             result.merge(checkSelection(new SubProgressMonitor(pm, 3)));
269     
270             if (result.hasFatalError())
271                 return result;
272             
273             if (isLiteralNodeSelected())
274                 fReplaceAllOccurrences= false;
275             
276             ITypeBinding targetType= getContainingTypeBinding();
277             if (targetType.isAnnotation() || targetType.isInterface()) {
278                 fTargetIsInterface= true;
279                 fVisibility= JdtFlags.VISIBILITY_STRING_PUBLIC;
280             }
281             
282             return result;
283         } finally {
284             pm.done();
285         }
286     }
287     
288     public boolean selectionAllStaticFinal() {
289         Assert.isTrue(fAllStaticFinalCheckPerformed);
290         return fSelectionAllStaticFinal;
291     }
292
293     private void checkAllStaticFinal() throws JavaModelException {
294         fSelectionAllStaticFinal= ConstantChecks.isStaticFinalConstant(getSelectedExpression());
295         fAllStaticFinalCheckPerformed= true;
296     }
297
298     private RefactoringStatus checkSelection(IProgressMonitor pm) throws JavaModelException {
299         try {
300             pm.beginTask("", 2); //$NON-NLS-1$
301

302             IExpressionFragment selectedExpression= getSelectedExpression();
303             
304             if (selectedExpression == null) {
305                 String JavaDoc message= RefactoringCoreMessages.ExtractConstantRefactoring_select_expression;
306                 return CodeRefactoringUtil.checkMethodSyntaxErrors(fSelectionStart, fSelectionLength, fCuRewrite.getRoot(), message);
307             }
308             pm.worked(1);
309             
310             RefactoringStatus result= new RefactoringStatus();
311             result.merge(checkExpression());
312             if (result.hasFatalError())
313                 return result;
314             pm.worked(1);
315             
316             return result;
317         } finally {
318             pm.done();
319         }
320     }
321
322     private RefactoringStatus checkExpressionBinding() throws JavaModelException {
323         return checkExpressionFragmentIsRValue();
324     }
325     
326     private RefactoringStatus checkExpressionFragmentIsRValue() throws JavaModelException {
327         /* Moved this functionality to Checks, to allow sharing with
328            ExtractTempRefactoring, others */

329         switch(Checks.checkExpressionIsRValue(getSelectedExpression().getAssociatedExpression())) {
330             case Checks.NOT_RVALUE_MISC:
331                 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.ExtractConstantRefactoring_select_expression, null, Corext.getPluginId(), RefactoringStatusCodes.EXPRESSION_NOT_RVALUE, null);
332             case Checks.NOT_RVALUE_VOID:
333                 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.ExtractConstantRefactoring_no_void, null, Corext.getPluginId(), RefactoringStatusCodes.EXPRESSION_NOT_RVALUE_VOID, null);
334             case Checks.IS_RVALUE:
335                 return new RefactoringStatus();
336             default:
337                 Assert.isTrue(false); return null;
338         }
339     }
340
341     // !!! -- same as in ExtractTempRefactoring
342
private boolean isLiteralNodeSelected() throws JavaModelException {
343         IExpressionFragment fragment= getSelectedExpression();
344         if (fragment == null)
345             return false;
346         Expression expression= fragment.getAssociatedExpression();
347         if (expression == null)
348             return false;
349         switch (expression.getNodeType()) {
350             case ASTNode.BOOLEAN_LITERAL :
351             case ASTNode.CHARACTER_LITERAL :
352             case ASTNode.NULL_LITERAL :
353             case ASTNode.NUMBER_LITERAL :
354                 return true;
355             
356             default :
357                 return false;
358         }
359     }
360
361     private RefactoringStatus checkExpression() throws JavaModelException {
362         RefactoringStatus result= new RefactoringStatus();
363         result.merge(checkExpressionBinding());
364         if(result.hasFatalError())
365             return result;
366         checkAllStaticFinal();
367
368         IExpressionFragment selectedExpression= getSelectedExpression();
369         Expression associatedExpression= selectedExpression.getAssociatedExpression();
370         if (associatedExpression instanceof NullLiteral)
371             result.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractConstantRefactoring_null_literals));
372         else if (!ConstantChecks.isLoadTimeConstant(selectedExpression))
373             result.merge(RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractConstantRefactoring_not_load_time_constant));
374         else if (associatedExpression instanceof SimpleName) {
375             if (associatedExpression.getParent() instanceof QualifiedName && associatedExpression.getLocationInParent() == QualifiedName.NAME_PROPERTY
376                     || associatedExpression.getParent() instanceof FieldAccess && associatedExpression.getLocationInParent() == FieldAccess.NAME_PROPERTY)
377                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractConstantRefactoring_select_expression);
378         }
379         
380         return result;
381     }
382
383     public void setConstantName(String JavaDoc newName) {
384         Assert.isNotNull(newName);
385         fConstantName= newName;
386     }
387
388     public String JavaDoc getConstantName() {
389         return fConstantName;
390     }
391
392     /**
393      * This method performs checks on the constant name which are
394      * quick enough to be performed every time the ui input component
395      * contents are changed.
396      *
397      * @return return the resulting status
398      * @throws JavaModelException thrown when the operation could not be executed
399      */

400     public RefactoringStatus checkConstantNameOnChange() throws JavaModelException {
401         if (Arrays.asList(getExcludedVariableNames()).contains(fConstantName))
402             return RefactoringStatus.createErrorStatus(Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_another_variable, getConstantName()));
403         return Checks.checkConstantName(getConstantName());
404     }
405     
406     // !! similar to ExtractTempRefactoring equivalent
407
public String JavaDoc getConstantSignaturePreview() throws JavaModelException {
408         String JavaDoc space= " "; //$NON-NLS-1$
409
return getVisibility() + space + MODIFIER + space + getConstantTypeName() + space + fConstantName;
410     }
411     
412     public CompilationUnitChange createTextChange(IProgressMonitor pm) throws CoreException {
413         createConstantDeclaration();
414         replaceExpressionsWithConstant();
415         return fCuRewrite.createChange(RefactoringCoreMessages.ExtractConstantRefactoring_change_name, true, pm);
416     }
417     
418
419     public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
420         pm.beginTask(RefactoringCoreMessages.ExtractConstantRefactoring_checking_preconditions, 4);
421         
422         /* Note: some checks are performed on change of input widget
423          * values. (e.g. see ExtractConstantRefactoring.checkConstantNameOnChange())
424          */

425         
426         //TODO: possibly add more checking for name conflicts that might
427
// lead to a change in behaviour
428

429         try {
430             RefactoringStatus result= new RefactoringStatus();
431             fChange= createTextChange(new SubProgressMonitor(pm, 2));
432             
433             String JavaDoc newCuSource= fChange.getPreviewContent(new NullProgressMonitor());
434             CompilationUnit newCUNode= new RefactoringASTParser(AST.JLS3).parse(newCuSource, fCu, true, true, null);
435             
436             IProblem[] newProblems= RefactoringAnalyzeUtil.getIntroducedCompileProblems(newCUNode, fCuRewrite.getRoot());
437             for (int i= 0; i < newProblems.length; i++) {
438                 IProblem problem= newProblems[i];
439                 if (problem.isError())
440                     result.addEntry(new RefactoringStatusEntry((problem.isError() ? RefactoringStatus.ERROR : RefactoringStatus.WARNING), problem.getMessage(), new JavaStringStatusContext(newCuSource, new SourceRange(problem))));
441             }
442             
443             fConstantTypeCache= null;
444             fCuRewrite.clearASTAndImportRewrites();
445
446             return result;
447         } finally {
448             pm.done();
449         }
450     }
451
452     private void createConstantDeclaration() throws CoreException {
453         Type type= getConstantType();
454         
455         IExpressionFragment fragment= getSelectedExpression();
456         String JavaDoc initializerSource= fCu.getBuffer().getText(fragment.getStartPosition(), fragment.getLength());
457         
458         AST ast= fCuRewrite.getAST();
459         VariableDeclarationFragment variableDeclarationFragment= ast.newVariableDeclarationFragment();
460         variableDeclarationFragment.setName(ast.newSimpleName(fConstantName));
461         variableDeclarationFragment.setInitializer((Expression) fCuRewrite.getASTRewrite().createStringPlaceholder(initializerSource, ASTNode.SIMPLE_NAME));
462         
463         FieldDeclaration fieldDeclaration= ast.newFieldDeclaration(variableDeclarationFragment);
464         fieldDeclaration.setType(type);
465         Modifier.ModifierKeyword accessModifier= Modifier.ModifierKeyword.toKeyword(fVisibility);
466         if (accessModifier != null)
467             fieldDeclaration.modifiers().add(ast.newModifier(accessModifier));
468         fieldDeclaration.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD));
469         fieldDeclaration.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.FINAL_KEYWORD));
470         
471         boolean createComments= JavaPreferencesSettings.getCodeGenerationSettings(fCu.getJavaProject()).createComments;
472         if (createComments) {
473             String JavaDoc comment= CodeGeneration.getFieldComment(fCu, getConstantTypeName(), fConstantName, StubUtility.getLineDelimiterUsed(fCu));
474             if (comment != null && comment.length() > 0) {
475                 Javadoc doc= (Javadoc) fCuRewrite.getASTRewrite().createStringPlaceholder(comment, ASTNode.JAVADOC);
476                 fieldDeclaration.setJavadoc(doc);
477             }
478         }
479         
480         AbstractTypeDeclaration parent= getContainingTypeDeclarationNode();
481         ListRewrite listRewrite= fCuRewrite.getASTRewrite().getListRewrite(parent, parent.getBodyDeclarationsProperty());
482         TextEditGroup msg= fCuRewrite.createGroupDescription(RefactoringCoreMessages.ExtractConstantRefactoring_declare_constant);
483         if (insertFirst()) {
484             listRewrite.insertFirst(fieldDeclaration, msg);
485         } else {
486             listRewrite.insertAfter(fieldDeclaration, getNodeToInsertConstantDeclarationAfter(), msg);
487         }
488         
489         if (fLinkedProposalModel != null) {
490             ASTRewrite rewrite= fCuRewrite.getASTRewrite();
491             LinkedProposalPositionGroup nameGroup= fLinkedProposalModel.getPositionGroup(KEY_NAME, true);
492             nameGroup.addPosition(rewrite.track(variableDeclarationFragment.getName()), true);
493             
494             String JavaDoc[] nameSuggestions= guessConstantNames();
495             if (nameSuggestions.length > 0 && !nameSuggestions[0].equals(fConstantName)) {
496                 nameGroup.addProposal(fConstantName, null, nameSuggestions.length + 1);
497             }
498             for (int i= 0; i < nameSuggestions.length; i++) {
499                 nameGroup.addProposal(nameSuggestions[i], null, nameSuggestions.length - i);
500             }
501             
502             LinkedProposalPositionGroup typeGroup= fLinkedProposalModel.getPositionGroup(KEY_TYPE, true);
503             typeGroup.addPosition(rewrite.track(type), true);
504             
505             ITypeBinding typeBinding= fragment.getAssociatedExpression().resolveTypeBinding();
506             if (typeBinding != null) {
507                 ITypeBinding[] relaxingTypes= ASTResolving.getNarrowingTypes(ast, typeBinding);
508                 for (int i= 0; i < relaxingTypes.length; i++) {
509                     typeGroup.addProposal(relaxingTypes[i], fCuRewrite.getCu(), relaxingTypes.length - i);
510                 }
511             }
512             boolean isInterface= parent.resolveBinding() != null && parent.resolveBinding().isInterface();
513             ModifierCorrectionSubProcessor.installLinkedVisibilityProposals(fLinkedProposalModel, rewrite, fieldDeclaration.modifiers(), isInterface);
514         }
515     }
516
517     private Type getConstantType() throws JavaModelException {
518         if (fConstantTypeCache == null) {
519             IExpressionFragment fragment= getSelectedExpression();
520             ITypeBinding typeBinding= fragment.getAssociatedExpression().resolveTypeBinding();
521             AST ast= fCuRewrite.getAST();
522             typeBinding= Bindings.normalizeForDeclarationUse(typeBinding, ast);
523             fConstantTypeCache= fCuRewrite.getImportRewrite().addImport(typeBinding, ast);
524         }
525         return fConstantTypeCache;
526     }
527
528     public Change createChange(IProgressMonitor monitor) throws CoreException {
529         final Map JavaDoc arguments= new HashMap JavaDoc();
530         String JavaDoc project= null;
531         IJavaProject javaProject= fCu.getJavaProject();
532         if (javaProject != null)
533             project= javaProject.getElementName();
534         int flags= JavaRefactoringDescriptor.JAR_REFACTORING | JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
535         if (JdtFlags.getVisibilityCode(fVisibility) != Modifier.PRIVATE)
536             flags|= RefactoringDescriptor.STRUCTURAL_CHANGE;
537         String JavaDoc pattern= ""; //$NON-NLS-1$
538
try {
539             pattern= BindingLabelProvider.getBindingLabel(getContainingTypeBinding(), JavaElementLabels.ALL_FULLY_QUALIFIED) + "."; //$NON-NLS-1$
540
} catch (JavaModelException exception) {
541             JavaPlugin.log(exception);
542         }
543         final String JavaDoc expression= ASTNodes.asString(fSelectedExpression.getAssociatedExpression());
544         final String JavaDoc description= Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_descriptor_description_short, fConstantName);
545         final String JavaDoc header= Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_descriptor_description, new String JavaDoc[] { pattern + fConstantName, expression});
546         final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
547         comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_constant_name_pattern, fConstantName));
548         comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_constant_expression_pattern, expression));
549         String JavaDoc visibility= fVisibility;
550         if ("".equals(visibility)) //$NON-NLS-1$
551
visibility= RefactoringCoreMessages.ExtractConstantRefactoring_default_visibility;
552         comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractConstantRefactoring_visibility_pattern, visibility));
553         if (fReplaceAllOccurrences)
554             comment.addSetting(RefactoringCoreMessages.ExtractConstantRefactoring_replace_occurrences);
555         if (fQualifyReferencesWithDeclaringClassName)
556             comment.addSetting(RefactoringCoreMessages.ExtractConstantRefactoring_qualify_references);
557         final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.EXTRACT_CONSTANT, project, description, comment.asString(), arguments, flags);
558         arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fCu));
559         arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_NAME, fConstantName);
560         arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION, new Integer JavaDoc(fSelectionStart).toString() + " " + new Integer JavaDoc(fSelectionLength).toString()); //$NON-NLS-1$
561
arguments.put(ATTRIBUTE_REPLACE, Boolean.valueOf(fReplaceAllOccurrences).toString());
562         arguments.put(ATTRIBUTE_QUALIFY, Boolean.valueOf(fQualifyReferencesWithDeclaringClassName).toString());
563         arguments.put(ATTRIBUTE_VISIBILITY, new Integer JavaDoc(JdtFlags.getVisibilityCode(fVisibility)).toString());
564         return new RefactoringDescriptorChange(descriptor, RefactoringCoreMessages.ExtractConstantRefactoring_name, new Change[] { fChange});
565     }
566
567     private void replaceExpressionsWithConstant() throws JavaModelException {
568         ASTRewrite astRewrite= fCuRewrite.getASTRewrite();
569         AST ast= astRewrite.getAST();
570         
571         IASTFragment[] fragmentsToReplace= getFragmentsToReplace();
572         for (int i= 0; i < fragmentsToReplace.length; i++) {
573             IASTFragment fragment= fragmentsToReplace[i];
574             
575             SimpleName ref= ast.newSimpleName(fConstantName);
576             Name replacement= ref;
577             if (qualifyReferencesWithDeclaringClassName()) {
578                 replacement= ast.newQualifiedName(ast.newSimpleName(getContainingTypeBinding().getName()), ref);
579             }
580             TextEditGroup description= fCuRewrite.createGroupDescription(RefactoringCoreMessages.ExtractConstantRefactoring_replace);
581             
582             fragment.replace(astRewrite, replacement, description);
583             if (fLinkedProposalModel != null)
584                 fLinkedProposalModel.getPositionGroup(KEY_NAME, true).addPosition(astRewrite.track(ref), false);
585         }
586     }
587     
588     private void computeConstantDeclarationLocation() throws JavaModelException {
589         if (isDeclarationLocationComputed())
590             return;
591
592         BodyDeclaration lastStaticDependency= null;
593         Iterator JavaDoc decls= getBodyDeclarations();
594         
595         Assert.isTrue(decls.hasNext()); /* Admissible selected expressions must occur
596                                            within a body declaration. Thus, the
597                                            class/interface in which such an expression occurs
598                                            must have at least one body declaration */

599         
600         while (decls.hasNext()) {
601             BodyDeclaration decl= (BodyDeclaration) decls.next();
602             
603             int modifiers;
604             if (decl instanceof FieldDeclaration)
605                 modifiers= ((FieldDeclaration) decl).getModifiers();
606             else if (decl instanceof Initializer)
607                 modifiers= ((Initializer) decl).getModifiers();
608             else {
609                 continue; /* this declaration is not a field declaration
610                               or initializer, so the placement of the constant
611                               declaration relative to it does not matter */

612             }
613             
614             if (Modifier.isStatic(modifiers) && depends(getSelectedExpression(), decl))
615                 lastStaticDependency= decl;
616         }
617         
618         if(lastStaticDependency == null)
619             fInsertFirst= true;
620         else
621             fToInsertAfter= lastStaticDependency;
622     }
623     
624     /* bd is a static field declaration or static initializer */
625     private static boolean depends(IExpressionFragment selected, BodyDeclaration bd) {
626         /* We currently consider selected to depend on bd only if db includes a declaration
627          * of a static field on which selected depends.
628          *
629          * A more accurate strategy might be to also check if bd contains (or is) a
630          * static initializer containing code which changes the value of a static field on
631          * which selected depends. However, if a static is written to multiple times within
632          * during class initialization, it is difficult to predict which value should be used.
633          * This would depend on which value is used by expressions instances for which the new
634          * constant will be substituted, and there may be many of these; in each, the
635          * static field in question may have taken on a different value (if some of these uses
636          * occur within static initializers).
637          */

638         
639         if(bd instanceof FieldDeclaration) {
640             FieldDeclaration fieldDecl = (FieldDeclaration) bd;
641             for(Iterator JavaDoc fragments = fieldDecl.fragments().iterator(); fragments.hasNext();) {
642                 VariableDeclarationFragment fragment = (VariableDeclarationFragment) fragments.next();
643                 SimpleName staticFieldName = fragment.getName();
644                 if(selected.getSubFragmentsMatching(ASTFragmentFactory.createFragmentForFullSubtree(staticFieldName)).length != 0)
645                     return true;
646             }
647         }
648         return false;
649     }
650
651     private boolean isDeclarationLocationComputed() {
652         return fInsertFirst == true || fToInsertAfter != null;
653     }
654     
655     private boolean insertFirst() throws JavaModelException {
656         if(!isDeclarationLocationComputed())
657             computeConstantDeclarationLocation();
658         return fInsertFirst;
659     }
660     
661     private BodyDeclaration getNodeToInsertConstantDeclarationAfter() throws JavaModelException {
662         if(!isDeclarationLocationComputed())
663             computeConstantDeclarationLocation();
664         return fToInsertAfter;
665     }
666     
667     private Iterator JavaDoc getBodyDeclarations() throws JavaModelException {
668         if(fBodyDeclarations == null)
669             fBodyDeclarations= getContainingTypeDeclarationNode().bodyDeclarations();
670         return fBodyDeclarations.iterator();
671     }
672
673     private String JavaDoc getConstantTypeName() throws JavaModelException {
674         return ASTNodes.asString(getConstantType());
675     }
676
677     private static boolean isStaticFieldOrStaticInitializer(BodyDeclaration node) {
678         if(node instanceof MethodDeclaration || node instanceof AbstractTypeDeclaration)
679             return false;
680         
681         int modifiers;
682         if(node instanceof FieldDeclaration) {
683             modifiers = ((FieldDeclaration) node).getModifiers();
684         } else if(node instanceof Initializer) {
685             modifiers = ((Initializer) node).getModifiers();
686         } else {
687             Assert.isTrue(false);
688             return false;
689         }
690         
691         if(!Modifier.isStatic(modifiers))
692             return false;
693         
694         return true;
695     }
696     
697     /*
698      * Elements returned by next() are BodyDeclaration
699      * instances.
700      */

701     private Iterator JavaDoc getReplacementScope() throws JavaModelException {
702         boolean declPredecessorReached= false;
703         
704         Collection JavaDoc scope= new ArrayList JavaDoc();
705         for(Iterator JavaDoc bodyDeclarations = getBodyDeclarations(); bodyDeclarations.hasNext();) {
706             BodyDeclaration bodyDeclaration= (BodyDeclaration) bodyDeclarations.next();
707             
708             if(bodyDeclaration == getNodeToInsertConstantDeclarationAfter())
709                 declPredecessorReached= true;
710             
711             if(insertFirst() || declPredecessorReached || !isStaticFieldOrStaticInitializer(bodyDeclaration))
712                 scope.add(bodyDeclaration);
713         }
714         return scope.iterator();
715     }
716
717     private IASTFragment[] getFragmentsToReplace() throws JavaModelException {
718         List JavaDoc toReplace = new ArrayList JavaDoc();
719         if (fReplaceAllOccurrences) {
720             Iterator JavaDoc replacementScope = getReplacementScope();
721             while(replacementScope.hasNext()) {
722                 BodyDeclaration bodyDecl = (BodyDeclaration) replacementScope.next();
723                 IASTFragment[] allMatches= ASTFragmentFactory.createFragmentForFullSubtree(bodyDecl).getSubFragmentsMatching(getSelectedExpression());
724                 IASTFragment[] replaceableMatches = retainOnlyReplacableMatches(allMatches);
725                 for(int i = 0; i < replaceableMatches.length; i++)
726                     toReplace.add(replaceableMatches[i]);
727             }
728         } else if (canReplace(getSelectedExpression()))
729             toReplace.add(getSelectedExpression());
730         return (IASTFragment[]) toReplace.toArray(new IASTFragment[toReplace.size()]);
731     }
732
733     // !! - like one in ExtractTempRefactoring
734
private static IASTFragment[] retainOnlyReplacableMatches(IASTFragment[] allMatches) {
735         List JavaDoc result= new ArrayList JavaDoc(allMatches.length);
736         for (int i= 0; i < allMatches.length; i++) {
737             if (canReplace(allMatches[i]))
738                 result.add(allMatches[i]);
739         }
740         return (IASTFragment[]) result.toArray(new IASTFragment[result.size()]);
741     }
742
743     // !! - like one in ExtractTempRefactoring
744
private static boolean canReplace(IASTFragment fragment) {
745         ASTNode node= fragment.getAssociatedNode();
746         ASTNode parent= node.getParent();
747         if (parent instanceof VariableDeclarationFragment) {
748             VariableDeclarationFragment vdf= (VariableDeclarationFragment) parent;
749             if (node.equals(vdf.getName()))
750                 return false;
751         }
752         if (parent instanceof ExpressionStatement)
753             return false;
754         if (parent instanceof SwitchCase)
755             return false;
756         return true;
757     }
758
759     private IExpressionFragment getSelectedExpression() throws JavaModelException {
760         if(fSelectedExpression != null)
761             return fSelectedExpression;
762         
763         IASTFragment selectedFragment= ASTFragmentFactory.createFragmentForSourceRange(new SourceRange(fSelectionStart, fSelectionLength), fCuRewrite.getRoot(), fCu);
764         
765         if (selectedFragment instanceof IExpressionFragment
766                 && ! Checks.isInsideJavadoc(selectedFragment.getAssociatedNode())) {
767             fSelectedExpression= (IExpressionFragment) selectedFragment;
768         }
769         
770         if (fSelectedExpression != null && Checks.isEnumCase(fSelectedExpression.getAssociatedExpression().getParent())) {
771             fSelectedExpression= null;
772         }
773         
774         return fSelectedExpression;
775     }
776
777     private AbstractTypeDeclaration getContainingTypeDeclarationNode() throws JavaModelException {
778         AbstractTypeDeclaration result= (AbstractTypeDeclaration) ASTNodes.getParent(getSelectedExpression().getAssociatedNode(), AbstractTypeDeclaration.class);
779         Assert.isNotNull(result);
780         return result;
781     }
782
783     private ITypeBinding getContainingTypeBinding() throws JavaModelException {
784         ITypeBinding result= getContainingTypeDeclarationNode().resolveBinding();
785         Assert.isNotNull(result);
786         return result;
787     }
788
789     public RefactoringStatus initialize(final RefactoringArguments arguments) {
790         if (arguments instanceof JavaRefactoringArguments) {
791             final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments;
792             final String JavaDoc selection= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION);
793             if (selection != null) {
794                 int offset= -1;
795                 int length= -1;
796                 final StringTokenizer JavaDoc tokenizer= new StringTokenizer JavaDoc(selection);
797                 if (tokenizer.hasMoreTokens())
798                     offset= Integer.valueOf(tokenizer.nextToken()).intValue();
799                 if (tokenizer.hasMoreTokens())
800                     length= Integer.valueOf(tokenizer.nextToken()).intValue();
801                 if (offset >= 0 && length >= 0) {
802                     fSelectionStart= offset;
803                     fSelectionLength= length;
804                 } else
805                     return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object JavaDoc[] { selection, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION}));
806             } else
807                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION));
808             final String JavaDoc handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT);
809             if (handle != null) {
810                 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
811                 if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT)
812                     return createInputFatalStatus(element, IJavaRefactorings.EXTRACT_CONSTANT);
813                 else
814                     fCu= (ICompilationUnit) element;
815             } else
816                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT));
817             final String JavaDoc visibility= extended.getAttribute(ATTRIBUTE_VISIBILITY);
818             if (visibility != null && !"".equals(visibility)) {//$NON-NLS-1$
819
int flag= 0;
820                 try {
821                     flag= Integer.parseInt(visibility);
822                 } catch (NumberFormatException JavaDoc exception) {
823                     return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_VISIBILITY));
824                 }
825                 fVisibility= JdtFlags.getVisibilityString(flag);
826             }
827             final String JavaDoc name= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_NAME);
828             if (name != null && !"".equals(name)) //$NON-NLS-1$
829
fConstantName= name;
830             else
831                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_NAME));
832             final String JavaDoc replace= extended.getAttribute(ATTRIBUTE_REPLACE);
833             if (replace != null) {
834                 fReplaceAllOccurrences= Boolean.valueOf(replace).booleanValue();
835             } else
836                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REPLACE));
837             final String JavaDoc declareFinal= extended.getAttribute(ATTRIBUTE_QUALIFY);
838             if (declareFinal != null) {
839                 fQualifyReferencesWithDeclaringClassName= Boolean.valueOf(declareFinal).booleanValue();
840             } else
841                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_QUALIFY));
842         } else
843             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
844         return new RefactoringStatus();
845     }
846 }
847
Popular Tags