KickJava   Java API By Example, From Geeks To Geeks.

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


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  * Dmitry Stalnov (dstalnov@fusionone.com) - contributed fix for
11  * o bug "inline method - doesn't handle implicit cast" (see
12  * https://bugs.eclipse.org/bugs/show_bug.cgi?id=24941).
13  * o inline call that is used in a field initializer
14  * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=38137)
15  * o inline call a field initializer: could detect self reference
16  * (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=44417)
17  *******************************************************************************/

18 package org.eclipse.jdt.internal.corext.refactoring.code;
19
20 import java.util.ArrayList JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.List JavaDoc;
24
25 import org.eclipse.text.edits.MalformedTreeException;
26 import org.eclipse.text.edits.MultiTextEdit;
27 import org.eclipse.text.edits.RangeMarker;
28 import org.eclipse.text.edits.TextEdit;
29 import org.eclipse.text.edits.TextEditProcessor;
30 import org.eclipse.text.edits.UndoEdit;
31
32 import org.eclipse.core.runtime.Assert;
33 import org.eclipse.core.runtime.CoreException;
34
35 import org.eclipse.jface.text.BadLocationException;
36 import org.eclipse.jface.text.Document;
37 import org.eclipse.jface.text.IDocument;
38 import org.eclipse.jface.text.IRegion;
39 import org.eclipse.jface.text.Region;
40 import org.eclipse.jface.text.TextUtilities;
41
42 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
43
44 import org.eclipse.jdt.core.ITypeRoot;
45 import org.eclipse.jdt.core.JavaModelException;
46 import org.eclipse.jdt.core.dom.ASTNode;
47 import org.eclipse.jdt.core.dom.ASTVisitor;
48 import org.eclipse.jdt.core.dom.Block;
49 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
50 import org.eclipse.jdt.core.dom.CompilationUnit;
51 import org.eclipse.jdt.core.dom.ConditionalExpression;
52 import org.eclipse.jdt.core.dom.Expression;
53 import org.eclipse.jdt.core.dom.FieldAccess;
54 import org.eclipse.jdt.core.dom.ForStatement;
55 import org.eclipse.jdt.core.dom.IBinding;
56 import org.eclipse.jdt.core.dom.IMethodBinding;
57 import org.eclipse.jdt.core.dom.ITypeBinding;
58 import org.eclipse.jdt.core.dom.IVariableBinding;
59 import org.eclipse.jdt.core.dom.IfStatement;
60 import org.eclipse.jdt.core.dom.MethodDeclaration;
61 import org.eclipse.jdt.core.dom.MethodInvocation;
62 import org.eclipse.jdt.core.dom.Modifier;
63 import org.eclipse.jdt.core.dom.Name;
64 import org.eclipse.jdt.core.dom.ReturnStatement;
65 import org.eclipse.jdt.core.dom.SimpleName;
66 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
67 import org.eclipse.jdt.core.dom.Statement;
68 import org.eclipse.jdt.core.dom.ThisExpression;
69 import org.eclipse.jdt.core.dom.WhileStatement;
70 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
71 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
72
73 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
74 import org.eclipse.jdt.internal.corext.dom.Bindings;
75 import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
76 import org.eclipse.jdt.internal.corext.refactoring.code.SourceAnalyzer.NameData;
77 import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
78 import org.eclipse.jdt.internal.corext.util.Strings;
79
80 import org.eclipse.jdt.internal.ui.JavaPlugin;
81
82 /**
83  * A SourceProvider encapsulates a piece of code (source) and the logic
84  * to inline it into given CallContexts.
85  */

