KickJava   Java API By Example, From Geeks To Geeks.

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


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.HashMap JavaDoc;
14 import java.util.Map JavaDoc;
15 import java.util.StringTokenizer JavaDoc;
16
17 import org.eclipse.text.edits.MalformedTreeException;
18 import org.eclipse.text.edits.RangeMarker;
19 import org.eclipse.text.edits.TextEdit;
20 import org.eclipse.text.edits.TextEditGroup;
21
22 import org.eclipse.core.runtime.Assert;
23 import org.eclipse.core.runtime.CoreException;
24 import org.eclipse.core.runtime.IProgressMonitor;
25 import org.eclipse.core.runtime.SubProgressMonitor;
26
27 import org.eclipse.jface.text.BadLocationException;
28 import org.eclipse.jface.text.Document;
29 import org.eclipse.jface.text.IDocument;
30 import org.eclipse.jface.text.IRegion;
31 import org.eclipse.jface.text.TextUtilities;
32
33 import org.eclipse.ltk.core.refactoring.Change;
34 import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
35 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
36 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
37 import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
38 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
39
40 import org.eclipse.jdt.core.ICompilationUnit;
41 import org.eclipse.jdt.core.IJavaElement;
42 import org.eclipse.jdt.core.IJavaProject;
43 import org.eclipse.jdt.core.ISourceRange;
44 import org.eclipse.jdt.core.JavaModelException;
45 import org.eclipse.jdt.core.dom.ASTNode;
46 import org.eclipse.jdt.core.dom.ArrayCreation;
47 import org.eclipse.jdt.core.dom.ArrayInitializer;
48 import org.eclipse.jdt.core.dom.ArrayType;
49 import org.eclipse.jdt.core.dom.Assignment;
50 import org.eclipse.jdt.core.dom.CatchClause;
51 import org.eclipse.jdt.core.dom.CompilationUnit;
52 import org.eclipse.jdt.core.dom.Expression;
53 import org.eclipse.jdt.core.dom.FieldDeclaration;
54 import org.eclipse.jdt.core.dom.ForStatement;
55 import org.eclipse.jdt.core.dom.IMethodBinding;
56 import org.eclipse.jdt.core.dom.ITypeBinding;
57 import org.eclipse.jdt.core.dom.IVariableBinding;
58 import org.eclipse.jdt.core.dom.MethodDeclaration;
59 import org.eclipse.jdt.core.dom.MethodInvocation;
60 import org.eclipse.jdt.core.dom.ParenthesizedExpression;
61 import org.eclipse.jdt.core.dom.SimpleName;
62 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
63 import org.eclipse.jdt.core.dom.SuperMethodInvocation;
64 import org.eclipse.jdt.core.dom.Type;
65 import org.eclipse.jdt.core.dom.VariableDeclaration;
66 import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
67 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
68 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
69 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
70 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
71 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
72
73 import org.eclipse.jdt.internal.corext.SourceRange;
74 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
75 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
76 import org.eclipse.jdt.internal.corext.refactoring.Checks;
77 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor;
78 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
79 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
80 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
81 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
82 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange;
83 import org.eclipse.jdt.internal.corext.refactoring.rename.TempDeclarationFinder;
84 import org.eclipse.jdt.internal.corext.refactoring.rename.TempOccurrenceAnalyzer;
85 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
86 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
87 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
88 import org.eclipse.jdt.internal.corext.util.Messages;
89 import org.eclipse.jdt.internal.corext.util.Strings;
90
91 import org.eclipse.jdt.ui.JavaElementLabels;
92
93 import org.eclipse.jdt.internal.ui.JavaPlugin;
94 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
95
96 public class InlineTempRefactoring extends ScriptableRefactoring {
97
98     private int fSelectionStart;
99     private int fSelectionLength;
100     private ICompilationUnit fCu;
101     
102     //the following fields are set after the construction
103
private VariableDeclaration fVariableDeclaration;
104     private SimpleName[] fReferences;
105     private CompilationUnit fASTRoot;
106
107     /**
108      * Creates a new inline constant refactoring.
109      * @param unit the compilation unit, or <code>null</code> if invoked by scripting
110      * @param node compilation unit node, or <code>null</code>
111      * @param selectionStart
112      * @param selectionLength
113      */

114     public InlineTempRefactoring(ICompilationUnit unit, CompilationUnit node, int selectionStart, int selectionLength) {
115         Assert.isTrue(selectionStart >= 0);
116         Assert.isTrue(selectionLength >= 0);
117         fSelectionStart= selectionStart;
118         fSelectionLength= selectionLength;
119         fCu= unit;
120         
121         fASTRoot= node;
122         fVariableDeclaration= null;
123     }
124     
125     /**
126      * Creates a new inline constant refactoring.
127      * @param unit the compilation unit, or <code>null</code> if invoked by scripting
128      * @param selectionStart
129      * @param selectionLength
130      */

131     public InlineTempRefactoring(ICompilationUnit unit, int selectionStart, int selectionLength) {
132         this(unit, null, selectionStart, selectionLength);
133     }
134     
135     public InlineTempRefactoring(VariableDeclaration decl) {
136         fVariableDeclaration= decl;
137         ASTNode astRoot= decl.getRoot();
138         Assert.isTrue(astRoot instanceof CompilationUnit);
139         fASTRoot= (CompilationUnit) astRoot;
140         Assert.isTrue(fASTRoot.getJavaElement() instanceof ICompilationUnit);
141         
142         fSelectionStart= decl.getStartPosition();
143         fSelectionLength= decl.getLength();
144         fCu= (ICompilationUnit) fASTRoot.getJavaElement();
145     }
146     
147     public RefactoringStatus checkIfTempSelected() {
148         VariableDeclaration decl= getVariableDeclaration();
149         if (decl == null) {
150             return CodeRefactoringUtil.checkMethodSyntaxErrors(fSelectionStart, fSelectionLength, getASTRoot(), RefactoringCoreMessages.InlineTempRefactoring_select_temp);
151         }
152         if (decl.getParent() instanceof FieldDeclaration) {
153             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineTemRefactoring_error_message_fieldsCannotBeInlined);
154         }
155         return new RefactoringStatus();
156     }
157     
158     private CompilationUnit getASTRoot() {
159         if (fASTRoot == null) {
160             fASTRoot= RefactoringASTParser.parseWithASTProvider(fCu, true, null);
161         }
162         return fASTRoot;
163     }
164     
165     public VariableDeclaration getVariableDeclaration() {
166         if (fVariableDeclaration == null) {
167             fVariableDeclaration= TempDeclarationFinder.findTempDeclaration(getASTRoot(), fSelectionStart, fSelectionLength);
168         }
169         return fVariableDeclaration;
170     }
171     
172     /*
173      * @see IRefactoring#getName()
174      */

