]> git.uio.no Git - ifi-stolz-refaktor.git/blame - case-study/jdt-after/core extension/org/eclipse/jdt/internal/corext/fix/ControlStatementsFix.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / core extension / org / eclipse / jdt / internal / corext / fix / ControlStatementsFix.java
CommitLineData
1b2798f6
EK
1/*******************************************************************************
2 * Copyright (c) 2000, 2011 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 *******************************************************************************/
11package org.eclipse.jdt.internal.corext.fix;
12
13import java.util.ArrayList;
14import java.util.List;
15
16import org.eclipse.core.runtime.CoreException;
17
18import org.eclipse.text.edits.TextEditGroup;
19
20import org.eclipse.jdt.core.dom.ASTNode;
21import org.eclipse.jdt.core.dom.Block;
22import org.eclipse.jdt.core.dom.ChildPropertyDescriptor;
23import org.eclipse.jdt.core.dom.CompilationUnit;
24import org.eclipse.jdt.core.dom.DoStatement;
25import org.eclipse.jdt.core.dom.EnhancedForStatement;
26import org.eclipse.jdt.core.dom.ForStatement;
27import org.eclipse.jdt.core.dom.IfStatement;
28import org.eclipse.jdt.core.dom.ReturnStatement;
29import org.eclipse.jdt.core.dom.Statement;
30import org.eclipse.jdt.core.dom.ThrowStatement;
31import org.eclipse.jdt.core.dom.WhileStatement;
32import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
33
34import org.eclipse.jdt.internal.corext.dom.GenericVisitor;
35import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
36
37import org.eclipse.jdt.ui.cleanup.ICleanUpFix;
38
39
40public class ControlStatementsFix extends CompilationUnitRewriteOperationsFix {
41
42 private final static class ControlStatementFinder extends GenericVisitor {
43
44 private final List<CompilationUnitRewriteOperation> fResult;
45 private final boolean fFindControlStatementsWithoutBlock;
46 private final boolean fRemoveUnnecessaryBlocks;
47 private final boolean fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow;
48
49 public ControlStatementFinder(boolean findControlStatementsWithoutBlock,
50 boolean removeUnnecessaryBlocks,
51 boolean removeUnnecessaryBlocksOnlyWhenReturnOrThrow,
52 List<CompilationUnitRewriteOperation> resultingCollection) {
53
54 fFindControlStatementsWithoutBlock= findControlStatementsWithoutBlock;
55 fRemoveUnnecessaryBlocks= removeUnnecessaryBlocks;
56 fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow= removeUnnecessaryBlocksOnlyWhenReturnOrThrow;
57 fResult= resultingCollection;
58 }
59
60 /* (non-Javadoc)
61 * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.DoStatement)
62 */
63 @Override
64 public boolean visit(DoStatement node) {
65 handle(node.getBody(), DoStatement.BODY_PROPERTY);
66
67 return super.visit(node);
68 }
69
70 /* (non-Javadoc)
71 * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.ForStatement)
72 */
73 @Override
74 public boolean visit(ForStatement node) {
75 handle(node.getBody(), ForStatement.BODY_PROPERTY);
76
77 return super.visit(node);
78 }
79
80 /**
81 * {@inheritDoc}
82 */
83 @Override
84 public boolean visit(EnhancedForStatement node) {
85 handle(node.getBody(), EnhancedForStatement.BODY_PROPERTY);
86
87 return super.visit(node);
88 }
89
90 /* (non-Javadoc)
91 * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.IfStatement)
92 */
93 @Override
94 public boolean visit(IfStatement statement) {
95 handle(statement.getThenStatement(), IfStatement.THEN_STATEMENT_PROPERTY);
96
97 Statement elseStatement= statement.getElseStatement();
98 if (elseStatement != null && !(elseStatement instanceof IfStatement)) {
99 handle(elseStatement, IfStatement.ELSE_STATEMENT_PROPERTY);
100 }
101
102 return super.visit(statement);
103 }
104
105 /* (non-Javadoc)
106 * @see org.eclipse.jdt.internal.corext.dom.GenericVisitor#visit(org.eclipse.jdt.core.dom.WhileStatement)
107 */
108 @Override
109 public boolean visit(WhileStatement node) {
110 handle(node.getBody(), WhileStatement.BODY_PROPERTY);
111
112 return super.visit(node);
113 }
114
115 private void handle(Statement body, ChildPropertyDescriptor bodyProperty) {
116 if ((body.getFlags() & ASTNode.RECOVERED) != 0)
117 return;
118 Statement parent= (Statement)body.getParent();
119 if ((parent.getFlags() & ASTNode.RECOVERED) != 0)
120 return;
121
122 if (fRemoveUnnecessaryBlocksOnlyWhenReturnOrThrow) {
123 if (!(body instanceof Block)) {
124 if (body.getNodeType() != ASTNode.IF_STATEMENT && body.getNodeType() != ASTNode.RETURN_STATEMENT && body.getNodeType() != ASTNode.THROW_STATEMENT) {
125 fResult.add(new AddBlockOperation(bodyProperty, body, parent));
126 }
127 } else {
128 if (RemoveBlockOperation.satisfiesCleanUpPrecondition(parent, bodyProperty, true)) {
129 fResult.add(new RemoveBlockOperation(parent, bodyProperty));
130 }
131 }
132 } else if (fFindControlStatementsWithoutBlock) {
133 if (!(body instanceof Block)) {
134 fResult.add(new AddBlockOperation(bodyProperty, body, parent));
135 }
136 } else if (fRemoveUnnecessaryBlocks) {
137 if (RemoveBlockOperation.satisfiesCleanUpPrecondition(parent, bodyProperty, false)) {
138 fResult.add(new RemoveBlockOperation(parent, bodyProperty));
139 }
140 }
141 }
142
143 }
144
145 private static class IfElseIterator {
146
147 private IfStatement fCursor;
148
149 public IfElseIterator(IfStatement item) {
150 fCursor= findStart(item);
151 }
152
153 public IfStatement next() {
154 if (!hasNext())
155 return null;
156
157 IfStatement result= fCursor;
158
159 if (fCursor.getElseStatement() instanceof IfStatement) {
160 fCursor= (IfStatement)fCursor.getElseStatement();
161 } else {
162 fCursor= null;
163 }
164
165 return result;
166 }
167
168 public boolean hasNext() {
169 return fCursor != null;
170 }
171
172 private IfStatement findStart(IfStatement item) {
173 while (item.getLocationInParent() == IfStatement.ELSE_STATEMENT_PROPERTY) {
174 item= (IfStatement)item.getParent();
175 }
176 return item;
177 }
178 }
179
180 private static final class AddBlockOperation extends CompilationUnitRewriteOperation {
181
182 private final ChildPropertyDescriptor fBodyProperty;
183 private final Statement fBody;
184 private final Statement fControlStatement;
185
186 public AddBlockOperation(ChildPropertyDescriptor bodyProperty, Statement body, Statement controlStatement) {
187 fBodyProperty= bodyProperty;
188 fBody= body;
189 fControlStatement= controlStatement;
190 }
191
192 /**
193 * {@inheritDoc}
194 */
195 @Override
196 public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
197 ASTRewrite rewrite= cuRewrite.getASTRewrite();
198 String label;
199 if (fBodyProperty == IfStatement.THEN_STATEMENT_PROPERTY) {
200 label = FixMessages.CodeStyleFix_ChangeIfToBlock_desription;
201 } else if (fBodyProperty == IfStatement.ELSE_STATEMENT_PROPERTY) {
202 label = FixMessages.CodeStyleFix_ChangeElseToBlock_description;
203 } else {
204 label = FixMessages.CodeStyleFix_ChangeControlToBlock_description;
205 }
206
207 TextEditGroup group= createTextEditGroup(label, cuRewrite);
208 ASTNode moveTarget= rewrite.createMoveTarget(fBody);
209 Block replacingBody= cuRewrite.getRoot().getAST().newBlock();
210 replacingBody.statements().add(moveTarget);
211 rewrite.set(fControlStatement, fBodyProperty, replacingBody, group);
212 }
213
214 }
215
216 static class RemoveBlockOperation extends CompilationUnitRewriteOperation {
217
218 private final Statement fStatement;
219 private final ChildPropertyDescriptor fChild;
220
221 public RemoveBlockOperation(Statement controlStatement, ChildPropertyDescriptor child) {
222 fStatement= controlStatement;
223 fChild= child;
224 }
225
226 /**
227 * {@inheritDoc}
228 */
229 @Override
230 public void rewriteAST(CompilationUnitRewrite cuRewrite, LinkedProposalModel model) throws CoreException {
231 ASTRewrite rewrite= cuRewrite.getASTRewrite();
232
233 Block block= (Block)fStatement.getStructuralProperty(fChild);
234 Statement statement= (Statement)block.statements().get(0);
235 Statement moveTarget= (Statement)rewrite.createMoveTarget(statement);
236
237 TextEditGroup group= createTextEditGroup(FixMessages.ControlStatementsFix_removeBrackets_proposalDescription, cuRewrite);
238 rewrite.set(fStatement, fChild, moveTarget, group);
239 }
240
241 public static boolean satisfiesCleanUpPrecondition(Statement controlStatement, ChildPropertyDescriptor childDescriptor, boolean onlyReturnAndThrows) {
242 return satisfiesPrecondition(controlStatement, childDescriptor, onlyReturnAndThrows, true);
243 }
244
245 public static boolean satisfiesQuickAssistPrecondition(Statement controlStatement, ChildPropertyDescriptor childDescriptor) {
246 return satisfiesPrecondition(controlStatement, childDescriptor, false, false);
247 }
248
249 //Can the block around child with childDescriptor of controlStatement be removed?
250 private static boolean satisfiesPrecondition(Statement controlStatement, ChildPropertyDescriptor childDescriptor, boolean onlyReturnAndThrows, boolean cleanUpCheck) {
251 Object child= controlStatement.getStructuralProperty(childDescriptor);
252
253 if (!(child instanceof Block))
254 return false;
255
256 Block block= (Block)child;
257 List<Statement> list= block.statements();
258 if (list.size() != 1)
259 return false;
260
261 ASTNode singleStatement= list.get(0);
262
263 if (onlyReturnAndThrows)
264 if (!(singleStatement instanceof ReturnStatement) && !(singleStatement instanceof ThrowStatement))
265 return false;
266
267 if (controlStatement instanceof IfStatement) {
268 // if (true) {
269 // while (true)
270 // if (false)
271 // ;
272 // } else
273 // ;
274
275 if (((IfStatement)controlStatement).getThenStatement() != child)
276 return true;//can always remove blocks in else part
277
278 IfStatement ifStatement= (IfStatement)controlStatement;
279 if (ifStatement.getElseStatement() == null)
280 return true;//can always remove if no else part
281
282 return !hasUnblockedIf((Statement)singleStatement, onlyReturnAndThrows, cleanUpCheck);
283 } else {
284 //if (true)
285 // while (true) {
286 // if (false)
287 // ;
288 // }
289 //else
290 // ;
291 if (!hasUnblockedIf((Statement)singleStatement, onlyReturnAndThrows, cleanUpCheck))
292 return true;
293
294 ASTNode currentChild= controlStatement;
295 ASTNode parent= currentChild.getParent();
296 while (true) {
297 Statement body= null;
298 if (parent instanceof IfStatement) {
299 body= ((IfStatement)parent).getThenStatement();
300 if (body == currentChild && ((IfStatement)parent).getElseStatement() != null)//->currentChild is an unblocked then part
301 return false;
302 } else if (parent instanceof WhileStatement) {
303 body= ((WhileStatement)parent).getBody();
304 } else if (parent instanceof DoStatement) {
305 body= ((DoStatement)parent).getBody();
306 } else if (parent instanceof ForStatement) {
307 body= ((ForStatement)parent).getBody();
308 } else if (parent instanceof EnhancedForStatement) {
309 body= ((EnhancedForStatement)parent).getBody();
310 } else {
311 return true;
312 }
313 if (body != currentChild)//->parents child is a block
314 return true;
315
316 currentChild= parent;
317 parent= currentChild.getParent();
318 }
319 }
320 }
321
322 private static boolean hasUnblockedIf(Statement p, boolean onlyReturnAndThrows, boolean cleanUpCheck) {
323 while (true) {
324 if (p instanceof IfStatement) {
325 return true;
326 } else {
327
328 ChildPropertyDescriptor childD= null;
329 if (p instanceof WhileStatement) {
330 childD= WhileStatement.BODY_PROPERTY;
331 } else if (p instanceof ForStatement) {
332 childD= ForStatement.BODY_PROPERTY;
333 } else if (p instanceof EnhancedForStatement) {
334 childD= EnhancedForStatement.BODY_PROPERTY;
335 } else if (p instanceof DoStatement) {
336 childD= DoStatement.BODY_PROPERTY;
337 } else {
338 return false;
339 }
340 Statement body= (Statement)p.getStructuralProperty(childD);
341 if (body instanceof Block) {
342 if (!cleanUpCheck) {
343 return false;
344 } else {
345 if (!satisfiesPrecondition(p, childD, onlyReturnAndThrows, cleanUpCheck))
346 return false;
347
348 p= (Statement)((Block)body).statements().get(0);
349 }
350 } else {
351 p= body;
352 }
353 }
354 }
355 }
356
357 }
358
359 public static ControlStatementsFix[] createRemoveBlockFix(CompilationUnit compilationUnit, ASTNode node) {
360 if (!(node instanceof Statement)) {
361 return null;
362 }
363 Statement statement= (Statement) node;
364
365 if (statement instanceof Block) {
366 Block block= (Block)statement;
367 if (block.statements().size() != 1)
368 return null;
369
370 ASTNode parent= block.getParent();
371 if (!(parent instanceof Statement))
372 return null;
373
374 statement= (Statement)parent;
375 }
376
377 if (statement instanceof IfStatement) {
378 List<ControlStatementsFix> result= new ArrayList<ControlStatementsFix>();
379
380 List<RemoveBlockOperation> removeAllList= new ArrayList<RemoveBlockOperation>();
381
382 IfElseIterator iter= new IfElseIterator((IfStatement)statement);
383 IfStatement item= null;
384 while (iter.hasNext()) {
385 item= iter.next();
386 if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(item, IfStatement.THEN_STATEMENT_PROPERTY)) {
387 RemoveBlockOperation op= new RemoveBlockOperation(item, IfStatement.THEN_STATEMENT_PROPERTY);
388 removeAllList.add(op);
389 if (item == statement)
390 result.add(new ControlStatementsFix(FixMessages.ControlStatementsFix_removeIfBlock_proposalDescription, compilationUnit, new CompilationUnitRewriteOperation[] {op}));
391 }
392 }
393
394 if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(item, IfStatement.ELSE_STATEMENT_PROPERTY)) {
395 RemoveBlockOperation op= new RemoveBlockOperation(item, IfStatement.ELSE_STATEMENT_PROPERTY);
396 removeAllList.add(op);
397 if (item == statement)
398 result.add(new ControlStatementsFix(FixMessages.ControlStatementsFix_removeElseBlock_proposalDescription, compilationUnit, new CompilationUnitRewriteOperation[] {op}));
399 }
400
401 if (removeAllList.size() > 1) {
402 CompilationUnitRewriteOperation[] allConvert= removeAllList.toArray(new CompilationUnitRewriteOperation[removeAllList.size()]);
403 result.add(new ControlStatementsFix(FixMessages.ControlStatementsFix_removeIfElseBlock_proposalDescription, compilationUnit, allConvert));
404 }
405
406 return result.toArray(new ControlStatementsFix[result.size()]);
407 } else if (statement instanceof WhileStatement) {
408 if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(statement, WhileStatement.BODY_PROPERTY)) {
409 RemoveBlockOperation op= new RemoveBlockOperation(statement, WhileStatement.BODY_PROPERTY);
410 return new ControlStatementsFix[] {new ControlStatementsFix(FixMessages.ControlStatementsFix_removeBrackets_proposalDescription, compilationUnit, new CompilationUnitRewriteOperation[] {op})};
411 }
412 } else if (statement instanceof ForStatement) {
413 if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(statement, ForStatement.BODY_PROPERTY)) {
414 RemoveBlockOperation op= new RemoveBlockOperation(statement, ForStatement.BODY_PROPERTY);
415 return new ControlStatementsFix[] {new ControlStatementsFix(FixMessages.ControlStatementsFix_removeBrackets_proposalDescription, compilationUnit, new CompilationUnitRewriteOperation[] {op})};
416 }
417 } else if (statement instanceof EnhancedForStatement) {
418 if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(statement, EnhancedForStatement.BODY_PROPERTY)) {
419 RemoveBlockOperation op= new RemoveBlockOperation(statement, EnhancedForStatement.BODY_PROPERTY);
420 return new ControlStatementsFix[] {new ControlStatementsFix(FixMessages.ControlStatementsFix_removeBrackets_proposalDescription, compilationUnit, new CompilationUnitRewriteOperation[] {op})};
421 }
422 } else if (statement instanceof DoStatement) {
423 if (RemoveBlockOperation.satisfiesQuickAssistPrecondition(statement, DoStatement.BODY_PROPERTY)) {
424 RemoveBlockOperation op= new RemoveBlockOperation(statement, DoStatement.BODY_PROPERTY);
425 return new ControlStatementsFix[] {new ControlStatementsFix(FixMessages.ControlStatementsFix_removeBrackets_proposalDescription, compilationUnit, new CompilationUnitRewriteOperation[] {op})};
426 }
427 }
428
429 return null;
430 }
431
432 public static ICleanUpFix createCleanUp(CompilationUnit compilationUnit,
433 boolean convertSingleStatementToBlock,
434 boolean removeUnnecessaryBlock,
435 boolean removeUnnecessaryBlockContainingReturnOrThrow) {
436
437 if (!convertSingleStatementToBlock && !removeUnnecessaryBlock && !removeUnnecessaryBlockContainingReturnOrThrow)
438 return null;
439
440 List<CompilationUnitRewriteOperation> operations= new ArrayList<CompilationUnitRewriteOperation>();
441 ControlStatementFinder finder= new ControlStatementFinder(convertSingleStatementToBlock, removeUnnecessaryBlock, removeUnnecessaryBlockContainingReturnOrThrow, operations);
442 compilationUnit.accept(finder);
443
444 if (operations.isEmpty())
445 return null;
446
447 CompilationUnitRewriteOperation[] ops= operations.toArray(new CompilationUnitRewriteOperation[operations.size()]);
448 return new ControlStatementsFix(FixMessages.ControlStatementsFix_change_name, compilationUnit, ops);
449 }
450
451 protected ControlStatementsFix(String name, CompilationUnit compilationUnit, CompilationUnitRewriteOperation[] fixRewriteOperations) {
452 super(name, compilationUnit, fixRewriteOperations);
453 }
454
455}