86 public class SourceProvider {
87
88     private ITypeRoot fTypeRoot;
89     private IDocument fDocument;
90     private MethodDeclaration fDeclaration;
91     private SourceAnalyzer fAnalyzer;
92     private boolean fMustEvalReturnedExpression;
93     private boolean fReturnValueNeedsLocalVariable;
94     private List JavaDoc fReturnExpressions;
95     private IDocument fSource;
96     
97     private static final int EXPRESSION_MODE= 1;
98     private static final int STATEMENT_MODE= 2;
99     private static final int RETURN_STATEMENT_MODE= 3;
100     private int fMarkerMode;
101     
102     
103     private class ReturnAnalyzer extends ASTVisitor {
104         public boolean visit(ReturnStatement node) {
105             Expression expression= node.getExpression();
106             if (!(ASTNodes.isLiteral(expression) || expression instanceof Name)) {
107                 fMustEvalReturnedExpression= true;
108             }
109             if (Invocations.isInvocation(expression) || expression instanceof ClassInstanceCreation) {
110                 fReturnValueNeedsLocalVariable= false;
111             }
112             fReturnExpressions.add(expression);
113             return false;
114         }
115     }
116
117     public SourceProvider(ITypeRoot typeRoot, MethodDeclaration declaration) {
118         super();
119         fTypeRoot= typeRoot;
120         fDeclaration= declaration;
121         List JavaDoc parameters= fDeclaration.parameters();
122         for (Iterator JavaDoc iter= parameters.iterator(); iter.hasNext();) {
123             SingleVariableDeclaration element= (SingleVariableDeclaration)iter.next();
124             ParameterData data= new ParameterData(element);
125             element.setProperty(ParameterData.PROPERTY, data);
126         }
127         fAnalyzer= new SourceAnalyzer(fTypeRoot, fDeclaration);
128         fReturnValueNeedsLocalVariable= true;
129         fReturnExpressions= new ArrayList JavaDoc();
130     }
131     
132     /**
133      * TODO: unit's source does not match contents of source document and declaration node.
134      */

135     public SourceProvider(ITypeRoot typeRoot, IDocument source, MethodDeclaration declaration) {
136         this(typeRoot, declaration);
137         fSource= source;
138     }
139
140     public RefactoringStatus checkActivation() throws JavaModelException {
141         return fAnalyzer.checkActivation();
142     }
143     
144     public void initialize() throws JavaModelException {
145         fDocument= fSource == null ? new Document(fTypeRoot.getBuffer().getContents()) : fSource;
146         fAnalyzer.initialize();
147         if (hasReturnValue()) {
148             ASTNode last= getLastStatement();
149             if (last != null) {
150                 ReturnAnalyzer analyzer= new ReturnAnalyzer();
151                 last.accept(analyzer);
152             }
153         }
154     }
155
156     public boolean isExecutionFlowInterrupted() {
157         return fAnalyzer.isExecutionFlowInterrupted();
158     }
159
160     static class VariableReferenceFinder extends ASTVisitor {
161         private boolean fResult;
162         private IVariableBinding fBinding;
163         public VariableReferenceFinder(IVariableBinding binding) {
164             fBinding= binding;
165         }
166         public boolean getResult() {
167             return fResult;
168         }
169         public boolean visit(SimpleName node) {
170             if(!fResult) {
171                 fResult= Bindings.equals(fBinding, node.resolveBinding());
172             }
173             return false;
174         }
175     }
176
177     /**
178      * Checks whether variable is referenced by the method declaration or not.
179      *
180      * @param binding binding of variable to check.
181      * @return <code>true</code> if variable is referenced by the method, otherwise <code>false</code>
182      */

183     public boolean isVariableReferenced(IVariableBinding binding) {
184         VariableReferenceFinder finder= new VariableReferenceFinder(binding);
185         fDeclaration.accept(finder);
186         return finder.getResult();
187     }
188
189     public boolean hasReturnValue() {
190         IMethodBinding binding= fDeclaration.resolveBinding();
191         return binding.getReturnType() != fDeclaration.getAST().resolveWellKnownType("void"); //$NON-NLS-1$
192
}
193     
194     // returns true if the declaration has a vararg and
195
// the body contains an array access to the vararg
196
public boolean hasArrayAccess() {
197         return fAnalyzer.hasArrayAccess();
198     }
199     
200     public boolean hasSuperMethodInvocation() {
201         return fAnalyzer.hasSuperMethodInvocation();
202     }
203     
204     public boolean mustEvaluateReturnedExpression() {
205         return fMustEvalReturnedExpression;
206     }
207     
208     public boolean returnValueNeedsLocalVariable() {
209         return fReturnValueNeedsLocalVariable;
210     }
211     
212     public int getNumberOfStatements() {
213         return fDeclaration.getBody().statements().size();
214     }
215     
216     public boolean isSimpleFunction() {
217         List JavaDoc statements= fDeclaration.getBody().statements();
218         if (statements.size() != 1)
219             return false;
220         return statements.get(0) instanceof ReturnStatement;
221     }
222     
223     public boolean isLastStatementReturn() {
224         List JavaDoc statements= fDeclaration.getBody().statements();
225         if (statements.size() == 0)
226             return false;
227         return statements.get(statements.size() - 1) instanceof ReturnStatement;
228     }
229     
230     public boolean isDangligIf() {
231         List JavaDoc statements= fDeclaration.getBody().statements();
232         if (statements.size() != 1)
233             return false;
234         
235         Object JavaDoc statement= statements.get(0);
236         if (! (statement instanceof IfStatement))
237             return false;
238         
239         return ((IfStatement) statement).getElseStatement() == null;
240     }
241     
242     public MethodDeclaration getDeclaration() {
243         return fDeclaration;
244     }
245     
246     public String JavaDoc getMethodName() {
247         return fDeclaration.getName().getIdentifier();
248     }
249     
250     public ITypeBinding getReturnType() {
251         return fDeclaration.resolveBinding().getReturnType();
252     }
253     
254     public List JavaDoc getReturnExpressions() {
255         return fReturnExpressions;
256     }
257     
258     public boolean returnTypeMatchesReturnExpressions() {
259         ITypeBinding returnType= getReturnType();
260         for (Iterator JavaDoc iter= fReturnExpressions.iterator(); iter.hasNext();) {
261             Expression expression= (Expression)iter.next();
262             if (!Bindings.equals(returnType, expression.resolveTypeBinding()))
263                 return false;
264         }
265         return true;
266     }
267     
268     public ParameterData getParameterData(int index) {
269         SingleVariableDeclaration decl= (SingleVariableDeclaration)fDeclaration.parameters().get(index);
270         return (ParameterData)decl.getProperty(ParameterData.PROPERTY);
271     }
272     
273     public ITypeRoot getTypeRoot() {
274         return fTypeRoot;
275     }
276     
277     public boolean needsReturnedExpressionParenthesis() {
278         ASTNode last= getLastStatement();
279         if (last instanceof ReturnStatement) {
280             return ASTNodes.needsParentheses(((ReturnStatement)last).getExpression());
281         }
282         return false;
283     }
284     
285     public boolean returnsConditionalExpression() {
286         ASTNode last= getLastStatement();
287         if (last instanceof ReturnStatement) {
288             return ((ReturnStatement)last).getExpression() instanceof ConditionalExpression;
289         }
290         return false;
291     }
292     
293     public int getReceiversToBeUpdated() {
294         return fAnalyzer.getImplicitReceivers().size();
295     }
296     
297     public boolean isVarargs() {
298         return fDeclaration.isVarargs();
299     }
300     
301     public int getVarargIndex() {
302         return fDeclaration.parameters().size() - 1;
303     }
304     
305     public TextEdit getDeleteEdit() {
306         final ASTRewrite rewriter= ASTRewrite.create(fDeclaration.getAST());
307         rewriter.remove(fDeclaration, null);
308         return rewriter.rewriteAST(fDocument, fTypeRoot.getJavaProject().getOptions(true));
309     }
310     
311     public String JavaDoc[] getCodeBlocks(CallContext context) throws CoreException {
312         final ASTRewrite rewriter= ASTRewrite.create(fDeclaration.getAST());
313         replaceParameterWithExpression(rewriter, context.arguments);
314         updateImplicitReceivers(rewriter, context);
315         makeNamesUnique(rewriter, context.scope);
316         updateTypeReferences(rewriter, context);
317         updateStaticReferences(rewriter, context);
318         updateTypeVariables(rewriter, context);
319         updateMethodTypeVariable(rewriter, context);
320         
321         List JavaDoc ranges= null;
322         if (hasReturnValue()) {
323             if (context.callMode == ASTNode.RETURN_STATEMENT) {
324                 ranges= getStatementRanges();
325             } else {
326                 ranges= getExpressionRanges();
327             }
328         } else {
329             ASTNode last= getLastStatement();
330             if (last != null && last.getNodeType() == ASTNode.RETURN_STATEMENT) {
331                 ranges= getReturnStatementRanges();
332             } else {
333                 ranges= getStatementRanges();
334             }
335         }
336
337         final TextEdit dummy= rewriter.rewriteAST(fDocument, fTypeRoot.getJavaProject().getOptions(true));
338         int size= ranges.size();
339         RangeMarker[] markers= new RangeMarker[size];
340         for (int i= 0; i < markers.length; i++) {
341             IRegion range= (IRegion)ranges.get(i);
342             markers[i]= new RangeMarker(range.getOffset(), range.getLength());
343         }
344         int split;
345         if (size <= 1) {
346             split= Integer.MAX_VALUE;
347         } else {
348             IRegion region= (IRegion)ranges.get(0);
349             split= region.getOffset() + region.getLength();
350         }
351         TextEdit[] edits= dummy.removeChildren();
352         for (int i= 0; i < edits.length; i++) {
353             TextEdit edit= edits[i];
354             int pos= edit.getOffset() >= split ? 1 : 0;
355             markers[pos].addChild(edit);
356         }
357         MultiTextEdit root= new MultiTextEdit(0, fDocument.getLength());
358         root.addChildren(markers);
359         
360         try {
361             TextEditProcessor processor= new TextEditProcessor(fDocument, root, TextEdit.CREATE_UNDO | TextEdit.UPDATE_REGIONS);
362             UndoEdit undo= processor.performEdits();
363             String JavaDoc[] result= getBlocks(markers);
364             // It is faster to undo the changes than coping the buffer over and over again.
365
processor= new TextEditProcessor(fDocument, undo, TextEdit.UPDATE_REGIONS);
366             processor.performEdits();
367             return result;
368         } catch (MalformedTreeException exception) {
369             JavaPlugin.log(exception);
370         } catch (BadLocationException exception) {
371             JavaPlugin.log(exception);
372         }
373         return new String JavaDoc[] {};
374     }
375
376     private void replaceParameterWithExpression(ASTRewrite rewriter, String JavaDoc[] expressions) {
377         for (int i= 0; i < expressions.length; i++) {
378             String JavaDoc expression= expressions[i];
379             ParameterData parameter= getParameterData(i);
380             List JavaDoc references= parameter.references();
381             for (Iterator JavaDoc iter= references.iterator(); iter.hasNext();) {
382                 ASTNode element= (ASTNode) iter.next();
383                 ASTNode newNode= rewriter.createStringPlaceholder(expression, element.getNodeType());
384                 rewriter.replace(element, newNode, null);
385             }
386         }
387     }
388
389     private void makeNamesUnique(ASTRewrite rewriter, CodeScopeBuilder.Scope scope) {
390         Collection JavaDoc usedCalleeNames= fAnalyzer.getUsedNames();
391         for (Iterator JavaDoc iter= usedCalleeNames.iterator(); iter.hasNext();) {
392             SourceAnalyzer.NameData nd= (SourceAnalyzer.NameData) iter.next();
393             if (scope.isInUse(nd.getName())) {
394                 String JavaDoc newName= scope.createName(nd.getName(), true);
395                 List JavaDoc references= nd.references();
396                 for (Iterator JavaDoc refs= references.iterator(); refs.hasNext();) {
397                     SimpleName element= (SimpleName) refs.next();
398                     ASTNode newNode= rewriter.createStringPlaceholder(newName, ASTNode.METHOD_INVOCATION);
399                     rewriter.replace(element, newNode, null);
400                 }
401             }
402         }
403     }
404     
405     private void updateImplicitReceivers(ASTRewrite rewriter, CallContext context) {
406         if (context.receiver == null)
407             return;
408         List JavaDoc implicitReceivers= fAnalyzer.getImplicitReceivers();
409         for (Iterator JavaDoc iter= implicitReceivers.iterator(); iter.hasNext();) {
410             ASTNode node= (ASTNode)iter.next();
411             if (node instanceof MethodInvocation) {
412                 final MethodInvocation inv= (MethodInvocation)node;
413                 rewriter.set(inv, MethodInvocation.EXPRESSION_PROPERTY, createReceiver(rewriter, context, (IMethodBinding)inv.getName().resolveBinding()), null);
414             } else if (node instanceof ClassInstanceCreation) {
415                 final ClassInstanceCreation inst= (ClassInstanceCreation)node;
416                 rewriter.set(inst, ClassInstanceCreation.EXPRESSION_PROPERTY, createReceiver(rewriter, context, inst.resolveConstructorBinding()), null);
417             } else if (node instanceof ThisExpression) {
418                 rewriter.replace(node, rewriter.createStringPlaceholder(context.receiver, ASTNode.METHOD_INVOCATION), null);
419             } else if (node instanceof FieldAccess) {
420                 final FieldAccess access= (FieldAccess)node;
421                 rewriter.set(access, FieldAccess.EXPRESSION_PROPERTY, createReceiver(rewriter, context, access.resolveFieldBinding()), null);
422             } else if (node instanceof SimpleName && ((SimpleName)node).resolveBinding() instanceof IVariableBinding) {
423                 IVariableBinding vb= (IVariableBinding)((SimpleName)node).resolveBinding();
424                 if (vb.isField()) {
425                     Expression receiver= createReceiver(rewriter, context, vb);
426                     if (receiver != null) {
427                         FieldAccess access= node.getAST().newFieldAccess();
428                         ASTNode target= rewriter.createMoveTarget(node);
429                         access.setName((SimpleName)target);
430                         access.setExpression(receiver);
431                         rewriter.replace(node, access, null);
432                     }
433                 }
434             }
435         }
436     }
437     
438     private void updateTypeReferences(ASTRewrite rewriter, CallContext context) {
439         ImportRewrite importer= context.importer;
440         for (Iterator JavaDoc iter= fAnalyzer.getTypesToImport().iterator(); iter.hasNext();) {
441             Name element= (Name)iter.next();
442             ITypeBinding binding= ASTNodes.getTypeBinding(element);
443             if (binding != null && !binding.isLocal()) {
444                 // We have collected names not types. So we have to import
445
// the declaration type if we reference a parameterized type
446
// since we have an entry for every name node (e.g. one for
447
// Vector and one for Integer in Vector<Integer>.
448
if (binding.isParameterizedType()) {
449                     binding= binding.getTypeDeclaration();
450                 }
451                 String JavaDoc s= importer.addImport(binding);
452                 if (!ASTNodes.asString(element).equals(s)) {
453                     rewriter.replace(element, rewriter.createStringPlaceholder(s, ASTNode.SIMPLE_NAME), null);
454                 }
455             }
456         }
457     }
458     
459     private void updateStaticReferences(ASTRewrite rewriter, CallContext context) {
460         ImportRewrite importer= context.importer;
461         for (Iterator JavaDoc iter= fAnalyzer.getStaticsToImport().iterator(); iter.hasNext();) {
462             Name element= (Name)iter.next();
463             IBinding binding= element.resolveBinding();
464             if (binding != null) {
465                 String JavaDoc s= importer.addStaticImport(binding);
466                 if (!ASTNodes.asString(element).equals(s)) {
467                     rewriter.replace(element, rewriter.createStringPlaceholder(s, ASTNode.SIMPLE_NAME), null);
468                 }
469             }
470         }
471         
472     }
473
474     private Expression createReceiver(ASTRewrite rewriter, CallContext context, IMethodBinding method) {
475         String JavaDoc receiver= getReceiver(context, method.getModifiers());
476         if (receiver == null)
477             return null;
478         return (Expression)rewriter.createStringPlaceholder(receiver, ASTNode.METHOD_INVOCATION);
479     }
480     
481     private Expression createReceiver(ASTRewrite rewriter, CallContext context, IVariableBinding field) {
482         String JavaDoc receiver= getReceiver(context, field.getModifiers());
483         if (receiver == null)
484             return null;
485         return (Expression)rewriter.createStringPlaceholder(receiver, ASTNode.SIMPLE_NAME);
486     }
487     
488     private String JavaDoc getReceiver(CallContext context, int modifiers) {
489         String JavaDoc receiver= context.receiver;
490         ITypeBinding invocationType= ASTNodes.getEnclosingType(context.invocation);
491         ITypeBinding sourceType= fDeclaration.resolveBinding().getDeclaringClass();
492         if (!context.receiverIsStatic && Modifier.isStatic(modifiers)) {
493             if ("this".equals(receiver) && invocationType != null && Bindings.equals(invocationType, sourceType)) { //$NON-NLS-1$
494
receiver= null;
495             } else {
496                 receiver= context.importer.addImport(sourceType);
497             }
498         }
499         return receiver;
500     }
501
502     private void updateTypeVariables(ASTRewrite rewriter, CallContext context) {
503         ITypeBinding type= context.getReceiverType();
504         if (type == null)
505             return;
506         rewriteReferences(rewriter, type.getTypeArguments(), fAnalyzer.getTypeParameterReferences());
507     }
508     
509     private void updateMethodTypeVariable(ASTRewrite rewriter, CallContext context) {
510         IMethodBinding method= Invocations.resolveBinding(context.invocation);
511         if (method == null)
512             return;
513         rewriteReferences(rewriter, method.getTypeArguments(), fAnalyzer.getMethodTypeParameterReferences());
514     }
515
516     private void rewriteReferences(ASTRewrite rewriter, ITypeBinding[] typeArguments, List JavaDoc typeParameterReferences) {
517         if (typeArguments.length == 0)
518             return;
519         Assert.isTrue(typeArguments.length == typeParameterReferences.size());
520         for (int i= 0; i < typeArguments.length; i++) {
521             SourceAnalyzer.NameData refData= (NameData)typeParameterReferences.get(i);
522             List JavaDoc references= refData.references();
523             String JavaDoc newName= typeArguments[i].getName();
524             for (Iterator JavaDoc iter= references.iterator(); iter.hasNext();) {
525                 SimpleName name= (SimpleName)iter.next();
526                 rewriter.replace(name, rewriter.createStringPlaceholder(newName, ASTNode.SIMPLE_NAME), null);
527             }
528         }
529     }
530     
531     private ASTNode getLastStatement() {
532         List JavaDoc statements= fDeclaration.getBody().statements();
533         if (statements.isEmpty())
534             return null;
535         return (ASTNode)statements.get(statements.size() - 1);
536     }
537
538     private List JavaDoc getReturnStatementRanges() {
539         fMarkerMode= RETURN_STATEMENT_MODE;
540         List JavaDoc result= new ArrayList JavaDoc(1);
541         List JavaDoc statements= fDeclaration.getBody().statements();
542         int size= statements.size();
543         if (size <= 1)
544             return result;
545         result.add(createRange(statements, size - 2));
546         return result;
547     }
548
549     private List JavaDoc getStatementRanges() {
550         fMarkerMode= STATEMENT_MODE;
551         List JavaDoc result= new ArrayList JavaDoc(1);
552         List JavaDoc statements= fDeclaration.getBody().statements();
553         int size= statements.size();
554         if (size == 0)
555             return result;
556         result.add(createRange(statements, size - 1));
557         return result;
558     }
559
560     private List JavaDoc getExpressionRanges() {
561         fMarkerMode= EXPRESSION_MODE;
562         List JavaDoc result= new ArrayList JavaDoc(2);
563         List JavaDoc statements= fDeclaration.getBody().statements();
564         ReturnStatement rs= null;
565         int size= statements.size();
566         ASTNode node;
567         switch (size) {
568             case 0:
569                 return result;
570             case 1:
571                 node= (ASTNode)statements.get(0);
572                 if (node.getNodeType() == ASTNode.RETURN_STATEMENT) {
573                     rs= (ReturnStatement)node;
574                 } else {
575                     result.add(new Region(node.getStartPosition(), node.getLength()));
576                 }
577                 break;
578             default: {
579                 node= (ASTNode)statements.get(size - 1);
580                 if (node.getNodeType() == ASTNode.RETURN_STATEMENT) {
581                     result.add(createRange(statements, size - 2));
582                     rs= (ReturnStatement)node;
583                 } else {
584                     result.add(createRange(statements, size - 1));
585                 }
586                 break;
587             }
588         }
589         if (rs != null) {
590             Expression exp= rs.getExpression();
591             result.add(new Region(exp.getStartPosition(), exp.getLength()));
592         }
593         return result;
594     }
595     
596     private IRegion createRange(List JavaDoc statements, int end) {
597         ASTNode first= (ASTNode)statements.get(0);
598         ASTNode root= first.getRoot();
599         if (root instanceof CompilationUnit) {
600             CompilationUnit unit= (CompilationUnit)root;
601             int start= unit.getExtendedStartPosition(first);
602             ASTNode last= (ASTNode)statements.get(end);
603             int length = unit.getExtendedStartPosition(last) - start + unit.getExtendedLength(last);
604             IRegion range= new Region(start, length);
605             return range;
606         } else {
607             int start= first.getStartPosition();
608             ASTNode last= (ASTNode)statements.get(end);
609             int length = last.getStartPosition() - start + last.getLength();
610             IRegion range= new Region(start, length);
611             return range;
612         }
613     }
614     
615     private String JavaDoc[] getBlocks(RangeMarker[] markers) throws BadLocationException {
616         String JavaDoc[] result= new String JavaDoc[markers.length];
617         for (int i= 0; i < markers.length; i++) {
618             RangeMarker marker= markers[i];
619             String JavaDoc content= fDocument.get(marker.getOffset(), marker.getLength());
620             String JavaDoc lines[]= Strings.convertIntoLines(content);
621             Strings.trimIndentation(lines, fTypeRoot.getJavaProject(), false);
622             if (fMarkerMode == STATEMENT_MODE && lines.length == 2 && isSingleControlStatementWithoutBlock()) {
623                 lines[1]= CodeFormatterUtil.createIndentString(1, fTypeRoot.getJavaProject()) + lines[1];
624             }
625             result[i]= Strings.concatenate(lines, TextUtilities.getDefaultLineDelimiter(fDocument));
626         }
627         return result;
628     }
629
630     private boolean isSingleControlStatementWithoutBlock() {
631         List JavaDoc statements= fDeclaration.getBody().statements();
632         int size= statements.size();
633         if (size != 1)
634             return false;
635         Statement statement= (Statement) statements.get(size - 1);
636         int nodeType= statement.getNodeType();
637         if (nodeType == ASTNode.IF_STATEMENT) {
638             IfStatement ifStatement= (IfStatement) statement;
639             return !(ifStatement.getThenStatement() instanceof Block)
640                 && !(ifStatement.getElseStatement() instanceof Block);
641         } else if (nodeType == ASTNode.FOR_STATEMENT) {
642             return !(((ForStatement)statement).getBody() instanceof Block);
643         } else if (nodeType == ASTNode.WHILE_STATEMENT) {
644             return !(((WhileStatement)statement).getBody() instanceof Block);
645         }
646         return false;
647     }
648 }
649
Popular Tags