175     public String JavaDoc getName() {
176         return RefactoringCoreMessages.InlineTempRefactoring_name;
177     }
178     
179     /*
180      * @see Refactoring#checkActivation(IProgressMonitor)
181      */

182     public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
183         try {
184             pm.beginTask("", 1); //$NON-NLS-1$
185

186             RefactoringStatus result= Checks.validateModifiesFiles(ResourceUtil.getFiles(new ICompilationUnit[]{fCu}), getValidationContext());
187             if (result.hasFatalError())
188                 return result;
189                     
190             VariableDeclaration declaration= getVariableDeclaration();
191             
192             result.merge(checkSelection(declaration));
193             if (result.hasFatalError())
194                 return result;
195             
196             result.merge(checkInitializer(declaration));
197             return result;
198         } finally {
199             pm.done();
200         }
201     }
202
203     private RefactoringStatus checkInitializer(VariableDeclaration decl) {
204         if (decl.getInitializer().getNodeType() == ASTNode.NULL_LITERAL)
205             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineTemRefactoring_error_message_nulLiteralsCannotBeInlined);
206         return null;
207     }
208
209     private RefactoringStatus checkSelection(VariableDeclaration decl) {
210         ASTNode parent= decl.getParent();
211         if (parent instanceof MethodDeclaration) {
212             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineTempRefactoring_method_parameter);
213         }
214         
215         if (parent instanceof CatchClause) {
216             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineTempRefactoring_exceptions_declared);
217         }
218         
219         if (parent instanceof VariableDeclarationExpression && parent.getLocationInParent() == ForStatement.INITIALIZERS_PROPERTY) {
220             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InlineTempRefactoring_for_initializers);
221         }
222         
223         if (decl.getInitializer() == null) {
224             String JavaDoc message= Messages.format(RefactoringCoreMessages.InlineTempRefactoring_not_initialized, decl.getName().getIdentifier());
225             return RefactoringStatus.createFatalErrorStatus(message);
226         }
227                 
228         return checkAssignments(decl);
229     }
230     
231     private RefactoringStatus checkAssignments(VariableDeclaration decl) {
232         TempAssignmentFinder assignmentFinder= new TempAssignmentFinder(decl);
233         getASTRoot().accept(assignmentFinder);
234         if (!assignmentFinder.hasAssignments())
235             return new RefactoringStatus();
236         ASTNode firstAssignment= assignmentFinder.getFirstAssignment();
237         int start= firstAssignment.getStartPosition();
238         int length= firstAssignment.getLength();
239         ISourceRange range= new SourceRange(start, length);
240         RefactoringStatusContext context= JavaStatusContext.create(fCu, range);
241         String JavaDoc message= Messages.format(RefactoringCoreMessages.InlineTempRefactoring_assigned_more_once, decl.getName().getIdentifier());
242         return RefactoringStatus.createFatalErrorStatus(message, context);
243     }
244     
245     /*
246      * @see Refactoring#checkInput(IProgressMonitor)
247      */

