1 /******************************************************************************* 2 * Copyright (c) 2000, 2019 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * Microsoft Corporation - copied to jdt.core.manipulation 14 *******************************************************************************/ 15 package org.eclipse.jdt.internal.corext.refactoring.code.flow; 16 17 import java.util.ArrayList; 18 import java.util.HashMap; 19 import java.util.Iterator; 20 import java.util.List; 21 22 import org.eclipse.jface.text.IRegion; 23 import org.eclipse.jface.text.Region; 24 25 import org.eclipse.jdt.core.dom.ASTNode; 26 import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; 27 import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration; 28 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; 29 import org.eclipse.jdt.core.dom.ArrayAccess; 30 import org.eclipse.jdt.core.dom.ArrayCreation; 31 import org.eclipse.jdt.core.dom.ArrayInitializer; 32 import org.eclipse.jdt.core.dom.ArrayType; 33 import org.eclipse.jdt.core.dom.AssertStatement; 34 import org.eclipse.jdt.core.dom.Assignment; 35 import org.eclipse.jdt.core.dom.Block; 36 import org.eclipse.jdt.core.dom.BooleanLiteral; 37 import org.eclipse.jdt.core.dom.BreakStatement; 38 import org.eclipse.jdt.core.dom.CastExpression; 39 import org.eclipse.jdt.core.dom.CatchClause; 40 import org.eclipse.jdt.core.dom.CharacterLiteral; 41 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 42 import org.eclipse.jdt.core.dom.CompilationUnit; 43 import org.eclipse.jdt.core.dom.ConditionalExpression; 44 import org.eclipse.jdt.core.dom.ConstructorInvocation; 45 import org.eclipse.jdt.core.dom.ContinueStatement; 46 import org.eclipse.jdt.core.dom.DoStatement; 47 import org.eclipse.jdt.core.dom.EmptyStatement; 48 import org.eclipse.jdt.core.dom.EnhancedForStatement; 49 import org.eclipse.jdt.core.dom.EnumConstantDeclaration; 50 import org.eclipse.jdt.core.dom.EnumDeclaration; 51 import org.eclipse.jdt.core.dom.Expression; 52 import org.eclipse.jdt.core.dom.ExpressionStatement; 53 import org.eclipse.jdt.core.dom.FieldAccess; 54 import org.eclipse.jdt.core.dom.FieldDeclaration; 55 import org.eclipse.jdt.core.dom.ForStatement; 56 import org.eclipse.jdt.core.dom.IBinding; 57 import org.eclipse.jdt.core.dom.IMethodBinding; 58 import org.eclipse.jdt.core.dom.ITypeBinding; 59 import org.eclipse.jdt.core.dom.IVariableBinding; 60 import org.eclipse.jdt.core.dom.IfStatement; 61 import org.eclipse.jdt.core.dom.ImportDeclaration; 62 import org.eclipse.jdt.core.dom.InfixExpression; 63 import org.eclipse.jdt.core.dom.Initializer; 64 import org.eclipse.jdt.core.dom.InstanceofExpression; 65 import org.eclipse.jdt.core.dom.Javadoc; 66 import org.eclipse.jdt.core.dom.LabeledStatement; 67 import org.eclipse.jdt.core.dom.LambdaExpression; 68 import org.eclipse.jdt.core.dom.MarkerAnnotation; 69 import org.eclipse.jdt.core.dom.MemberValuePair; 70 import org.eclipse.jdt.core.dom.MethodDeclaration; 71 import org.eclipse.jdt.core.dom.MethodInvocation; 72 import org.eclipse.jdt.core.dom.Name; 73 import org.eclipse.jdt.core.dom.NameQualifiedType; 74 import org.eclipse.jdt.core.dom.NormalAnnotation; 75 import org.eclipse.jdt.core.dom.NullLiteral; 76 import org.eclipse.jdt.core.dom.NumberLiteral; 77 import org.eclipse.jdt.core.dom.PackageDeclaration; 78 import org.eclipse.jdt.core.dom.ParameterizedType; 79 import org.eclipse.jdt.core.dom.ParenthesizedExpression; 80 import org.eclipse.jdt.core.dom.PostfixExpression; 81 import org.eclipse.jdt.core.dom.PrefixExpression; 82 import org.eclipse.jdt.core.dom.PrimitiveType; 83 import org.eclipse.jdt.core.dom.QualifiedName; 84 import org.eclipse.jdt.core.dom.QualifiedType; 85 import org.eclipse.jdt.core.dom.ReturnStatement; 86 import org.eclipse.jdt.core.dom.SimpleName; 87 import org.eclipse.jdt.core.dom.SimpleType; 88 import org.eclipse.jdt.core.dom.SingleMemberAnnotation; 89 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 90 import org.eclipse.jdt.core.dom.Statement; 91 import org.eclipse.jdt.core.dom.StringLiteral; 92 import org.eclipse.jdt.core.dom.SuperConstructorInvocation; 93 import org.eclipse.jdt.core.dom.SuperFieldAccess; 94 import org.eclipse.jdt.core.dom.SuperMethodInvocation; 95 import org.eclipse.jdt.core.dom.SwitchCase; 96 import org.eclipse.jdt.core.dom.SwitchExpression; 97 import org.eclipse.jdt.core.dom.SwitchStatement; 98 import org.eclipse.jdt.core.dom.SynchronizedStatement; 99 import org.eclipse.jdt.core.dom.ThisExpression; 100 import org.eclipse.jdt.core.dom.ThrowStatement; 101 import org.eclipse.jdt.core.dom.TryStatement; 102 import org.eclipse.jdt.core.dom.TypeDeclaration; 103 import org.eclipse.jdt.core.dom.TypeDeclarationStatement; 104 import org.eclipse.jdt.core.dom.TypeLiteral; 105 import org.eclipse.jdt.core.dom.TypeParameter; 106 import org.eclipse.jdt.core.dom.VariableDeclarationExpression; 107 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 108 import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 109 import org.eclipse.jdt.core.dom.WhileStatement; 110 import org.eclipse.jdt.core.dom.WildcardType; 111 112 import org.eclipse.jdt.internal.corext.dom.GenericVisitor; 113 114 /** 115 * Special flow analyzer to determine the return value of the extracted method 116 * and the variables which have to be passed to the method. 117 * 118 * Note: This analyzer doesn't do a full flow analysis. For example it doesn't 119 * do dead code analysis or variable initialization analysis. It analyses the 120 * the first access to a variable (read or write) and if all execution paths 121 * return a value. 122 */ 123 abstract class FlowAnalyzer extends GenericVisitor { 124 125 static protected class SwitchData { 126 private boolean fHasDefaultCase; 127 private List<IRegion> fRanges= new ArrayList<>(4); 128 private List<FlowInfo> fInfos= new ArrayList<>(4); setHasDefaultCase()129 public void setHasDefaultCase() { 130 fHasDefaultCase= true; 131 } hasDefaultCase()132 public boolean hasDefaultCase() { 133 return fHasDefaultCase; 134 } add(IRegion range, FlowInfo info)135 public void add(IRegion range, FlowInfo info) { 136 fRanges.add(range); 137 fInfos.add(info); 138 } getRanges()139 public IRegion[] getRanges() { 140 return fRanges.toArray(new IRegion[fRanges.size()]); 141 } getInfos()142 public FlowInfo[] getInfos() { 143 return fInfos.toArray(new FlowInfo[fInfos.size()]); 144 } getInfo(int index)145 public FlowInfo getInfo(int index) { 146 return fInfos.get(index); 147 } 148 } 149 150 private HashMap<ASTNode, FlowInfo> fData = new HashMap<>(100); 151 /* package */ FlowContext fFlowContext= null; 152 FlowAnalyzer(FlowContext context)153 public FlowAnalyzer(FlowContext context) { 154 fFlowContext= context; 155 } 156 createReturnFlowInfo(ReturnStatement node)157 protected abstract boolean createReturnFlowInfo(ReturnStatement node); 158 traverseNode(ASTNode node)159 protected abstract boolean traverseNode(ASTNode node); 160 skipNode(ASTNode node)161 protected boolean skipNode(ASTNode node) { 162 return !traverseNode(node); 163 } 164 165 @Override visitNode(ASTNode node)166 protected final boolean visitNode(ASTNode node) { 167 return traverseNode(node); 168 } 169 170 //---- Hooks to create Flow info objects. User may introduce their own infos. 171 createReturn(ReturnStatement statement)172 protected ReturnFlowInfo createReturn(ReturnStatement statement) { 173 return new ReturnFlowInfo(statement); 174 } 175 createThrow()176 protected ThrowFlowInfo createThrow() { 177 return new ThrowFlowInfo(); 178 } 179 createBranch(SimpleName label)180 protected BranchFlowInfo createBranch(SimpleName label) { 181 return new BranchFlowInfo(label, fFlowContext); 182 } 183 createSequential()184 protected GenericSequentialFlowInfo createSequential() { 185 return new GenericSequentialFlowInfo(); 186 } 187 createConditional()188 protected ConditionalFlowInfo createConditional() { 189 return new ConditionalFlowInfo(); 190 } 191 createEnhancedFor()192 protected EnhancedForFlowInfo createEnhancedFor() { 193 return new EnhancedForFlowInfo(); 194 } 195 createFor()196 protected ForFlowInfo createFor() { 197 return new ForFlowInfo(); 198 } 199 createTry()200 protected TryFlowInfo createTry() { 201 return new TryFlowInfo(); 202 } 203 createWhile()204 protected WhileFlowInfo createWhile() { 205 return new WhileFlowInfo(); 206 } 207 createIf()208 protected IfFlowInfo createIf() { 209 return new IfFlowInfo(); 210 } 211 createDoWhile()212 protected DoWhileFlowInfo createDoWhile() { 213 return new DoWhileFlowInfo(); 214 } 215 createSwitch()216 protected SwitchFlowInfo createSwitch() { 217 return new SwitchFlowInfo(); 218 } 219 createBlock()220 protected BlockFlowInfo createBlock() { 221 return new BlockFlowInfo(); 222 } 223 createMessageSendFlowInfo()224 protected MessageSendFlowInfo createMessageSendFlowInfo() { 225 return new MessageSendFlowInfo(); 226 } 227 getFlowContext()228 protected FlowContext getFlowContext() { 229 return fFlowContext; 230 } 231 232 //---- Helpers to access flow analysis objects ---------------------------------------- 233 getFlowInfo(ASTNode node)234 protected FlowInfo getFlowInfo(ASTNode node) { 235 return fData.remove(node); 236 } 237 setFlowInfo(ASTNode node, FlowInfo info)238 protected void setFlowInfo(ASTNode node, FlowInfo info) { 239 fData.put(node, info); 240 } 241 assignFlowInfo(ASTNode target, ASTNode source)242 protected FlowInfo assignFlowInfo(ASTNode target, ASTNode source) { 243 FlowInfo result= getFlowInfo(source); 244 setFlowInfo(target, result); 245 return result; 246 } 247 accessFlowInfo(ASTNode node)248 protected FlowInfo accessFlowInfo(ASTNode node) { 249 return fData.get(node); 250 } 251 252 //---- Helpers to process sequential flow infos ------------------------------------- 253 processSequential(ASTNode parent, List<? extends ASTNode> nodes)254 protected GenericSequentialFlowInfo processSequential(ASTNode parent, List<? extends ASTNode> nodes) { 255 GenericSequentialFlowInfo result= createSequential(parent); 256 process(result, nodes); 257 return result; 258 } 259 processSequential(ASTNode parent, ASTNode node1)260 protected GenericSequentialFlowInfo processSequential(ASTNode parent, ASTNode node1) { 261 GenericSequentialFlowInfo result= createSequential(parent); 262 if (node1 != null) 263 result.merge(getFlowInfo(node1), fFlowContext); 264 return result; 265 } 266 processSequential(ASTNode parent, ASTNode node1, ASTNode node2)267 protected GenericSequentialFlowInfo processSequential(ASTNode parent, ASTNode node1, ASTNode node2) { 268 GenericSequentialFlowInfo result= createSequential(parent); 269 if (node1 != null) 270 result.merge(getFlowInfo(node1), fFlowContext); 271 if (node2 != null) 272 result.merge(getFlowInfo(node2), fFlowContext); 273 return result; 274 } 275 createSequential(ASTNode parent)276 protected GenericSequentialFlowInfo createSequential(ASTNode parent) { 277 GenericSequentialFlowInfo result= createSequential(); 278 setFlowInfo(parent, result); 279 return result; 280 } 281 createSequential(List<? extends ASTNode> nodes)282 protected GenericSequentialFlowInfo createSequential(List<? extends ASTNode> nodes) { 283 GenericSequentialFlowInfo result= createSequential(); 284 process(result, nodes); 285 return result; 286 } 287 288 //---- Generic merge methods -------------------------------------------------------- 289 process(GenericSequentialFlowInfo info, List<? extends ASTNode> nodes)290 protected void process(GenericSequentialFlowInfo info, List<? extends ASTNode> nodes) { 291 if (nodes == null) 292 return; 293 for (ASTNode node : nodes) { 294 info.merge(getFlowInfo(node), fFlowContext); 295 } 296 } 297 process(GenericSequentialFlowInfo info, ASTNode node)298 protected void process(GenericSequentialFlowInfo info, ASTNode node) { 299 if (node != null) 300 info.merge(getFlowInfo(node), fFlowContext); 301 } 302 process(GenericSequentialFlowInfo info, ASTNode node1, ASTNode node2)303 protected void process(GenericSequentialFlowInfo info, ASTNode node1, ASTNode node2) { 304 if (node1 != null) 305 info.merge(getFlowInfo(node1), fFlowContext); 306 if (node2 != null) 307 info.merge(getFlowInfo(node2), fFlowContext); 308 } 309 310 //---- special visit methods ------------------------------------------------------- 311 312 @Override visit(EmptyStatement node)313 public boolean visit(EmptyStatement node) { 314 // Empty statements aren't of any interest. 315 return false; 316 } 317 318 @Override visit(TryStatement node)319 public boolean visit(TryStatement node) { 320 if (traverseNode(node)) { 321 fFlowContext.pushExcptions(node); 322 for (Iterator<Expression> iterator= node.resources().iterator(); iterator.hasNext();) { 323 iterator.next().accept(this); 324 } 325 node.getBody().accept(this); 326 fFlowContext.popExceptions(); 327 List<CatchClause> catchClauses= node.catchClauses(); 328 for (CatchClause catchClause : catchClauses) { 329 catchClause.accept(this); 330 } 331 Block finallyBlock= node.getFinally(); 332 if (finallyBlock != null) { 333 finallyBlock.accept(this); 334 } 335 } 336 return false; 337 } 338 339 //---- Helper to process switch statement ---------------------------------------- 340 createSwitchData(SwitchStatement node)341 protected SwitchData createSwitchData(SwitchStatement node) { 342 return createSwitchData(node.statements()); 343 } 344 createSwitchData(SwitchExpression node)345 protected SwitchData createSwitchData(SwitchExpression node) { 346 return createSwitchData(node.statements()); 347 } 348 createSwitchData(List<Statement> statements)349 protected SwitchData createSwitchData(List<Statement> statements) { 350 SwitchData result= new SwitchData(); 351 if (statements == null || statements.isEmpty()) 352 return result; 353 354 int start= -1, end= -1; 355 GenericSequentialFlowInfo info= null; 356 357 for (Statement statement : statements) { 358 if (statement instanceof SwitchCase) { 359 SwitchCase switchCase= (SwitchCase) statement; 360 if (switchCase.isDefault()) { 361 result.setHasDefaultCase(); 362 } 363 if (info == null) { 364 info= createSequential(); 365 start= statement.getStartPosition(); 366 } else { 367 if (info.isReturn() || info.isPartialReturn() || info.branches()) { 368 result.add(new Region(start, end - start + 1), info); 369 info= createSequential(); 370 start= statement.getStartPosition(); 371 } 372 } 373 } else { 374 info.merge(getFlowInfo(statement), fFlowContext); 375 } 376 end= statement.getStartPosition() + statement.getLength() - 1; 377 } 378 result.add(new Region(start, end - start + 1), info); 379 return result; 380 } 381 endVisit(SwitchStatement node, SwitchData data)382 protected void endVisit(SwitchStatement node, SwitchData data) { 383 preEndVisit(node, node.getExpression(), data); 384 } 385 endVisit(SwitchExpression node, SwitchData data)386 protected void endVisit(SwitchExpression node, SwitchData data) { 387 preEndVisit(node, node.getExpression(), data); 388 } 389 preEndVisit(ASTNode node, Expression expression, SwitchData data)390 private void preEndVisit(ASTNode node, Expression expression, SwitchData data) { 391 SwitchFlowInfo switchFlowInfo= createSwitch(); 392 setFlowInfo(node, switchFlowInfo); 393 switchFlowInfo.mergeTest(getFlowInfo(expression), fFlowContext); 394 for (FlowInfo case1 : data.getInfos()) 395 switchFlowInfo.mergeCase(case1, fFlowContext); 396 switchFlowInfo.mergeDefault(data.hasDefaultCase(), fFlowContext); 397 switchFlowInfo.removeLabel(null); 398 } 399 400 //---- concret endVisit methods --------------------------------------------------- 401 402 @Override endVisit(AnnotationTypeDeclaration node)403 public void endVisit(AnnotationTypeDeclaration node) { 404 if (skipNode(node)) 405 return; 406 GenericSequentialFlowInfo info= processSequential(node, node.bodyDeclarations()); 407 info.setNoReturn(); 408 } 409 410 @Override endVisit(AnnotationTypeMemberDeclaration node)411 public void endVisit(AnnotationTypeMemberDeclaration node) { 412 if (skipNode(node)) 413 return; 414 GenericSequentialFlowInfo info= processSequential(node, node.getType(), node.getDefault()); 415 info.setNoReturn(); 416 } 417 418 @Override endVisit(AnonymousClassDeclaration node)419 public void endVisit(AnonymousClassDeclaration node) { 420 if (skipNode(node)) 421 return; 422 FlowInfo info= processSequential(node, node.bodyDeclarations()); 423 info.setNoReturn(); 424 } 425 426 @Override endVisit(ArrayAccess node)427 public void endVisit(ArrayAccess node) { 428 if (skipNode(node)) 429 return; 430 processSequential(node, node.getArray(), node.getIndex()); 431 } 432 433 @Override endVisit(ArrayCreation node)434 public void endVisit(ArrayCreation node) { 435 if (skipNode(node)) 436 return; 437 GenericSequentialFlowInfo info= processSequential(node, node.getType()); 438 process(info, node.dimensions()); 439 process(info, node.getInitializer()); 440 } 441 442 @Override endVisit(ArrayInitializer node)443 public void endVisit(ArrayInitializer node) { 444 if (skipNode(node)) 445 return; 446 processSequential(node, node.expressions()); 447 } 448 449 @Override endVisit(ArrayType node)450 public void endVisit(ArrayType node) { 451 if (skipNode(node)) 452 return; 453 processSequential(node, node.getElementType()); 454 } 455 456 @Override endVisit(AssertStatement node)457 public void endVisit(AssertStatement node) { 458 if (skipNode(node)) 459 return; 460 IfFlowInfo info= new IfFlowInfo(); 461 setFlowInfo(node, info); 462 info.mergeCondition(getFlowInfo(node.getExpression()), fFlowContext); 463 info.merge(getFlowInfo(node.getMessage()), null, fFlowContext); 464 } 465 466 @Override endVisit(Assignment node)467 public void endVisit(Assignment node) { 468 if (skipNode(node)) 469 return; 470 FlowInfo lhs= getFlowInfo(node.getLeftHandSide()); 471 FlowInfo rhs= getFlowInfo(node.getRightHandSide()); 472 if (lhs instanceof LocalFlowInfo) { 473 LocalFlowInfo llhs= (LocalFlowInfo)lhs; 474 llhs.setWriteAccess(fFlowContext); 475 if (node.getOperator() != Assignment.Operator.ASSIGN) { 476 GenericSequentialFlowInfo tmp= createSequential(); 477 tmp.merge(new LocalFlowInfo(llhs, FlowInfo.READ, fFlowContext), fFlowContext); 478 tmp.merge(rhs, fFlowContext); 479 rhs= tmp; 480 } 481 } 482 GenericSequentialFlowInfo info= createSequential(node); 483 // first process right and side and then left hand side. 484 info.merge(rhs, fFlowContext); 485 info.merge(lhs, fFlowContext); 486 } 487 488 @Override endVisit(Block node)489 public void endVisit(Block node) { 490 if (skipNode(node)) 491 return; 492 BlockFlowInfo info= createBlock(); 493 setFlowInfo(node, info); 494 process(info, node.statements()); 495 } 496 497 @Override endVisit(BooleanLiteral node)498 public void endVisit(BooleanLiteral node) { 499 // Leaf node. 500 } 501 502 @Override endVisit(BreakStatement node)503 public void endVisit(BreakStatement node) { 504 if (skipNode(node)) 505 return; 506 setFlowInfo(node, createBranch(node.getLabel())); 507 } 508 509 @Override endVisit(CastExpression node)510 public void endVisit(CastExpression node) { 511 if (skipNode(node)) 512 return; 513 processSequential(node, node.getType(), node.getExpression()); 514 } 515 516 @Override endVisit(CatchClause node)517 public void endVisit(CatchClause node) { 518 if (skipNode(node)) 519 return; 520 processSequential(node, node.getException(), node.getBody()); 521 } 522 523 @Override endVisit(CharacterLiteral node)524 public void endVisit(CharacterLiteral node) { 525 // Leaf node. 526 } 527 528 @Override endVisit(ClassInstanceCreation node)529 public void endVisit(ClassInstanceCreation node) { 530 if (skipNode(node)) 531 return; 532 GenericSequentialFlowInfo info= processSequential(node, node.getExpression()); 533 process(info, node.getType()); 534 process(info, node.arguments()); 535 process(info, node.getAnonymousClassDeclaration()); 536 } 537 538 @Override endVisit(CompilationUnit node)539 public void endVisit(CompilationUnit node) { 540 if (skipNode(node)) 541 return; 542 GenericSequentialFlowInfo info= processSequential(node, node.imports()); 543 process(info, node.types()); 544 } 545 546 @Override endVisit(ConditionalExpression node)547 public void endVisit(ConditionalExpression node) { 548 if (skipNode(node)) 549 return; 550 ConditionalFlowInfo info= createConditional(); 551 setFlowInfo(node, info); 552 info.mergeCondition(getFlowInfo(node.getExpression()), fFlowContext); 553 info.merge( 554 getFlowInfo(node.getThenExpression()), 555 getFlowInfo(node.getElseExpression()), 556 fFlowContext); 557 } 558 559 @Override endVisit(ConstructorInvocation node)560 public void endVisit(ConstructorInvocation node) { 561 if (skipNode(node)) 562 return; 563 processSequential(node, node.arguments()); 564 } 565 566 @Override endVisit(ContinueStatement node)567 public void endVisit(ContinueStatement node) { 568 if (skipNode(node)) 569 return; 570 setFlowInfo(node, createBranch(node.getLabel())); 571 } 572 573 @Override endVisit(DoStatement node)574 public void endVisit(DoStatement node) { 575 if (skipNode(node)) 576 return; 577 DoWhileFlowInfo info= createDoWhile(); 578 setFlowInfo(node, info); 579 info.mergeAction(getFlowInfo(node.getBody()), fFlowContext); 580 info.mergeCondition(getFlowInfo(node.getExpression()), fFlowContext); 581 info.removeLabel(null); 582 } 583 584 @Override endVisit(EmptyStatement node)585 public void endVisit(EmptyStatement node) { 586 // Leaf node. 587 } 588 589 @Override endVisit(EnhancedForStatement node)590 public void endVisit(EnhancedForStatement node) { 591 if (skipNode(node)) 592 return; 593 EnhancedForFlowInfo forInfo= createEnhancedFor(); 594 setFlowInfo(node, forInfo); 595 forInfo.mergeParameter(getFlowInfo(node.getParameter()), fFlowContext); 596 forInfo.mergeExpression(getFlowInfo(node.getExpression()), fFlowContext); 597 forInfo.mergeAction(getFlowInfo(node.getBody()), fFlowContext); 598 forInfo.removeLabel(null); 599 } 600 601 @Override endVisit(EnumConstantDeclaration node)602 public void endVisit(EnumConstantDeclaration node) { 603 if (skipNode(node)) 604 return; 605 GenericSequentialFlowInfo info= processSequential(node, node.arguments()); 606 process(info, node.getAnonymousClassDeclaration()); 607 } 608 609 @Override endVisit(EnumDeclaration node)610 public void endVisit(EnumDeclaration node) { 611 if (skipNode(node)) 612 return; 613 GenericSequentialFlowInfo info= processSequential(node, node.superInterfaceTypes()); 614 process(info, node.enumConstants()); 615 process(info, node.bodyDeclarations()); 616 info.setNoReturn(); 617 } 618 619 @Override endVisit(ExpressionStatement node)620 public void endVisit(ExpressionStatement node) { 621 if (skipNode(node)) 622 return; 623 assignFlowInfo(node, node.getExpression()); 624 } 625 626 @Override endVisit(FieldAccess node)627 public void endVisit(FieldAccess node) { 628 if (skipNode(node)) 629 return; 630 processSequential(node, node.getExpression(), node.getName()); 631 } 632 633 @Override endVisit(FieldDeclaration node)634 public void endVisit(FieldDeclaration node) { 635 if (skipNode(node)) 636 return; 637 GenericSequentialFlowInfo info= processSequential(node, node.getType()); 638 process(info, node.fragments()); 639 } 640 641 @Override endVisit(ForStatement node)642 public void endVisit(ForStatement node) { 643 if (skipNode(node)) 644 return; 645 ForFlowInfo forInfo= createFor(); 646 setFlowInfo(node, forInfo); 647 forInfo.mergeInitializer(createSequential(node.initializers()), fFlowContext); 648 forInfo.mergeCondition(getFlowInfo(node.getExpression()), fFlowContext); 649 forInfo.mergeAction(getFlowInfo(node.getBody()), fFlowContext); 650 // Increments are executed after the action. 651 forInfo.mergeIncrement(createSequential(node.updaters()), fFlowContext); 652 forInfo.removeLabel(null); 653 } 654 655 @Override endVisit(IfStatement node)656 public void endVisit(IfStatement node) { 657 if (skipNode(node)) 658 return; 659 IfFlowInfo info= createIf(); 660 setFlowInfo(node, info); 661 info.mergeCondition(getFlowInfo(node.getExpression()), fFlowContext); 662 info.merge(getFlowInfo(node.getThenStatement()), getFlowInfo(node.getElseStatement()), fFlowContext); 663 } 664 665 @Override endVisit(ImportDeclaration node)666 public void endVisit(ImportDeclaration node) { 667 if (skipNode(node)) 668 return; 669 assignFlowInfo(node, node.getName()); 670 } 671 672 @Override endVisit(InfixExpression node)673 public void endVisit(InfixExpression node) { 674 if (skipNode(node)) 675 return; 676 GenericSequentialFlowInfo info= processSequential(node, node.getLeftOperand(), node.getRightOperand()); 677 process(info, node.extendedOperands()); 678 } 679 680 @Override endVisit(InstanceofExpression node)681 public void endVisit(InstanceofExpression node) { 682 if (skipNode(node)) 683 return; 684 processSequential(node, node.getLeftOperand(), node.getRightOperand()); 685 } 686 687 @Override endVisit(Initializer node)688 public void endVisit(Initializer node) { 689 if (skipNode(node)) 690 return; 691 assignFlowInfo(node, node.getBody()); 692 } 693 694 @Override endVisit(Javadoc node)695 public void endVisit(Javadoc node) { 696 // no influence on flow analysis 697 } 698 699 @Override endVisit(LabeledStatement node)700 public void endVisit(LabeledStatement node) { 701 if (skipNode(node)) 702 return; 703 FlowInfo info= assignFlowInfo(node, node.getBody()); 704 if (info != null) 705 info.removeLabel(node.getLabel()); 706 } 707 708 @Override endVisit(LambdaExpression node)709 public void endVisit(LambdaExpression node) { 710 if (skipNode(node)) 711 return; 712 GenericSequentialFlowInfo info= createSequential(node); 713 process(info, node.parameters()); 714 process(info, node.getBody()); 715 info.setNoReturn(); 716 } 717 718 @Override endVisit(MarkerAnnotation node)719 public void endVisit(MarkerAnnotation node) { 720 // nothing to do for marker annotations; 721 } 722 723 @Override endVisit(MemberValuePair node)724 public void endVisit(MemberValuePair node) { 725 if (skipNode(node)) 726 return; 727 728 FlowInfo name= getFlowInfo(node.getName()); 729 FlowInfo value= getFlowInfo(node.getValue()); 730 if (name instanceof LocalFlowInfo) { 731 LocalFlowInfo llhs= (LocalFlowInfo)name; 732 llhs.setWriteAccess(fFlowContext); 733 } 734 GenericSequentialFlowInfo info= createSequential(node); 735 // first process value and then name. 736 info.merge(value, fFlowContext); 737 info.merge(name, fFlowContext); 738 739 } 740 741 @Override endVisit(MethodDeclaration node)742 public void endVisit(MethodDeclaration node) { 743 if (skipNode(node)) 744 return; 745 GenericSequentialFlowInfo info= processSequential(node, node.getReturnType2()); 746 process(info, node.parameters()); 747 process(info, node.thrownExceptionTypes()); 748 process(info, node.getBody()); 749 } 750 751 @Override endVisit(MethodInvocation node)752 public void endVisit(MethodInvocation node) { 753 endVisitMethodInvocation(node, node.getExpression(), node.arguments(), getMethodBinding(node.getName())); 754 } 755 756 @Override endVisit(NameQualifiedType node)757 public void endVisit(NameQualifiedType node) { 758 if (skipNode(node)) 759 return; 760 processSequential(node, node.getQualifier(), node.getName()); 761 } 762 763 @Override endVisit(NormalAnnotation node)764 public void endVisit(NormalAnnotation node) { 765 if (skipNode(node)) 766 return; 767 GenericSequentialFlowInfo info= processSequential(node, node.getTypeName()); 768 process(info, node.values()); 769 } 770 771 @Override endVisit(NullLiteral node)772 public void endVisit(NullLiteral node) { 773 // Leaf node. 774 } 775 776 @Override endVisit(NumberLiteral node)777 public void endVisit(NumberLiteral node) { 778 // Leaf node. 779 } 780 781 @Override endVisit(PackageDeclaration node)782 public void endVisit(PackageDeclaration node) { 783 if (skipNode(node)) 784 return; 785 assignFlowInfo(node, node.getName()); 786 } 787 788 @Override endVisit(ParameterizedType node)789 public void endVisit(ParameterizedType node) { 790 if (skipNode(node)) 791 return; 792 GenericSequentialFlowInfo info= processSequential(node, node.getType()); 793 process(info, node.typeArguments()); 794 } 795 796 @Override endVisit(ParenthesizedExpression node)797 public void endVisit(ParenthesizedExpression node) { 798 if (skipNode(node)) 799 return; 800 assignFlowInfo(node, node.getExpression()); 801 } 802 803 @Override endVisit(PostfixExpression node)804 public void endVisit(PostfixExpression node) { 805 endVisitIncDecOperation(node, node.getOperand()); 806 } 807 808 @Override endVisit(PrefixExpression node)809 public void endVisit(PrefixExpression node) { 810 PrefixExpression.Operator op= node.getOperator(); 811 if (PrefixExpression.Operator.INCREMENT.equals(op) || PrefixExpression.Operator.DECREMENT.equals(op)) { 812 endVisitIncDecOperation(node, node.getOperand()); 813 } else { 814 assignFlowInfo(node, node.getOperand()); 815 } 816 } 817 818 @Override endVisit(PrimitiveType node)819 public void endVisit(PrimitiveType node) { 820 // Leaf node 821 } 822 823 @Override endVisit(QualifiedName node)824 public void endVisit(QualifiedName node) { 825 if (skipNode(node)) 826 return; 827 processSequential(node, node.getQualifier(), node.getName()); 828 } 829 830 @Override endVisit(QualifiedType node)831 public void endVisit(QualifiedType node) { 832 if (skipNode(node)) 833 return; 834 processSequential(node, node.getQualifier(), node.getName()); 835 } 836 837 @Override endVisit(ReturnStatement node)838 public void endVisit(ReturnStatement node) { 839 if (skipNode(node)) 840 return; 841 842 if (createReturnFlowInfo(node)) { 843 ReturnFlowInfo info= createReturn(node); 844 setFlowInfo(node, info); 845 info.merge(getFlowInfo(node.getExpression()), fFlowContext); 846 } else { 847 assignFlowInfo(node, node.getExpression()); 848 } 849 } 850 851 @Override endVisit(SimpleName node)852 public void endVisit(SimpleName node) { 853 if (skipNode(node) || node.isDeclaration()) 854 return; 855 IBinding binding= node.resolveBinding(); 856 if (binding instanceof IVariableBinding) { 857 IVariableBinding variable= (IVariableBinding)binding; 858 if (!variable.isField()) { 859 setFlowInfo(node, new LocalFlowInfo( 860 variable, 861 FlowInfo.READ, 862 fFlowContext)); 863 } 864 } else if (binding instanceof ITypeBinding) { 865 ITypeBinding type= (ITypeBinding)binding; 866 if (type.isTypeVariable()) { 867 setFlowInfo(node, new TypeVariableFlowInfo(type, fFlowContext)); 868 } 869 } 870 } 871 872 @Override endVisit(SimpleType node)873 public void endVisit(SimpleType node) { 874 if (skipNode(node)) 875 return; 876 assignFlowInfo(node, node.getName()); 877 } 878 879 @Override endVisit(SingleMemberAnnotation node)880 public void endVisit(SingleMemberAnnotation node) { 881 if (skipNode(node)) 882 return; 883 assignFlowInfo(node, node.getValue()); 884 } 885 886 @Override endVisit(SingleVariableDeclaration node)887 public void endVisit(SingleVariableDeclaration node) { 888 if (skipNode(node)) 889 return; 890 891 IVariableBinding binding= node.resolveBinding(); 892 LocalFlowInfo nameInfo= null; 893 Expression initializer= node.getInitializer(); 894 if (binding != null && !binding.isField() && initializer != null) { 895 nameInfo= new LocalFlowInfo(binding, FlowInfo.WRITE, fFlowContext); 896 } 897 GenericSequentialFlowInfo info= processSequential(node, node.getType(), initializer); 898 info.merge(nameInfo, fFlowContext); 899 } 900 901 @Override endVisit(StringLiteral node)902 public void endVisit(StringLiteral node) { 903 // Leaf node 904 } 905 906 @Override endVisit(SuperConstructorInvocation node)907 public void endVisit(SuperConstructorInvocation node) { 908 endVisitMethodInvocation(node, node.getExpression(), node.arguments(), node.resolveConstructorBinding()); 909 } 910 911 @Override endVisit(SuperFieldAccess node)912 public void endVisit(SuperFieldAccess node) { 913 if (skipNode(node)) 914 return; 915 processSequential(node, node.getQualifier(), node.getName()); 916 } 917 918 @Override endVisit(SuperMethodInvocation node)919 public void endVisit(SuperMethodInvocation node) { 920 endVisitMethodInvocation(node, node.getQualifier(), node.arguments(), getMethodBinding(node.getName())); 921 } 922 923 @Override endVisit(SwitchCase node)924 public void endVisit(SwitchCase node) { 925 endVisitNode(node); 926 } 927 928 @Override endVisit(SwitchStatement node)929 public void endVisit(SwitchStatement node) { 930 if (skipNode(node)) 931 return; 932 endVisit(node, createSwitchData(node)); 933 } 934 935 @Override endVisit(SwitchExpression node)936 public void endVisit(SwitchExpression node) { 937 if (skipNode(node)) 938 return; 939 endVisit(node, createSwitchData(node)); 940 } 941 942 @Override endVisit(SynchronizedStatement node)943 public void endVisit(SynchronizedStatement node) { 944 if (skipNode(node)) 945 return; 946 GenericSequentialFlowInfo info= processSequential(node, node.getExpression()); 947 process(info, node.getBody()); 948 } 949 950 @Override endVisit(ThisExpression node)951 public void endVisit(ThisExpression node) { 952 if (skipNode(node)) 953 return; 954 assignFlowInfo(node, node.getQualifier()); 955 } 956 957 @Override endVisit(ThrowStatement node)958 public void endVisit(ThrowStatement node) { 959 if (skipNode(node)) 960 return; 961 ThrowFlowInfo info= createThrow(); 962 setFlowInfo(node, info); 963 Expression expression= node.getExpression(); 964 info.merge(getFlowInfo(expression), fFlowContext); 965 } 966 967 @Override endVisit(TryStatement node)968 public void endVisit(TryStatement node) { 969 if (skipNode(node)) 970 return; 971 TryFlowInfo info= createTry(); 972 setFlowInfo(node, info); 973 for (Iterator<Expression> iterator= node.resources().iterator(); iterator.hasNext();) { 974 info.mergeResources(getFlowInfo(iterator.next()), fFlowContext); 975 } 976 info.mergeTry(getFlowInfo(node.getBody()), fFlowContext); 977 for (Iterator<CatchClause> iter= node.catchClauses().iterator(); iter.hasNext();) { 978 CatchClause element= iter.next(); 979 info.mergeCatch(getFlowInfo(element), fFlowContext); 980 } 981 info.mergeFinally(getFlowInfo(node.getFinally()), fFlowContext); 982 } 983 984 // TODO account for enums and annotations 985 986 @Override endVisit(TypeDeclaration node)987 public void endVisit(TypeDeclaration node) { 988 if (skipNode(node)) 989 return; 990 GenericSequentialFlowInfo info= processSequential(node, node.getSuperclassType()); 991 process(info, node.superInterfaceTypes()); 992 process(info, node.bodyDeclarations()); 993 info.setNoReturn(); 994 } 995 996 @Override endVisit(TypeDeclarationStatement node)997 public void endVisit(TypeDeclarationStatement node) { 998 if (skipNode(node)) 999 return; 1000 assignFlowInfo(node, node.getDeclaration()); 1001 } 1002 1003 @Override endVisit(TypeLiteral node)1004 public void endVisit(TypeLiteral node) { 1005 if (skipNode(node)) 1006 return; 1007 assignFlowInfo(node, node.getType()); 1008 } 1009 1010 @Override endVisit(TypeParameter node)1011 public void endVisit(TypeParameter node) { 1012 if (skipNode(node)) 1013 return; 1014 GenericSequentialFlowInfo info= processSequential(node, node.getName()); 1015 process(info, node.typeBounds()); 1016 } 1017 1018 @Override endVisit(VariableDeclarationExpression node)1019 public void endVisit(VariableDeclarationExpression node) { 1020 if (skipNode(node)) 1021 return; 1022 GenericSequentialFlowInfo info= processSequential(node, node.getType()); 1023 process(info, node.fragments()); 1024 } 1025 1026 @Override endVisit(VariableDeclarationStatement node)1027 public void endVisit(VariableDeclarationStatement node) { 1028 if (skipNode(node)) 1029 return; 1030 GenericSequentialFlowInfo info= processSequential(node, node.getType()); 1031 process(info, node.fragments()); 1032 } 1033 1034 @Override endVisit(VariableDeclarationFragment node)1035 public void endVisit(VariableDeclarationFragment node) { 1036 if (skipNode(node)) 1037 return; 1038 1039 IVariableBinding binding= node.resolveBinding(); 1040 LocalFlowInfo nameInfo= null; 1041 Expression initializer= node.getInitializer(); 1042 if (binding != null && !binding.isField() && initializer != null) { 1043 nameInfo= new LocalFlowInfo(binding, FlowInfo.WRITE, fFlowContext); 1044 } 1045 GenericSequentialFlowInfo info= processSequential(node, initializer); 1046 info.merge(nameInfo, fFlowContext); 1047 } 1048 1049 @Override endVisit(WhileStatement node)1050 public void endVisit(WhileStatement node) { 1051 if (skipNode(node)) 1052 return; 1053 WhileFlowInfo info= createWhile(); 1054 setFlowInfo(node, info); 1055 info.mergeCondition(getFlowInfo(node.getExpression()), fFlowContext); 1056 info.mergeAction(getFlowInfo(node.getBody()), fFlowContext); 1057 info.removeLabel(null); 1058 } 1059 1060 @Override endVisit(WildcardType node)1061 public void endVisit(WildcardType node) { 1062 if (skipNode(node)) 1063 return; 1064 assignFlowInfo(node, node.getBound()); 1065 } 1066 endVisitMethodInvocation(ASTNode node, ASTNode receiver, List<Expression> arguments, IMethodBinding binding)1067 private void endVisitMethodInvocation(ASTNode node, ASTNode receiver, List<Expression> arguments, IMethodBinding binding) { 1068 if (skipNode(node)) 1069 return; 1070 MessageSendFlowInfo info= createMessageSendFlowInfo(); 1071 setFlowInfo(node, info); 1072 for (Expression arg : arguments) { 1073 info.mergeArgument(getFlowInfo(arg), fFlowContext); 1074 } 1075 info.mergeReceiver(getFlowInfo(receiver), fFlowContext); 1076 } 1077 endVisitIncDecOperation(Expression node, Expression operand)1078 private void endVisitIncDecOperation(Expression node, Expression operand) { 1079 if (skipNode(node)) 1080 return; 1081 FlowInfo info= getFlowInfo(operand); 1082 if (info instanceof LocalFlowInfo) { 1083 // Normally we should do this in the parent node since the write access take place later. 1084 // But I couldn't come up with a case where this influences the flow analysis. So I kept 1085 // it here to simplify the code. 1086 GenericSequentialFlowInfo result= createSequential(node); 1087 result.merge(info, fFlowContext); 1088 result.merge( 1089 new LocalFlowInfo((LocalFlowInfo)info, FlowInfo.WRITE, fFlowContext), 1090 fFlowContext); 1091 } else { 1092 setFlowInfo(node, info); 1093 } 1094 } 1095 getMethodBinding(Name name)1096 private IMethodBinding getMethodBinding(Name name) { 1097 if (name == null) 1098 return null; 1099 IBinding binding= name.resolveBinding(); 1100 if (binding instanceof IMethodBinding) 1101 return (IMethodBinding)binding; 1102 return null; 1103 } 1104 } 1105