1 11 package org.eclipse.jdt.internal.ui.text.correction; 12 13 import java.util.ArrayList ; 14 import java.util.Iterator ; 15 import java.util.List ; 16 17 import org.eclipse.core.runtime.CoreException; 18 19 import org.eclipse.jdt.core.ICompilationUnit; 20 import org.eclipse.jdt.core.IJavaElement; 21 import org.eclipse.jdt.core.IType; 22 import org.eclipse.jdt.core.JavaModelException; 23 import org.eclipse.jdt.core.dom.AST; 24 import org.eclipse.jdt.core.dom.ASTNode; 25 import org.eclipse.jdt.core.dom.Assignment; 26 import org.eclipse.jdt.core.dom.Block; 27 import org.eclipse.jdt.core.dom.BodyDeclaration; 28 import org.eclipse.jdt.core.dom.CompilationUnit; 29 import org.eclipse.jdt.core.dom.Expression; 30 import org.eclipse.jdt.core.dom.ITypeBinding; 31 import org.eclipse.jdt.core.dom.IVariableBinding; 32 import org.eclipse.jdt.core.dom.Modifier; 33 import org.eclipse.jdt.core.dom.SimpleName; 34 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 35 import org.eclipse.jdt.core.dom.Statement; 36 import org.eclipse.jdt.core.dom.SwitchStatement; 37 import org.eclipse.jdt.core.dom.ThisExpression; 38 import org.eclipse.jdt.core.dom.Type; 39 import org.eclipse.jdt.core.dom.VariableDeclaration; 40 import org.eclipse.jdt.core.dom.VariableDeclarationExpression; 41 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 42 import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 43 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 44 import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition; 45 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 46 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 47 48 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 49 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 50 import org.eclipse.jdt.internal.corext.dom.GenericVisitor; 51 import org.eclipse.jdt.internal.corext.dom.LocalVariableIndex; 52 import org.eclipse.jdt.internal.corext.dom.ModifierRewrite; 53 import org.eclipse.jdt.internal.corext.dom.Selection; 54 import org.eclipse.jdt.internal.corext.dom.VariableDeclarationRewrite; 55 import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowContext; 56 import org.eclipse.jdt.internal.corext.refactoring.code.flow.FlowInfo; 57 import org.eclipse.jdt.internal.corext.refactoring.code.flow.InOutFlowAnalyzer; 58 import org.eclipse.jdt.internal.corext.refactoring.surround.SurroundWithAnalyzer; 59 60 import org.eclipse.jdt.ui.text.java.IInvocationContext; 61 62 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider; 63 64 public abstract class SurroundWith { 65 66 private static final class SplitSelectedOperator implements ISplitOperation { 67 68 private List fAccessedInside; 69 private List fStatements; 70 private List fAccessedAfter; 71 private ASTRewrite fRewrite; 72 private ListRewrite fBlockRewrite; 73 private VariableDeclarationStatement fLastStatement= null; 74 75 public SplitSelectedOperator(List inside, List after, ListRewrite blockRewrite, ASTRewrite rewrite, List statements) { 76 super(); 77 fAccessedInside= inside; 78 fStatements= statements; 79 fAccessedAfter= after; 80 fRewrite= rewrite; 81 fBlockRewrite= blockRewrite; 82 } 83 84 public boolean needsSplit(VariableDeclarationFragment last, VariableDeclarationFragment current) { 85 return fAccessedInside.contains(last) != fAccessedInside.contains(current) || fAccessedAfter.contains(last) != fAccessedAfter.contains(current); 86 } 87 88 public void initializeStatement(VariableDeclarationStatement statement, VariableDeclarationFragment current) { 89 if (fAccessedAfter.contains(current)) { 90 if (fAccessedInside.contains(current)) 91 makeFinal(statement, fRewrite); 92 handleInitializer(current); 93 94 if (fLastStatement != null) { 95 fBlockRewrite.insertAfter(statement, fLastStatement, null); 96 } 97 fLastStatement= statement; 98 } else { 99 if (fLastStatement != null) { 100 handleNewStatement(statement); 101 } else { 102 handleStatement(statement); 103 fLastStatement= statement; 104 } 105 } 106 } 107 108 protected void handleStatement(Statement statement) { 109 fStatements.add(fRewrite.createMoveTarget(statement)); 110 } 111 112 protected void handleNewStatement(Statement statement) { 113 fStatements.add(statement); 114 } 115 116 protected void handleInitializer(VariableDeclarationFragment fragment) { 117 splitOffInitializer(fStatements, fragment, fRewrite); 118 } 119 120 } 121 122 private static final class SplitUnselectedOperator implements ISplitOperation { 123 124 private List fAccessedInside; 125 private ListRewrite fBlockRewrite; 126 private ASTRewrite fRewrite; 127 private VariableDeclarationStatement fLastStatement; 128 129 private SplitUnselectedOperator(List accessedInside, ListRewrite blockRewrite, ASTRewrite rewrite) { 130 super(); 131 fAccessedInside= accessedInside; 132 fBlockRewrite= blockRewrite; 133 fRewrite= rewrite; 134 fLastStatement= null; 135 } 136 137 public boolean needsSplit(VariableDeclarationFragment last, VariableDeclarationFragment current) { 138 return fAccessedInside.contains(last) != fAccessedInside.contains(current); 139 } 140 141 public void initializeStatement(VariableDeclarationStatement statement, VariableDeclarationFragment current) { 142 if (fAccessedInside.contains(current)) 143 makeFinal(statement, fRewrite); 144 145 if (fLastStatement != null) 146 fBlockRewrite.insertAfter(statement, fLastStatement, null); 147 fLastStatement= statement; 148 } 149 } 150 151 protected interface ISplitOperation { 152 boolean needsSplit(VariableDeclarationFragment last, VariableDeclarationFragment current); 153 void initializeStatement(VariableDeclarationStatement statement, VariableDeclarationFragment current); 154 } 155 156 private final CompilationUnit fRootNode; 157 private final Statement[] fSelectedStatements; 158 private boolean fIsNewContext; 159 private ITrackedNodePosition fFirstInsertedPosition; 160 private ITrackedNodePosition fLastInsertedPosition; 161 162 public SurroundWith(CompilationUnit root, Statement[] selectedStatements) { 163 fRootNode= root; 164 fSelectedStatements= selectedStatements; 165 } 166 167 168 public static boolean isApplicable(IInvocationContext context) throws JavaModelException { 169 ICompilationUnit unit= context.getCompilationUnit(); 170 CompilationUnit ast= ASTProvider.getASTProvider().getAST(unit, ASTProvider.WAIT_NO, null); 171 if (ast == null) 172 return true; 173 174 Selection selection= Selection.createFromStartLength(context.getSelectionOffset(), context.getSelectionLength()); 175 SurroundWithAnalyzer analyzer= new SurroundWithAnalyzer(unit, selection); 176 context.getASTRoot().accept(analyzer); 177 178 return analyzer.getStatus().isOK() && analyzer.hasSelectedNodes(); 179 } 180 181 187 public static Statement[] getSelectedStatements(IInvocationContext context) throws JavaModelException { 188 Selection selection= Selection.createFromStartLength(context.getSelectionOffset(), context.getSelectionLength()); 189 SurroundWithAnalyzer analyzer= new SurroundWithAnalyzer(context.getCompilationUnit(), selection); 190 context.getASTRoot().accept(analyzer); 191 192 if (!analyzer.getStatus().isOK() || !analyzer.hasSelectedNodes()) { 193 return null; 194 } else { 195 return analyzer.getSelectedStatements(); 196 } 197 } 198 199 public int getBodyStart() { 200 return fFirstInsertedPosition.getStartPosition(); 201 } 202 203 public int getBodyLength() { 204 return fLastInsertedPosition.getStartPosition() + fLastInsertedPosition.getLength() - getBodyStart(); 205 } 206 207 212 public ASTRewrite getRewrite() throws CoreException { 213 Statement[] selectedStatements= fSelectedStatements; 214 AST ast= getAst(); 215 216 ASTRewrite rewrite= ASTRewrite.create(ast); 217 218 BodyDeclaration enclosingBodyDeclaration= (BodyDeclaration)ASTNodes.getParent(selectedStatements[0], BodyDeclaration.class); 219 int maxVariableId= LocalVariableIndex.perform(enclosingBodyDeclaration) + 1; 220 221 fIsNewContext= isNewContext(); 222 223 List accessedAfter= getVariableDeclarationsAccessedAfter(selectedStatements[selectedStatements.length - 1], maxVariableId); 224 List readInside; 225 readInside= getVariableDeclarationReadsInside(selectedStatements, maxVariableId); 226 227 List inserted= new ArrayList (); 228 moveToBlock(selectedStatements, inserted, accessedAfter, readInside, rewrite); 229 if (fIsNewContext) { 230 ImportRewrite importRewrite= StubUtility.createImportRewrite((CompilationUnit)selectedStatements[0].getRoot(), false); 231 for (int i= 0; i < selectedStatements.length; i++) { 232 qualifyThisExpressions(selectedStatements[i], rewrite, importRewrite); 233 } 234 } 235 236 if (selectedStatements.length == 1 && ASTNodes.isControlStatementBody(selectedStatements[0].getLocationInParent())) { 237 Block wrap= ast.newBlock(); 238 rewrite.replace(selectedStatements[0], wrap, null); 239 ListRewrite listRewrite= rewrite.getListRewrite(wrap, Block.STATEMENTS_PROPERTY); 240 241 for (Iterator iterator= inserted.iterator(); iterator.hasNext();) { 242 ASTNode node= (ASTNode)iterator.next(); 243 listRewrite.insertLast(node, null); 244 } 245 246 } else { 247 ListRewrite listRewrite= getListRewrite(selectedStatements[0], rewrite); 248 249 ASTNode current= selectedStatements[selectedStatements.length - 1]; 250 for (Iterator iterator= inserted.iterator(); iterator.hasNext();) { 251 ASTNode node= (ASTNode)iterator.next(); 252 listRewrite.insertAfter(node, current, null); 253 current= node; 254 } 255 } 256 257 fFirstInsertedPosition= rewrite.track((ASTNode)inserted.get(0)); 258 fLastInsertedPosition= rewrite.track((ASTNode)inserted.get(inserted.size() - 1)); 259 260 return rewrite; 261 } 262 263 264 267 protected abstract boolean isNewContext(); 268 269 276 protected List getVariableDeclarationReadsInside(Statement[] selectedNodes, int maxVariableId) { 277 ArrayList result= new ArrayList (); 278 if (!fIsNewContext) 279 return result; 280 281 IVariableBinding[] reads= getReads(selectedNodes, maxVariableId); 282 for (int i= 0; i < reads.length; i++) { 283 IVariableBinding read= reads[i]; 284 if (!read.isField()) { 285 ASTNode readDecl= getRootNode().findDeclaringNode(read); 286 if (readDecl instanceof VariableDeclaration) { 287 result.add(readDecl); 288 } 289 } 290 } 291 292 return result; 293 } 294 295 302 protected List getVariableDeclarationsAccessedAfter(ASTNode startNode, int maxVariableId) { 303 304 List statements; 305 if (startNode.getLocationInParent() == SwitchStatement.STATEMENTS_PROPERTY) { 306 SwitchStatement block= (SwitchStatement)ASTNodes.getParent(startNode, SwitchStatement.class); 307 statements= block.statements(); 308 } else { 309 Block block= (Block)ASTNodes.getParent(startNode, Block.class); 310 statements= block.statements(); 311 } 312 List bodyAfterSelection= statements.subList(statements.indexOf(startNode) + 1, statements.size()); 313 314 List result= new ArrayList (); 315 if (!bodyAfterSelection.isEmpty()) { 316 317 IVariableBinding[] accesses= getAccesses((ASTNode[]) bodyAfterSelection.toArray(new ASTNode[bodyAfterSelection.size()]), maxVariableId); 318 319 for (int i= 0; i < accesses.length; i++) { 320 IVariableBinding curVar= accesses[i]; 321 if (!curVar.isField()) { 322 ASTNode readDecl= ASTNodes.findDeclaration(curVar, getRootNode()); 323 if (readDecl instanceof VariableDeclarationFragment) { 324 result.add(readDecl); 325 } 326 } 327 } 328 } 329 return result; 330 } 331 332 337 private IVariableBinding[] getReads(ASTNode[] region, int maxVariableId) { 338 FlowContext flowContext= new FlowContext(0, maxVariableId); 339 flowContext.setConsiderAccessMode(true); 340 flowContext.setComputeMode(FlowContext.ARGUMENTS); 341 FlowInfo argInfo= new InOutFlowAnalyzer(flowContext).perform(region); 342 IVariableBinding[] reads= argInfo.get(flowContext, FlowInfo.READ | FlowInfo.READ_POTENTIAL | FlowInfo.UNKNOWN); 343 return reads; 344 } 345 346 351 private IVariableBinding[] getAccesses(ASTNode[] region, int maxVariableId) { 352 FlowContext flowContext= new FlowContext(0, maxVariableId); 353 flowContext.setConsiderAccessMode(true); 354 flowContext.setComputeMode(FlowContext.ARGUMENTS); 355 FlowInfo argInfo= new InOutFlowAnalyzer(flowContext).perform(region); 356 IVariableBinding[] varsAccessedAfter= argInfo.get(flowContext, FlowInfo.READ | FlowInfo.READ_POTENTIAL | FlowInfo.WRITE | FlowInfo.WRITE_POTENTIAL | FlowInfo.UNKNOWN); 357 return varsAccessedAfter; 358 } 359 360 379 private final void moveToBlock(Statement[] toMove, List statements, final List accessedAfter, final List accessedInside, final ASTRewrite rewrite) { 380 381 for (int i= 0; i < toMove.length; i++) { 382 ASTNode node= toMove[i]; 383 if (node instanceof VariableDeclarationStatement) { 384 VariableDeclarationStatement statement= (VariableDeclarationStatement)node; 385 final ListRewrite blockRewrite= getListRewrite(statement, rewrite); 386 387 splitVariableDeclarationStatement(statement, createSplitSelectedOperator(accessedAfter, accessedInside, rewrite, statements, blockRewrite), rewrite); 388 389 for (Iterator iter= statement.fragments().iterator(); iter.hasNext();) { 390 accessedInside.remove(iter.next()); 391 } 392 } else { 393 insertNodeAtEnd(rewrite, statements, node); 394 } 395 } 396 397 while (!accessedInside.isEmpty()) { 398 VariableDeclaration variableDeclaration= (VariableDeclaration)accessedInside.get(0); 399 if (variableDeclaration instanceof SingleVariableDeclaration) { 400 if (ASTNodes.findModifierNode(Modifier.FINAL, ASTNodes.getModifiers(variableDeclaration)) == null) { 401 ModifierRewrite.create(rewrite, variableDeclaration).setModifiers(Modifier.FINAL, Modifier.NONE, null); 402 } 403 accessedInside.remove(0); 404 } else if (variableDeclaration.getParent() instanceof VariableDeclarationStatement) { 405 VariableDeclarationStatement statement= (VariableDeclarationStatement)variableDeclaration.getParent(); 406 final ListRewrite blockRewrite= getListRewrite(statement, rewrite); 407 408 splitVariableDeclarationStatement(statement, createSplitUnselectedOperator(accessedInside, rewrite, blockRewrite), rewrite); 409 410 for (Iterator iter= statement.fragments().iterator(); iter.hasNext();) { 411 VariableDeclarationFragment fragment= (VariableDeclarationFragment)iter.next(); 412 accessedInside.remove(fragment); 413 } 414 } else if (variableDeclaration.getParent() instanceof VariableDeclarationExpression) { 415 VariableDeclarationExpression expression= (VariableDeclarationExpression)variableDeclaration.getParent(); 416 417 VariableDeclarationRewrite.rewriteModifiers(expression, Modifier.FINAL, 0, rewrite, null); 418 419 for (Iterator iter= expression.fragments().iterator(); iter.hasNext();) { 420 VariableDeclarationFragment fragment= (VariableDeclarationFragment)iter.next(); 421 accessedInside.remove(fragment); 422 } 423 } 424 } 425 } 426 427 private void insertNodeAtEnd(final ASTRewrite rewrite, final List statements, ASTNode node) { 428 statements.add(rewrite.createMoveTarget(node)); 429 } 430 431 protected ISplitOperation createSplitUnselectedOperator(List accessedInside, ASTRewrite rewrite, ListRewrite blockRewrite) { 432 return new SplitUnselectedOperator(accessedInside, blockRewrite, rewrite); 433 } 434 435 protected ISplitOperation createSplitSelectedOperator(List accessedAfter, List accessedInside, ASTRewrite rewrite, List statements, ListRewrite blockRewrite) { 436 return new SplitSelectedOperator(accessedInside, accessedAfter, blockRewrite, rewrite, statements); 437 } 438 439 449 private void splitVariableDeclarationStatement(VariableDeclarationStatement statement, ISplitOperation splitOperator, ASTRewrite rewrite) { 450 451 List fragments= statement.fragments(); 452 Iterator iter= fragments.iterator(); 453 VariableDeclarationFragment lastFragment= (VariableDeclarationFragment)iter.next(); 454 VariableDeclarationStatement lastStatement= statement; 455 456 splitOperator.initializeStatement(lastStatement, lastFragment); 457 458 ListRewrite fragmentsRewrite= null; 459 while (iter.hasNext()) { 460 VariableDeclarationFragment currentFragment= (VariableDeclarationFragment)iter.next(); 461 462 if (splitOperator.needsSplit(lastFragment, currentFragment)) { 463 464 VariableDeclarationStatement newStatement= getAst().newVariableDeclarationStatement((VariableDeclarationFragment)rewrite.createMoveTarget(currentFragment)); 465 466 ListRewrite modifierRewrite= rewrite.getListRewrite(newStatement, VariableDeclarationStatement.MODIFIERS2_PROPERTY); 467 for (Iterator iterator= statement.modifiers().iterator(); iterator.hasNext();) { 468 modifierRewrite.insertLast(rewrite.createCopyTarget((ASTNode)iterator.next()), null); 469 } 470 471 newStatement.setType((Type)rewrite.createCopyTarget(statement.getType())); 472 473 splitOperator.initializeStatement(newStatement, currentFragment); 474 475 fragmentsRewrite= rewrite.getListRewrite(newStatement, VariableDeclarationStatement.FRAGMENTS_PROPERTY); 476 477 lastStatement= newStatement; 478 } else if (fragmentsRewrite != null) { 479 ASTNode fragment0= rewrite.createMoveTarget(currentFragment); 480 fragmentsRewrite.insertLast(fragment0, null); 481 } 482 lastFragment= currentFragment; 483 } 484 } 485 486 491 protected static void makeFinal(VariableDeclarationStatement statement, ASTRewrite rewrite) { 492 VariableDeclaration fragment= (VariableDeclaration)statement.fragments().get(0); 493 if (ASTNodes.findModifierNode(Modifier.FINAL, ASTNodes.getModifiers(fragment)) == null) { 494 ModifierRewrite.create(rewrite, statement).setModifiers(Modifier.FINAL, Modifier.NONE, null); 495 } 496 } 497 498 private void qualifyThisExpressions(ASTNode node, final ASTRewrite rewrite, final ImportRewrite importRewrite) { 499 node.accept(new GenericVisitor() { 500 503 public boolean visit(ThisExpression thisExpr) { 504 if (thisExpr.getQualifier() == null) { 505 ITypeBinding typeBinding= thisExpr.resolveTypeBinding(); 506 if (typeBinding != null) { 507 IJavaElement javaElement= typeBinding.getJavaElement(); 508 if (javaElement instanceof IType) { 509 String typeName= ((IType)javaElement).getElementName(); 510 SimpleName simpleName= thisExpr.getAST().newSimpleName(typeName); 511 rewrite.set(thisExpr, ThisExpression.QUALIFIER_PROPERTY, simpleName, null); 512 } 513 } 514 } 515 return super.visit(thisExpr); 516 } 517 }); 518 } 519 520 526 protected static void splitOffInitializer(List statements, VariableDeclarationFragment fragment, ASTRewrite rewrite) { 527 Expression initializer= fragment.getInitializer(); 528 if (initializer != null) { 529 AST ast= rewrite.getAST(); 530 Assignment assignment= ast.newAssignment(); 531 assignment.setLeftHandSide((Expression)rewrite.createCopyTarget(fragment.getName())); 532 assignment.setRightHandSide((Expression)rewrite.createMoveTarget(initializer)); 533 statements.add(ast.newExpressionStatement(assignment)); 534 } 535 } 536 537 543 private ListRewrite getListRewrite(ASTNode node, ASTRewrite rewrite) { 544 if (node.getLocationInParent() == SwitchStatement.STATEMENTS_PROPERTY) { 545 ASTNode block= ASTNodes.getParent(node, SwitchStatement.class); 546 return rewrite.getListRewrite(block, SwitchStatement.STATEMENTS_PROPERTY); 547 } else { 548 ASTNode block= ASTNodes.getParent(node, Block.class); 549 return rewrite.getListRewrite(block, Block.STATEMENTS_PROPERTY); 550 } 551 } 552 553 protected final AST getAst() { 554 return getRootNode().getAST(); 555 } 556 557 protected final Statement[] getSelectedStatements() { 558 return fSelectedStatements; 559 } 560 561 private CompilationUnit getRootNode() { 562 if (fSelectedStatements.length > 0) 563 return (CompilationUnit)fSelectedStatements[0].getRoot(); 564 return fRootNode; 565 } 566 567 } 568 | Popular Tags |