KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > fix > ControlStatementsFix


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

11 package org.eclipse.jdt.internal.corext.fix;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.List JavaDoc;
15
16 import org.eclipse.text.edits.TextEditGroup;
17
18 import org.eclipse.core.runtime.CoreException;
19
20 import org.eclipse.jdt.core.dom.ASTNode;
21 import org.eclipse.jdt.core.dom.Block;
22 import org.eclipse.jdt.core.dom.ChildPropertyDescriptor;
23 import org.eclipse.jdt.core.dom.CompilationUnit;
24 import org.eclipse.jdt.core.dom.DoStatement;
25 import org.eclipse.jdt.core.dom.EnhancedForStatement;
26 import org.eclipse.jdt.core.dom.ForStatement;
27 import org.eclipse.jdt.core.dom.IfStatement;
28 import org.eclipse.jdt.core.dom.ReturnStatement;
29 import org.eclipse.jdt.core.dom.Statement;
30 import org.eclipse.jdt.core.dom.ThrowStatement;
31 import org.eclipse.jdt.core.dom.WhileStatement;
32 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
33
34 import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
35 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
36
37 import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
38
39 public class ControlStatementsFix extends AbstractFix {
40         
41     private final static class ControlStatementFinder extends GenericVisitor {
42         
43         private final List JavaDoc/*<IFixRewriteOperation>*/ fResult;
44         private final boolean fFindControlStatementsWithoutBlock;
45         private final boolean fRemoveUnnecessaryBlocks;
46         private final boolean fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow;
47         
48         public ControlStatementFinder(boolean findControlStatementsWithoutBlock,
49                 boolean removeUnnecessaryBlocks,
50                 boolean removeUnnecessaryBlocksOnlyWhenReturnOrThrow,
51                 List JavaDoc resultingCollection) {
52             
53             fFindControlStatementsWithoutBlock= findControlStatementsWithoutBlock;
54             fRemoveUnnecessaryBlocks= removeUnnecessaryBlocks;
55             fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow= removeUnnecessaryBlocksOnlyWhenReturnOrThrow;
56             fResult= resultingCollection;
57         }
58         
59         /* (non-Javadoc)
60          * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.DoStatement)
61          */

62         public boolean visit(DoStatement node) {
63             if (fFindControlStatementsWithoutBlock) {
64                 Statement doBody= node.getBody();
65                 if (!(doBody instanceof Block)) {
66                     fResult.add(new AddBlockOperation(DoStatement.BODY_PROPERTY, doBody, node));
67                 }
68             } else if (fRemoveUnnecessaryBlocks || fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow) {
69                 if (RemoveBlockOperation.satisfiesCleanUpPrecondition(node, DoStatement.BODY_PROPERTY, fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow)) {
70                     fResult.add(new RemoveBlockOperation(node, DoStatement.BODY_PROPERTY));
71                 }
72             }
73             return super.visit(node);
74         }
75
76         /* (non-Javadoc)
77          * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.ForStatement)
78          */

79         public boolean visit(ForStatement node) {
80             if (fFindControlStatementsWithoutBlock) {
81                 Statement forBody= node.getBody();
82                 if (!(forBody instanceof Block)) {
83                     fResult.add(new AddBlockOperation(ForStatement.BODY_PROPERTY, forBody, node));
84                 }
85             } else if (fRemoveUnnecessaryBlocks || fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow) {
86                 if (RemoveBlockOperation.satisfiesCleanUpPrecondition(node, ForStatement.BODY_PROPERTY, fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow)) {
87                     fResult.add(new RemoveBlockOperation(node, ForStatement.BODY_PROPERTY));
88                 }
89             }
90             return super.visit(node);
91         }
92         
93         /**
94          * {@inheritDoc}
95          */

96         public boolean visit(EnhancedForStatement node) {
97             if (fFindControlStatementsWithoutBlock) {
98                 Statement forBody= node.getBody();
99                 if (!(forBody instanceof Block)) {
100                     fResult.add(new AddBlockOperation(EnhancedForStatement.BODY_PROPERTY, forBody, node));
101                 }
102             } else if (fRemoveUnnecessaryBlocks || fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow) {
103                 if (RemoveBlockOperation.satisfiesCleanUpPrecondition(node, EnhancedForStatement.BODY_PROPERTY, fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow)) {
104                     fResult.add(new RemoveBlockOperation(node, EnhancedForStatement.BODY_PROPERTY));
105                 }
106             }
107             return super.visit(node);
108         }
109         
110         /* (non-Javadoc)
111          * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.IfStatement)
112          */

113         public boolean visit(IfStatement statement) {
114             if (fFindControlStatementsWithoutBlock) {
115                 Statement then= statement.getThenStatement();
116                 if (!(then instanceof Block)) {
117                     fResult.add(new AddBlockOperation(IfStatement.THEN_STATEMENT_PROPERTY, then, statement));
118                 }
119                 Statement elseStatement= statement.getElseStatement();
120                 if (elseStatement != null && !(elseStatement instanceof Block) && !(elseStatement instanceof IfStatement)) {
121                     fResult.add(new AddBlockOperation(IfStatement.ELSE_STATEMENT_PROPERTY, elseStatement, statement));
122                 }
123             } else if (fRemoveUnnecessaryBlocks || fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow) {
124                 if (RemoveBlockOperation.satisfiesCleanUpPrecondition(statement, IfStatement.THEN_STATEMENT_PROPERTY, fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow)) {
125                     fResult.add(new RemoveBlockOperation(statement, IfStatement.THEN_STATEMENT_PROPERTY));
126                 }
127                 if (!(statement.getElseStatement() instanceof IfStatement)) {
128                     if (RemoveBlockOperation.satisfiesCleanUpPrecondition(statement, IfStatement.ELSE_STATEMENT_PROPERTY, fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow)) {
129                         fResult.add(new RemoveBlockOperation(statement, IfStatement.ELSE_STATEMENT_PROPERTY));
130                     }
131                 }
132             }
133             return super.visit(statement);
134         }
135
136         /* (non-Javadoc)
137          * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.WhileStatement)
138          */

139         public boolean visit(WhileStatement node) {
140             if (fFindControlStatementsWithoutBlock) {
141                 Statement whileBody= node.getBody();
142                 if (!(whileBody instanceof Block)) {
143                     fResult.add(new AddBlockOperation(WhileStatement.BODY_PROPERTY, whileBody, node));
144                 }
145             } else if (fRemoveUnnecessaryBlocks || fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow) {
146                 if (RemoveBlockOperation.satisfiesCleanUpPrecondition(node, WhileStatement.BODY_PROPERTY, fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow))
147                     fResult.add(new RemoveBlockOperation(node, WhileStatement.BODY_PROPERTY));
148             }
149             return super.visit(node);
150         }
151
152     }
153     
154     private static class IfElseIterator {
155         
156         private IfStatement fCursor;
157         
158         public IfElseIterator(IfStatement item) {
159             fCursor= findStart(item);
160         }
161         
162         public IfStatement next() {
163             if (!hasNext())
164                 return null;
165             
166             IfStatement result= fCursor;
167             
168             if (fCursor.getElseStatement() instanceof IfStatement) {
169                 fCursor= (IfStatement)fCursor.getElseStatement();
170             } else {
171                 fCursor= null;
172             }
173             
174             return result;
175         }
176         
177         public boolean hasNext() {
178             return fCursor != null;
179         }
180
181         private IfStatement findStart(IfStatement item) {
182             while (item.getLocationInParent() == IfStatement.ELSE_STATEMENT_PROPERTY) {
183                 item= (IfStatement)item.getParent();
184             }
185             return item;
186         }
187     }
188     
189     private static final class AddBlockOperation extends AbstractFixRewriteOperation {
190
191         private final ChildPropertyDescriptor fBodyProperty;
192         private final Statement fBody;
193         private final Statement fControlStatement;
194
195         public AddBlockOperation(ChildPropertyDescriptor bodyProperty, Statement body, Statement controlStatement) {
196             fBodyProperty= bodyProperty;
197             fBody= body;
198             fControlStatement= controlStatement;
199         }
200
201         /* (non-Javadoc)
202          * @see org.eclipse.jdt.internal.corext.fix.AbstractFix.IFixRewriteOperation#rewriteAST(org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite, java.util.List)
203          */

204         public void rewriteAST(CompilationUnitRewrite cuRewrite, List JavaDoc textEditGroups) throws CoreException {
205             ASTRewrite rewrite= cuRewrite.getASTRewrite();
206             String JavaDoc label;
207             if (fBodyProperty == IfStatement.THEN_STATEMENT_PROPERTY) {
208                 label = FixMessages.CodeStyleFix_ChangeIfToBlock_desription;
209             } else if (fBodyProperty == IfStatement.ELSE_STATEMENT_PROPERTY) {
210                 label = FixMessages.CodeStyleFix_ChangeElseToBlock_description;
211             } else {
212                 label = FixMessages.CodeStyleFix_ChangeControlToBlock_description;
213             }
214             
215             TextEditGroup group= createTextEditGroup(label);
216             textEditGroups.add(group);
217             
218             ASTNode moveTarget= rewrite.createMoveTarget(fBody);
219             Block replacingBody= cuRewrite.getRoot().getAST().newBlock();
220             replacingBody.statements().add(moveTarget);
221             rewrite.set(fControlStatement, fBodyProperty, replacingBody, group);
222         }
223
224     }
225     
226     static class RemoveBlockOperation extends AbstractFixRewriteOperation {
227
228         private final Statement fStatement;
229         private final ChildPropertyDescriptor fChild;
230
231         public RemoveBlockOperation(Statement controlStatement, ChildPropertyDescriptor child) {
232             fStatement= controlStatement;
233             fChild= child;
234         }
235
236         /**
237          * {@inheritDoc}
238          */

239         public void rewriteAST(CompilationUnitRewrite cuRewrite, List JavaDoc textEditGroups) throws CoreException {
240             ASTRewrite rewrite= cuRewrite.getASTRewrite();
241
242             Block block= (Block)fStatement.getStructuralProperty(fChild);
243             Statement statement= (Statement)block.statements().get(0);
244             Statement moveTarget= (Statement)rewrite.createMoveTarget(statement);
245             
246             TextEditGroup group= createTextEditGroup(FixMessages.ControlStatementsFix_removeBrackets_proposalDescription);
247             textEditGroups.add(group);
248             rewrite.set(fStatement, fChild, moveTarget, group);
249         }
250         
251         public static boolean satisfiesCleanUpPrecondition(Statement controlStatement, ChildPropertyDescriptor childDescriptor, boolean onlyReturnAndThrows) {
252             return satisfiesPrecondition(controlStatement, childDescriptor, onlyReturnAndThrows, true);
253         }
254         
255         public static boolean satisfiesQuickAssistPrecondition(Statement controlStatement, ChildPropertyDescriptor childDescriptor) {
256             return satisfiesPrecondition(controlStatement, childDescriptor, false, false);
257         }
258
259         //Can the block around child with childDescriptor of controlStatement be removed?
260
private static boolean satisfiesPrecondition(Statement controlStatement, ChildPropertyDescriptor childDescriptor, boolean onlyReturnAndThrows, boolean cleanUpCheck) {
261             Object JavaDoc child= controlStatement.getStructuralProperty(childDescriptor);
262             
263             if (!(child instanceof Block))
264                 return false;
265             
266             Block block= (Block)child;
267             List JavaDoc list= block.statements();
268             if (list.size() != 1)
269                 return false;
270             
271             ASTNode singleStatement= (ASTNode)list.get(0);
272             
273             if (onlyReturnAndThrows)
274                 if (!(singleStatement instanceof ReturnStatement) && !(singleStatement instanceof ThrowStatement))
275                     return false;
276             
277             if (controlStatement instanceof IfStatement) {
278                 // if (true) {
279
// while (true)
280
// if (false)
281
// ;
282
// } else
283
// ;
284

285                 if (((IfStatement)controlStatement).getThenStatement() != child)
286                     return true;//can always remove blocks in else part
287

288                 IfStatement ifStatement= (IfStatement)controlStatement;
289                 if (ifStatement.getElseStatement() == null)
290                     return true;//can always remove if no else part
291

292                 return !hasUnblockedIf((Statement)singleStatement, onlyReturnAndThrows, cleanUpCheck);
293             } else {
294                 //if (true)
295
// while (true) {
296
// if (false)
297
// ;
298
// }
299
//else
300
// ;
301
if (!hasUnblockedIf((Statement)singleStatement, onlyReturnAndThrows, cleanUpCheck))
302                     return true;
303                 
304                 ASTNode currentChild= controlStatement;
305                 ASTNode parent= currentChild.getParent();
306                 while (true) {
307                     Statement body= null;
308                     if (parent instanceof IfStatement) {
309                         body= ((IfStatement)parent).getThenStatement();
310                         if (body == currentChild && ((IfStatement)parent).getElseStatement() != null)//->currentChild is an unblocked then part
311
return false;
312                     } else if (parent instanceof WhileStatement) {
313                         body= ((WhileStatement)parent).getBody();
314                     } else if (parent instanceof DoStatement) {
315                         body= ((DoStatement)parent).getBody();
316                     } else if (parent instanceof ForStatement) {
317                         body= ((ForStatement)parent).getBody();
318                     } else if (parent instanceof EnhancedForStatement) {
319                         body= ((EnhancedForStatement)parent).getBody();
320                     } else {
321                         return true;
322                     }
323                     if (body != currentChild)//->parents child is a block
324
return true;
325                     
326                     currentChild= parent;
327                     parent= currentChild.getParent();
328                 }
329             }
330         }
331
332         private static boolean hasUnblockedIf(Statement p, boolean onlyReturnAndThrows, boolean cleanUpCheck) {
333             while (true) {
334                 if (p instanceof IfStatement) {
335                     return true;
336                 } else {
337
338                     ChildPropertyDescriptor childD= null;
339                     if (p instanceof WhileStatement) {
340                         childD= WhileStatement.BODY_PROPERTY;
341                     } else if (p instanceof ForStatement) {
342                         childD= ForStatement.BODY_PROPERTY;
343                     } else if (p instanceof EnhancedForStatement) {
344                         childD= EnhancedForStatement.BODY_PROPERTY;
345                     } else if (p instanceof DoStatement) {
346                         childD= DoStatement.BODY_PROPERTY;
347                     } else {
348                         return false;
349                     }
350                     Statement body= (Statement)p.getStructuralProperty(childD);
351                     if (body instanceof Block) {
352                         if (!cleanUpCheck) {
353                             return false;
354                         } else {
355                             if (!satisfiesPrecondition(p, childD, onlyReturnAndThrows, cleanUpCheck))
356                                 return false;
357                             
358                             p= (Statement)((Block)body).statements().get(0);
359                         }
360                     } else {
361                         p= body;
362                     }
363                 }
364             }
365         }
366
367     }
368
369     public static IFix[] createRemoveBlockFix(CompilationUnit compilationUnit, ASTNode node) {
370         Statement statement= ASTResolving.findParentStatement(node);
371         if (statement == null) {
372             return null;
373         }
374         
375         if (statement instanceof Block) {
376             Block block= (Block)statement;
377             if (block.statements().size() != 1)
378                 return null;
379             
380             ASTNode parent= block.getParent();
381             if (!(parent instanceof Statement))
382                 return null;
383             
384             statement= (Statement)parent;
385         }
386         
387         if (statement instanceof IfStatement) {
388             List JavaDoc result= new ArrayList JavaDoc();
389             
390             List JavaDoc removeAllList= new ArrayList JavaDoc();
391             
392             IfElseIterator iter= new IfElseIterator((IfStatement)statement);
393             IfStatement item= null;
394             while (iter.hasNext()) {
395                 item= iter.next();
396                 if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(item, IfStatement.THEN_STATEMENT_PROPERTY)) {
397                     RemoveBlockOperation op= new RemoveBlockOperation(item, IfStatement.THEN_STATEMENT_PROPERTY);
398                     removeAllList.add(op);
399                     if (item == statement)
400                         result.add(new ControlStatementsFix(FixMessages.ControlStatementsFix_removeIfBlock_proposalDescription, compilationUnit, new IFixRewriteOperation[] {op}));
401                 }
402             }
403             
404             if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(item, IfStatement.ELSE_STATEMENT_PROPERTY)) {
405                 RemoveBlockOperation op= new RemoveBlockOperation(item, IfStatement.ELSE_STATEMENT_PROPERTY);
406                 removeAllList.add(op);
407                 if (item == statement)
408                     result.add(new ControlStatementsFix(FixMessages.ControlStatementsFix_removeElseBlock_proposalDescription, compilationUnit, new IFixRewriteOperation[] {op}));
409             }
410             
411             if (removeAllList.size() > 1) {
412                 IFixRewriteOperation[] allConvert= (IFixRewriteOperation[])removeAllList.toArray(new IFixRewriteOperation[removeAllList.size()]);
413                 result.add(new ControlStatementsFix(FixMessages.ControlStatementsFix_removeIfElseBlock_proposalDescription, compilationUnit, allConvert));
414             }
415             
416             return (IFix[])result.toArray(new IFix[result.size()]);
417         } else if (statement instanceof WhileStatement) {
418             if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(statement, WhileStatement.BODY_PROPERTY)) {
419                 RemoveBlockOperation op= new RemoveBlockOperation(statement, WhileStatement.BODY_PROPERTY);
420                 return new IFix[] {new ControlStatementsFix(FixMessages.ControlStatementsFix_removeBrackets_proposalDescription, compilationUnit, new IFixRewriteOperation[] {op})};
421             }
422         } else if (statement instanceof ForStatement) {
423             if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(statement, ForStatement.BODY_PROPERTY)) {
424                 RemoveBlockOperation op= new RemoveBlockOperation(statement, ForStatement.BODY_PROPERTY);
425                 return new IFix[] {new ControlStatementsFix(FixMessages.ControlStatementsFix_removeBrackets_proposalDescription, compilationUnit, new IFixRewriteOperation[] {op})};
426             }
427         } else if (statement instanceof EnhancedForStatement) {
428             if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(statement, EnhancedForStatement.BODY_PROPERTY)) {
429                 RemoveBlockOperation op= new RemoveBlockOperation(statement, EnhancedForStatement.BODY_PROPERTY);
430                 return new IFix[] {new ControlStatementsFix(FixMessages.ControlStatementsFix_removeBrackets_proposalDescription, compilationUnit, new IFixRewriteOperation[] {op})};
431             }
432         } else if (statement instanceof DoStatement) {
433             if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(statement, DoStatement.BODY_PROPERTY)) {
434                 RemoveBlockOperation op= new RemoveBlockOperation(statement, DoStatement.BODY_PROPERTY);
435                 return new IFix[] {new ControlStatementsFix(FixMessages.ControlStatementsFix_removeBrackets_proposalDescription, compilationUnit, new IFixRewriteOperation[] {op})};
436             }
437         }
438         
439         return null;
440     }
441
442     public static IFix createCleanUp(CompilationUnit compilationUnit,
443             boolean convertSingleStatementToBlock,
444             boolean removeUnnecessaryBlock,
445             boolean removeUnnecessaryBlockContainingReturnOrThrow) throws CoreException {
446         
447         if (!convertSingleStatementToBlock && !removeUnnecessaryBlock && !removeUnnecessaryBlockContainingReturnOrThrow)
448             return null;
449         
450         List JavaDoc operations= new ArrayList JavaDoc();
451         ControlStatementFinder finder= new ControlStatementFinder(convertSingleStatementToBlock, removeUnnecessaryBlock, removeUnnecessaryBlockContainingReturnOrThrow, operations);
452         compilationUnit.accept(finder);
453         
454         if (operations.isEmpty())
455             return null;
456         
457         IFixRewriteOperation[] ops= (IFixRewriteOperation[])operations.toArray(new IFixRewriteOperation[operations.size()]);
458         return new ControlStatementsFix(FixMessages.ControlStatementsFix_change_name, compilationUnit, ops);
459     }
460
461     protected ControlStatementsFix(String JavaDoc name, CompilationUnit compilationUnit, IFixRewriteOperation[] fixRewriteOperations) {
462         super(name, compilationUnit, fixRewriteOperations);
463     }
464
465 }
466
Popular Tags