248     public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
249         try {
250             pm.beginTask("", 1); //$NON-NLS-1$
251
return new RefactoringStatus();
252         } finally {
253             pm.done();
254         }
255     }
256     
257     //----- changes
258

259     public Change createChange(IProgressMonitor pm) throws CoreException {
260         try {
261             pm.beginTask(RefactoringCoreMessages.InlineTempRefactoring_preview, 2);
262             final Map JavaDoc arguments= new HashMap JavaDoc();
263             String JavaDoc project= null;
264             IJavaProject javaProject= fCu.getJavaProject();
265             if (javaProject != null)
266                 project= javaProject.getElementName();
267             
268             final IVariableBinding binding= getVariableDeclaration().resolveBinding();
269             String JavaDoc text= null;
270             final IMethodBinding method= binding.getDeclaringMethod();
271             if (method != null)
272                 text= BindingLabelProvider.getBindingLabel(method, JavaElementLabels.ALL_FULLY_QUALIFIED);
273             else
274                 text= '{' + JavaElementLabels.ELLIPSIS_STRING + '}';
275             final String JavaDoc description= Messages.format(RefactoringCoreMessages.InlineTempRefactoring_descriptor_description_short, binding.getName());
276             final String JavaDoc header= Messages.format(RefactoringCoreMessages.InlineTempRefactoring_descriptor_description, new String JavaDoc[] { BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED), text});
277             final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
278             comment.addSetting(Messages.format(RefactoringCoreMessages.InlineTempRefactoring_original_pattern, BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED)));
279             final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.INLINE_LOCAL_VARIABLE, project, description, comment.asString(), arguments, RefactoringDescriptor.NONE);
280             arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fCu));
281             arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION, String.valueOf(fSelectionStart) + ' ' + String.valueOf(fSelectionLength));
282             
283             CompilationUnitRewrite cuRewrite= new CompilationUnitRewrite(fCu, fASTRoot);
284             
285             inlineTemp(cuRewrite);
286             removeTemp(cuRewrite);
287             
288             final CompilationUnitChange result= cuRewrite.createChange(RefactoringCoreMessages.InlineTempRefactoring_inline, false, new SubProgressMonitor(pm, 1));
289             result.setDescriptor(new RefactoringChangeDescriptor(descriptor));
290             return result;
291         } finally {
292             pm.done();
293         }
294     }
295
296     private void inlineTemp(CompilationUnitRewrite cuRewrite) throws JavaModelException {
297         SimpleName[] references= getReferences();
298
299         TextEditGroup groupDesc= cuRewrite.createGroupDescription(RefactoringCoreMessages.InlineTempRefactoring_inline_edit_name);
300         ASTRewrite rewrite= cuRewrite.getASTRewrite();
301
302         for (int i= 0; i < references.length; i++){
303             SimpleName curr= references[i];
304             ASTNode initializerCopy= getInitializerSource(cuRewrite, curr);
305             rewrite.replace(curr, initializerCopy, groupDesc);
306         }
307     }
308     
309     private boolean needsBrackets(SimpleName name, VariableDeclaration variableDeclaration) {
310         Expression initializer= variableDeclaration.getInitializer();
311         if (initializer instanceof Assignment) //for esthetic reasons
312
return true;
313             
314         return ASTNodes.substituteMustBeParenthesized(initializer, name);
315     }
316     
317
318     private void removeTemp(CompilationUnitRewrite cuRewrite) throws JavaModelException {
319         VariableDeclaration variableDeclaration= getVariableDeclaration();
320         TextEditGroup groupDesc= cuRewrite.createGroupDescription(RefactoringCoreMessages.InlineTempRefactoring_remove_edit_name);
321         ASTNode parent= variableDeclaration.getParent();
322         ASTRewrite rewrite= cuRewrite.getASTRewrite();
323         if (parent instanceof VariableDeclarationStatement && ((VariableDeclarationStatement) parent).fragments().size() == 1) {
324             rewrite.remove(parent, groupDesc);
325         } else {
326             rewrite.remove(variableDeclaration, groupDesc);
327         }
328     }
329     
330     private Expression getInitializerSource(CompilationUnitRewrite rewrite, SimpleName reference) throws JavaModelException {
331         Expression copy= getModifiedInitializerSource(rewrite, reference);
332         boolean brackets= needsBrackets(reference, getVariableDeclaration());
333         if (brackets) {
334             ParenthesizedExpression parentExpr= rewrite.getAST().newParenthesizedExpression();
335             parentExpr.setExpression(copy);
336             return parentExpr;
337         }
338         return copy;
339     }
340     
341     private Expression getModifiedInitializerSource(CompilationUnitRewrite rewrite, SimpleName reference) throws JavaModelException {
342         VariableDeclaration varDecl= getVariableDeclaration();
343         Expression initializer= varDecl.getInitializer();
344         
345         ASTNode referenceContext= reference.getParent();
346         if (isInvocation(initializer)) {
347             if (Invocations.isResolvedTypeInferredFromExpectedType(initializer)) {
348                 if (! (referenceContext instanceof VariableDeclarationFragment
349                         || referenceContext instanceof SingleVariableDeclaration
350                         || referenceContext instanceof Assignment)) {
351                     IMethodBinding methodBinding= Invocations.resolveBinding(initializer);
352                     ITypeBinding[] typeArguments= methodBinding.getTypeArguments();
353                     Type[] typeArgumentNodes= new Type[typeArguments.length];
354                     for (int i= 0; i < typeArguments.length; i++) {
355                         typeArgumentNodes[i]= rewrite.getImportRewrite().addImport(typeArguments[i], rewrite.getAST());
356                     }
357                     String JavaDoc newSource= createParameterizedInvocation(initializer, typeArgumentNodes);
358                     return (Expression) rewrite.getASTRewrite().createStringPlaceholder(newSource, initializer.getNodeType());
359                 }
360             }
361         }
362         
363         Expression copy= (Expression) rewrite.getASTRewrite().createCopyTarget(initializer);
364         if (initializer instanceof ArrayInitializer && ASTNodes.getDimensions(varDecl) > 0) {
365             ArrayType newType= (ArrayType) ASTNodeFactory.newType(rewrite.getAST(), varDecl);
366             
367             ArrayCreation newArrayCreation= rewrite.getAST().newArrayCreation();
368             newArrayCreation.setType(newType);
369             newArrayCreation.setInitializer((ArrayInitializer) copy);
370             return newArrayCreation;
371         }
372         return copy;
373     }
374
375     private String JavaDoc createParameterizedInvocation(Expression invocation, Type[] typeArgumentNodes) throws JavaModelException {
376         ASTRewrite rewrite= ASTRewrite.create(invocation.getAST());
377         ListRewrite typeArgsRewrite= rewrite.getListRewrite(invocation, Invocations.getTypeArgumentsProperty(invocation));
378         for (int i= 0; i < typeArgumentNodes.length; i++) {
379             typeArgsRewrite.insertLast(typeArgumentNodes[i], null);
380         }
381         
382         IDocument document= new Document(fCu.getBuffer().getContents());
383         final RangeMarker marker= new RangeMarker(invocation.getStartPosition(), invocation.getLength());
384         IJavaProject project= fCu.getJavaProject();
385         TextEdit[] rewriteEdits= rewrite.rewriteAST(document, project.getOptions(true)).removeChildren();
386         marker.addChildren(rewriteEdits);
387         try {
388             marker.apply(document, TextEdit.UPDATE_REGIONS);
389             String JavaDoc rewrittenInitializer= document.get(marker.getOffset(), marker.getLength());
390             IRegion region= document.getLineInformation(document.getLineOfOffset(marker.getOffset()));
391             int oldIndent= Strings.computeIndentUnits(document.get(region.getOffset(), region.getLength()), project);
392             return Strings.changeIndent(rewrittenInitializer, oldIndent, project, "", TextUtilities.getDefaultLineDelimiter(document)); //$NON-NLS-1$
393
} catch (MalformedTreeException e) {
394             JavaPlugin.log(e);
395         } catch (BadLocationException e) {
396             JavaPlugin.log(e);
397         }
398         //fallback:
399
return fCu.getBuffer().getText(invocation.getStartPosition(), invocation.getLength());
400     }
401     
402     private static boolean isInvocation(Expression node) {
403         return node instanceof MethodInvocation || node instanceof SuperMethodInvocation;
404     }
405
406     public SimpleName[] getReferences() {
407         if (fReferences != null)
408             return fReferences;
409         TempOccurrenceAnalyzer analyzer= new TempOccurrenceAnalyzer(getVariableDeclaration(), false);
410         analyzer.perform();
411         fReferences= analyzer.getReferenceNodes();
412         return fReferences;
413     }
414
415     public RefactoringStatus initialize(final RefactoringArguments arguments) {
416         if (arguments instanceof JavaRefactoringArguments) {
417             final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments;
418             final String JavaDoc selection= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION);
419             if (selection != null) {
420                 int offset= -1;
421                 int length= -1;
422                 final StringTokenizer JavaDoc tokenizer= new StringTokenizer JavaDoc(selection);
423                 if (tokenizer.hasMoreTokens())
424                     offset= Integer.valueOf(tokenizer.nextToken()).intValue();
425                 if (tokenizer.hasMoreTokens())
426                     length= Integer.valueOf(tokenizer.nextToken()).intValue();
427                 if (offset >= 0 && length >= 0) {
428                     fSelectionStart= offset;
429                     fSelectionLength= length;
430                 } else
431                     return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object JavaDoc[] { selection, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION}));
432             } else
433                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION));
434             final String JavaDoc handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT);
435             if (handle != null) {
436                 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false);
437                 if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT)
438                     return createInputFatalStatus(element, IJavaRefactorings.INLINE_LOCAL_VARIABLE);
439                 else {
440                     fCu= (ICompilationUnit) element;
441                     if (checkIfTempSelected().hasFatalError())
442                         return createInputFatalStatus(element, IJavaRefactorings.INLINE_LOCAL_VARIABLE);
443                 }
444             } else
445                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT));
446         } else
447             return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
448         return new RefactoringStatus();
449     }
450 }
451
Popular Tags