1 /* 2 * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 //todo: one might eliminate uninits.andSets when monotonic 27 28 package com.sun.tools.javac.comp; 29 30 import java.util.HashMap; 31 32 import com.sun.tools.javac.code.*; 33 import com.sun.tools.javac.tree.*; 34 import com.sun.tools.javac.util.*; 35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 36 37 import com.sun.tools.javac.code.Symbol.*; 38 import com.sun.tools.javac.tree.JCTree.*; 39 40 import static com.sun.tools.javac.code.Flags.*; 41 import static com.sun.tools.javac.code.Kinds.*; 42 import static com.sun.tools.javac.code.TypeTags.*; 43 44 /** This pass implements dataflow analysis for Java programs. 45 * Liveness analysis checks that every statement is reachable. 46 * Exception analysis ensures that every checked exception that is 47 * thrown is declared or caught. Definite assignment analysis 48 * ensures that each variable is assigned when used. Definite 49 * unassignment analysis ensures that no final variable is assigned 50 * more than once. 51 * 52 * <p>The second edition of the JLS has a number of problems in the 53 * specification of these flow analysis problems. This implementation 54 * attempts to address those issues. 55 * 56 * <p>First, there is no accommodation for a finally clause that cannot 57 * complete normally. For liveness analysis, an intervening finally 58 * clause can cause a break, continue, or return not to reach its 59 * target. For exception analysis, an intervening finally clause can 60 * cause any exception to be "caught". For DA/DU analysis, the finally 61 * clause can prevent a transfer of control from propagating DA/DU 62 * state to the target. In addition, code in the finally clause can 63 * affect the DA/DU status of variables. 64 * 65 * <p>For try statements, we introduce the idea of a variable being 66 * definitely unassigned "everywhere" in a block. A variable V is 67 * "unassigned everywhere" in a block iff it is unassigned at the 68 * beginning of the block and there is no reachable assignment to V 69 * in the block. An assignment V=e is reachable iff V is not DA 70 * after e. Then we can say that V is DU at the beginning of the 71 * catch block iff V is DU everywhere in the try block. Similarly, V 72 * is DU at the beginning of the finally block iff V is DU everywhere 73 * in the try block and in every catch block. Specifically, the 74 * following bullet is added to 16.2.2 75 * <pre> 76 * V is <em>unassigned everywhere</em> in a block if it is 77 * unassigned before the block and there is no reachable 78 * assignment to V within the block. 79 * </pre> 80 * <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all 81 * try blocks is changed to 82 * <pre> 83 * V is definitely unassigned before a catch block iff V is 84 * definitely unassigned everywhere in the try block. 85 * </pre> 86 * <p>The last bullet (and all of its sub-bullets) for try blocks that 87 * have a finally block is changed to 88 * <pre> 89 * V is definitely unassigned before the finally block iff 90 * V is definitely unassigned everywhere in the try block 91 * and everywhere in each catch block of the try statement. 92 * </pre> 93 * <p>In addition, 94 * <pre> 95 * V is definitely assigned at the end of a constructor iff 96 * V is definitely assigned after the block that is the body 97 * of the constructor and V is definitely assigned at every 98 * return that can return from the constructor. 99 * </pre> 100 * <p>In addition, each continue statement with the loop as its target 101 * is treated as a jump to the end of the loop body, and "intervening" 102 * finally clauses are treated as follows: V is DA "due to the 103 * continue" iff V is DA before the continue statement or V is DA at 104 * the end of any intervening finally block. V is DU "due to the 105 * continue" iff any intervening finally cannot complete normally or V 106 * is DU at the end of every intervening finally block. This "due to 107 * the continue" concept is then used in the spec for the loops. 108 * 109 * <p>Similarly, break statements must consider intervening finally 110 * blocks. For liveness analysis, a break statement for which any 111 * intervening finally cannot complete normally is not considered to 112 * cause the target statement to be able to complete normally. Then 113 * we say V is DA "due to the break" iff V is DA before the break or 114 * V is DA at the end of any intervening finally block. V is DU "due 115 * to the break" iff any intervening finally cannot complete normally 116 * or V is DU at the break and at the end of every intervening 117 * finally block. (I suspect this latter condition can be 118 * simplified.) This "due to the break" is then used in the spec for 119 * all statements that can be "broken". 120 * 121 * <p>The return statement is treated similarly. V is DA "due to a 122 * return statement" iff V is DA before the return statement or V is 123 * DA at the end of any intervening finally block. Note that we 124 * don't have to worry about the return expression because this 125 * concept is only used for construcrors. 126 * 127 * <p>There is no spec in JLS2 for when a variable is definitely 128 * assigned at the end of a constructor, which is needed for final 129 * fields (8.3.1.2). We implement the rule that V is DA at the end 130 * of the constructor iff it is DA and the end of the body of the 131 * constructor and V is DA "due to" every return of the constructor. 132 * 133 * <p>Intervening finally blocks similarly affect exception analysis. An 134 * intervening finally that cannot complete normally allows us to ignore 135 * an otherwise uncaught exception. 136 * 137 * <p>To implement the semantics of intervening finally clauses, all 138 * nonlocal transfers (break, continue, return, throw, method call that 139 * can throw a checked exception, and a constructor invocation that can 140 * thrown a checked exception) are recorded in a queue, and removed 141 * from the queue when we complete processing the target of the 142 * nonlocal transfer. This allows us to modify the queue in accordance 143 * with the above rules when we encounter a finally clause. The only 144 * exception to this [no pun intended] is that checked exceptions that 145 * are known to be caught or declared to be caught in the enclosing 146 * method are not recorded in the queue, but instead are recorded in a 147 * global variable "Set<Type> thrown" that records the type of all 148 * exceptions that can be thrown. 149 * 150 * <p>Other minor issues the treatment of members of other classes 151 * (always considered DA except that within an anonymous class 152 * constructor, where DA status from the enclosing scope is 153 * preserved), treatment of the case expression (V is DA before the 154 * case expression iff V is DA after the switch expression), 155 * treatment of variables declared in a switch block (the implied 156 * DA/DU status after the switch expression is DU and not DA for 157 * variables defined in a switch block), the treatment of boolean ?: 158 * expressions (The JLS rules only handle b and c non-boolean; the 159 * new rule is that if b and c are boolean valued, then V is 160 * (un)assigned after a?b:c when true/false iff V is (un)assigned 161 * after b when true/false and V is (un)assigned after c when 162 * true/false). 163 * 164 * <p>There is the remaining question of what syntactic forms constitute a 165 * reference to a variable. It is conventional to allow this.x on the 166 * left-hand-side to initialize a final instance field named x, yet 167 * this.x isn't considered a "use" when appearing on a right-hand-side 168 * in most implementations. Should parentheses affect what is 169 * considered a variable reference? The simplest rule would be to 170 * allow unqualified forms only, parentheses optional, and phase out 171 * support for assigning to a final field via this.x. 172 * 173 * <p><b>This is NOT part of any supported API. 174 * If you write code that depends on this, you do so at your own risk. 175 * This code and its internal interfaces are subject to change or 176 * deletion without notice.</b> 177 */ 178 public class Flow extends TreeScanner { 179 protected static final Context.Key<Flow> flowKey = 180 new Context.Key<Flow>(); 181 182 private final Names names; 183 private final Log log; 184 private final Symtab syms; 185 private final Types types; 186 private final Check chk; 187 private TreeMaker make; 188 private Lint lint; 189 private final boolean allowRethrowAnalysis; 190 191 public static Flow instance(Context context) { 192 Flow instance = context.get(flowKey); 193 if (instance == null) 194 instance = new Flow(context); 195 return instance; 196 } 197 198 protected Flow(Context context) { 199 context.put(flowKey, this); 200 names = Names.instance(context); 201 log = Log.instance(context); 202 syms = Symtab.instance(context); 203 types = Types.instance(context); 204 chk = Check.instance(context); 205 lint = Lint.instance(context); 206 Source source = Source.instance(context); 207 allowRethrowAnalysis = source.allowMulticatch(); 208 } 209 210 /** A flag that indicates whether the last statement could 211 * complete normally. 212 */ 213 private boolean alive; 214 215 /** The set of definitely assigned variables. 216 */ 217 Bits inits; 218 219 /** The set of definitely unassigned variables. 220 */ 221 Bits uninits; 222 223 HashMap<Symbol, List<Type>> multicatchTypes; 224 225 /** The set of variables that are definitely unassigned everywhere 226 * in current try block. This variable is maintained lazily; it is 227 * updated only when something gets removed from uninits, 228 * typically by being assigned in reachable code. To obtain the 229 * correct set of variables which are definitely unassigned 230 * anywhere in current try block, intersect uninitsTry and 231 * uninits. 232 */ 233 Bits uninitsTry; 234 235 /** When analyzing a condition, inits and uninits are null. 236 * Instead we have: 237 */ 238 Bits initsWhenTrue; 239 Bits initsWhenFalse; 240 Bits uninitsWhenTrue; 241 Bits uninitsWhenFalse; 242 243 /** A mapping from addresses to variable symbols. 244 */ 245 VarSymbol[] vars; 246 247 /** The current class being defined. 248 */ 249 JCClassDecl classDef; 250 251 /** The first variable sequence number in this class definition. 252 */ 253 int firstadr; 254 255 /** The next available variable sequence number. 256 */ 257 int nextadr; 258 259 /** The list of possibly thrown declarable exceptions. 260 */ 261 List<Type> thrown; 262 263 /** The list of exceptions that are either caught or declared to be 264 * thrown. 265 */ 266 List<Type> caught; 267 268 /** The list of unreferenced automatic resources. 269 */ 270 List<Symbol> unrefdResources; 271 272 /** Set when processing a loop body the second time for DU analysis. */ 273 boolean loopPassTwo = false; 274 275 /*-------------------- Environments ----------------------*/ 276 277 /** A pending exit. These are the statements return, break, and 278 * continue. In addition, exception-throwing expressions or 279 * statements are put here when not known to be caught. This 280 * will typically result in an error unless it is within a 281 * try-finally whose finally block cannot complete normally. 282 */ 283 static class PendingExit { 284 JCTree tree; 285 Bits inits; 286 Bits uninits; 287 Type thrown; 288 PendingExit(JCTree tree, Bits inits, Bits uninits) { 289 this.tree = tree; 290 this.inits = inits.dup(); 291 this.uninits = uninits.dup(); 292 } 293 PendingExit(JCTree tree, Type thrown) { 294 this.tree = tree; 295 this.thrown = thrown; 296 } 297 } 298 299 /** The currently pending exits that go from current inner blocks 300 * to an enclosing block, in source order. 301 */ 302 ListBuffer<PendingExit> pendingExits; 303 304 /*-------------------- Exceptions ----------------------*/ 305 306 /** Complain that pending exceptions are not caught. 307 */ 308 void errorUncaught() { 309 for (PendingExit exit = pendingExits.next(); 310 exit != null; 311 exit = pendingExits.next()) { 312 boolean synthetic = classDef != null && 313 classDef.pos == exit.tree.pos; 314 log.error(exit.tree.pos(), 315 synthetic 316 ? "unreported.exception.default.constructor" 317 : "unreported.exception.need.to.catch.or.throw", 318 exit.thrown); 319 } 320 } 321 322 /** Record that exception is potentially thrown and check that it 323 * is caught. 324 */ 325 void markThrown(JCTree tree, Type exc) { 326 if (!chk.isUnchecked(tree.pos(), exc)) { 327 if (!chk.isHandled(exc, caught)) 328 pendingExits.append(new PendingExit(tree, exc)); 329 thrown = chk.incl(exc, thrown); 330 } 331 } 332 333 /*-------------- Processing variables ----------------------*/ 334 335 /** Do we need to track init/uninit state of this symbol? 336 * I.e. is symbol either a local or a blank final variable? 337 */ 338 boolean trackable(VarSymbol sym) { 339 return 340 (sym.owner.kind == MTH || 341 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL && 342 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner))); 343 } 344 345 /** Initialize new trackable variable by setting its address field 346 * to the next available sequence number and entering it under that 347 * index into the vars array. 348 */ 349 void newVar(VarSymbol sym) { 350 if (nextadr == vars.length) { 351 VarSymbol[] newvars = new VarSymbol[nextadr * 2]; 352 System.arraycopy(vars, 0, newvars, 0, nextadr); 353 vars = newvars; 354 } 355 sym.adr = nextadr; 356 vars[nextadr] = sym; 357 inits.excl(nextadr); 358 uninits.incl(nextadr); 359 nextadr++; 360 } 361 362 /** Record an initialization of a trackable variable. 363 */ 364 void letInit(DiagnosticPosition pos, VarSymbol sym) { 365 if (sym.adr >= firstadr && trackable(sym)) { 366 if ((sym.flags() & FINAL) != 0) { 367 if ((sym.flags() & PARAMETER) != 0) { 368 if ((sym.flags() & DISJOINT) != 0) { //multi-catch parameter 369 log.error(pos, "multicatch.parameter.may.not.be.assigned", 370 sym); 371 } 372 else { 373 log.error(pos, "final.parameter.may.not.be.assigned", 374 sym); 375 } 376 } else if (!uninits.isMember(sym.adr)) { 377 log.error(pos, 378 loopPassTwo 379 ? "var.might.be.assigned.in.loop" 380 : "var.might.already.be.assigned", 381 sym); 382 } else if (!inits.isMember(sym.adr)) { 383 // reachable assignment 384 uninits.excl(sym.adr); 385 uninitsTry.excl(sym.adr); 386 } else { 387 //log.rawWarning(pos, "unreachable assignment");//DEBUG 388 uninits.excl(sym.adr); 389 } 390 } 391 inits.incl(sym.adr); 392 } else if ((sym.flags() & FINAL) != 0) { 393 log.error(pos, "var.might.already.be.assigned", sym); 394 } 395 } 396 397 /** If tree is either a simple name or of the form this.name or 398 * C.this.name, and tree represents a trackable variable, 399 * record an initialization of the variable. 400 */ 401 void letInit(JCTree tree) { 402 tree = TreeInfo.skipParens(tree); 403 if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) { 404 Symbol sym = TreeInfo.symbol(tree); 405 letInit(tree.pos(), (VarSymbol)sym); 406 } 407 } 408 409 /** Check that trackable variable is initialized. 410 */ 411 void checkInit(DiagnosticPosition pos, VarSymbol sym) { 412 if ((sym.adr >= firstadr || sym.owner.kind != TYP) && 413 trackable(sym) && 414 !inits.isMember(sym.adr)) { 415 log.error(pos, "var.might.not.have.been.initialized", 416 sym); 417 inits.incl(sym.adr); 418 } 419 } 420 421 /*-------------------- Handling jumps ----------------------*/ 422 423 /** Record an outward transfer of control. */ 424 void recordExit(JCTree tree) { 425 pendingExits.append(new PendingExit(tree, inits, uninits)); 426 markDead(); 427 } 428 429 /** Resolve all breaks of this statement. */ 430 boolean resolveBreaks(JCTree tree, 431 ListBuffer<PendingExit> oldPendingExits) { 432 boolean result = false; 433 List<PendingExit> exits = pendingExits.toList(); 434 pendingExits = oldPendingExits; 435 for (; exits.nonEmpty(); exits = exits.tail) { 436 PendingExit exit = exits.head; 437 if (exit.tree.getTag() == JCTree.BREAK && 438 ((JCBreak) exit.tree).target == tree) { 439 inits.andSet(exit.inits); 440 uninits.andSet(exit.uninits); 441 result = true; 442 } else { 443 pendingExits.append(exit); 444 } 445 } 446 return result; 447 } 448 449 /** Resolve all continues of this statement. */ 450 boolean resolveContinues(JCTree tree) { 451 boolean result = false; 452 List<PendingExit> exits = pendingExits.toList(); 453 pendingExits = new ListBuffer<PendingExit>(); 454 for (; exits.nonEmpty(); exits = exits.tail) { 455 PendingExit exit = exits.head; 456 if (exit.tree.getTag() == JCTree.CONTINUE && 457 ((JCContinue) exit.tree).target == tree) { 458 inits.andSet(exit.inits); 459 uninits.andSet(exit.uninits); 460 result = true; 461 } else { 462 pendingExits.append(exit); 463 } 464 } 465 return result; 466 } 467 468 /** Record that statement is unreachable. 469 */ 470 void markDead() { 471 inits.inclRange(firstadr, nextadr); 472 uninits.inclRange(firstadr, nextadr); 473 alive = false; 474 } 475 476 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets 477 */ 478 void split() { 479 initsWhenFalse = inits.dup(); 480 uninitsWhenFalse = uninits.dup(); 481 initsWhenTrue = inits; 482 uninitsWhenTrue = uninits; 483 inits = uninits = null; 484 } 485 486 /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets. 487 */ 488 void merge() { 489 inits = initsWhenFalse.andSet(initsWhenTrue); 490 uninits = uninitsWhenFalse.andSet(uninitsWhenTrue); 491 } 492 493 /* ************************************************************************ 494 * Visitor methods for statements and definitions 495 *************************************************************************/ 496 497 /** Analyze a definition. 498 */ 499 void scanDef(JCTree tree) { 500 scanStat(tree); 501 if (tree != null && tree.getTag() == JCTree.BLOCK && !alive) { 502 log.error(tree.pos(), 503 "initializer.must.be.able.to.complete.normally"); 504 } 505 } 506 507 /** Analyze a statement. Check that statement is reachable. 508 */ 509 void scanStat(JCTree tree) { 510 if (!alive && tree != null) { 511 log.error(tree.pos(), "unreachable.stmt"); 512 if (tree.getTag() != JCTree.SKIP) alive = true; 513 } 514 scan(tree); 515 } 516 517 /** Analyze list of statements. 518 */ 519 void scanStats(List<? extends JCStatement> trees) { 520 if (trees != null) 521 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail) 522 scanStat(l.head); 523 } 524 525 /** Analyze an expression. Make sure to set (un)inits rather than 526 * (un)initsWhenTrue(WhenFalse) on exit. 527 */ 528 void scanExpr(JCTree tree) { 529 if (tree != null) { 530 scan(tree); 531 if (inits == null) merge(); 532 } 533 } 534 535 /** Analyze a list of expressions. 536 */ 537 void scanExprs(List<? extends JCExpression> trees) { 538 if (trees != null) 539 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail) 540 scanExpr(l.head); 541 } 542 543 /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse) 544 * rather than (un)inits on exit. 545 */ 546 void scanCond(JCTree tree) { 547 if (tree.type.isFalse()) { 548 if (inits == null) merge(); 549 initsWhenTrue = inits.dup(); 550 initsWhenTrue.inclRange(firstadr, nextadr); 551 uninitsWhenTrue = uninits.dup(); 552 uninitsWhenTrue.inclRange(firstadr, nextadr); 553 initsWhenFalse = inits; 554 uninitsWhenFalse = uninits; 555 } else if (tree.type.isTrue()) { 556 if (inits == null) merge(); 557 initsWhenFalse = inits.dup(); 558 initsWhenFalse.inclRange(firstadr, nextadr); 559 uninitsWhenFalse = uninits.dup(); 560 uninitsWhenFalse.inclRange(firstadr, nextadr); 561 initsWhenTrue = inits; 562 uninitsWhenTrue = uninits; 563 } else { 564 scan(tree); 565 if (inits != null) split(); 566 } 567 inits = uninits = null; 568 } 569 570 /* ------------ Visitor methods for various sorts of trees -------------*/ 571 572 public void visitClassDef(JCClassDecl tree) { 573 if (tree.sym == null) return; 574 575 JCClassDecl classDefPrev = classDef; 576 List<Type> thrownPrev = thrown; 577 List<Type> caughtPrev = caught; 578 boolean alivePrev = alive; 579 int firstadrPrev = firstadr; 580 int nextadrPrev = nextadr; 581 ListBuffer<PendingExit> pendingExitsPrev = pendingExits; 582 Lint lintPrev = lint; 583 584 pendingExits = new ListBuffer<PendingExit>(); 585 if (tree.name != names.empty) { 586 caught = List.nil(); 587 firstadr = nextadr; 588 } 589 classDef = tree; 590 thrown = List.nil(); 591 lint = lint.augment(tree.sym.attributes_field); 592 593 try { 594 // define all the static fields 595 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 596 if (l.head.getTag() == JCTree.VARDEF) { 597 JCVariableDecl def = (JCVariableDecl)l.head; 598 if ((def.mods.flags & STATIC) != 0) { 599 VarSymbol sym = def.sym; 600 if (trackable(sym)) 601 newVar(sym); 602 } 603 } 604 } 605 606 // process all the static initializers 607 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 608 if (l.head.getTag() != JCTree.METHODDEF && 609 (TreeInfo.flags(l.head) & STATIC) != 0) { 610 scanDef(l.head); 611 errorUncaught(); 612 } 613 } 614 615 // add intersection of all thrown clauses of initial constructors 616 // to set of caught exceptions, unless class is anonymous. 617 if (tree.name != names.empty) { 618 boolean firstConstructor = true; 619 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 620 if (TreeInfo.isInitialConstructor(l.head)) { 621 List<Type> mthrown = 622 ((JCMethodDecl) l.head).sym.type.getThrownTypes(); 623 if (firstConstructor) { 624 caught = mthrown; 625 firstConstructor = false; 626 } else { 627 caught = chk.intersect(mthrown, caught); 628 } 629 } 630 } 631 } 632 633 // define all the instance fields 634 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 635 if (l.head.getTag() == JCTree.VARDEF) { 636 JCVariableDecl def = (JCVariableDecl)l.head; 637 if ((def.mods.flags & STATIC) == 0) { 638 VarSymbol sym = def.sym; 639 if (trackable(sym)) 640 newVar(sym); 641 } 642 } 643 } 644 645 // process all the instance initializers 646 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 647 if (l.head.getTag() != JCTree.METHODDEF && 648 (TreeInfo.flags(l.head) & STATIC) == 0) { 649 scanDef(l.head); 650 errorUncaught(); 651 } 652 } 653 654 // in an anonymous class, add the set of thrown exceptions to 655 // the throws clause of the synthetic constructor and propagate 656 // outwards. 657 if (tree.name == names.empty) { 658 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 659 if (TreeInfo.isInitialConstructor(l.head)) { 660 JCMethodDecl mdef = (JCMethodDecl)l.head; 661 mdef.thrown = make.Types(thrown); 662 mdef.sym.type.setThrown(thrown); 663 } 664 } 665 thrownPrev = chk.union(thrown, thrownPrev); 666 } 667 668 // process all the methods 669 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 670 if (l.head.getTag() == JCTree.METHODDEF) { 671 scan(l.head); 672 errorUncaught(); 673 } 674 } 675 676 thrown = thrownPrev; 677 } finally { 678 pendingExits = pendingExitsPrev; 679 alive = alivePrev; 680 nextadr = nextadrPrev; 681 firstadr = firstadrPrev; 682 caught = caughtPrev; 683 classDef = classDefPrev; 684 lint = lintPrev; 685 } 686 } 687 688 public void visitMethodDef(JCMethodDecl tree) { 689 if (tree.body == null) return; 690 691 List<Type> caughtPrev = caught; 692 List<Type> mthrown = tree.sym.type.getThrownTypes(); 693 Bits initsPrev = inits.dup(); 694 Bits uninitsPrev = uninits.dup(); 695 int nextadrPrev = nextadr; 696 int firstadrPrev = firstadr; 697 Lint lintPrev = lint; 698 699 lint = lint.augment(tree.sym.attributes_field); 700 701 assert pendingExits.isEmpty(); 702 703 try { 704 boolean isInitialConstructor = 705 TreeInfo.isInitialConstructor(tree); 706 707 if (!isInitialConstructor) 708 firstadr = nextadr; 709 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { 710 JCVariableDecl def = l.head; 711 scan(def); 712 inits.incl(def.sym.adr); 713 uninits.excl(def.sym.adr); 714 } 715 if (isInitialConstructor) 716 caught = chk.union(caught, mthrown); 717 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK) 718 caught = mthrown; 719 // else we are in an instance initializer block; 720 // leave caught unchanged. 721 722 alive = true; 723 scanStat(tree.body); 724 725 if (alive && tree.sym.type.getReturnType().tag != VOID) 726 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt"); 727 728 if (isInitialConstructor) { 729 for (int i = firstadr; i < nextadr; i++) 730 if (vars[i].owner == classDef.sym) 731 checkInit(TreeInfo.diagEndPos(tree.body), vars[i]); 732 } 733 List<PendingExit> exits = pendingExits.toList(); 734 pendingExits = new ListBuffer<PendingExit>(); 735 while (exits.nonEmpty()) { 736 PendingExit exit = exits.head; 737 exits = exits.tail; 738 if (exit.thrown == null) { 739 assert exit.tree.getTag() == JCTree.RETURN; 740 if (isInitialConstructor) { 741 inits = exit.inits; 742 for (int i = firstadr; i < nextadr; i++) 743 checkInit(exit.tree.pos(), vars[i]); 744 } 745 } else { 746 // uncaught throws will be reported later 747 pendingExits.append(exit); 748 } 749 } 750 } finally { 751 inits = initsPrev; 752 uninits = uninitsPrev; 753 nextadr = nextadrPrev; 754 firstadr = firstadrPrev; 755 caught = caughtPrev; 756 lint = lintPrev; 757 } 758 } 759 760 public void visitVarDef(JCVariableDecl tree) { 761 boolean track = trackable(tree.sym); 762 if (track && tree.sym.owner.kind == MTH) newVar(tree.sym); 763 if (tree.init != null) { 764 Lint lintPrev = lint; 765 lint = lint.augment(tree.sym.attributes_field); 766 try{ 767 scanExpr(tree.init); 768 if (track) letInit(tree.pos(), tree.sym); 769 } finally { 770 lint = lintPrev; 771 } 772 } 773 } 774 775 public void visitBlock(JCBlock tree) { 776 int nextadrPrev = nextadr; 777 scanStats(tree.stats); 778 nextadr = nextadrPrev; 779 } 780 781 public void visitDoLoop(JCDoWhileLoop tree) { 782 ListBuffer<PendingExit> prevPendingExits = pendingExits; 783 boolean prevLoopPassTwo = loopPassTwo; 784 pendingExits = new ListBuffer<PendingExit>(); 785 do { 786 Bits uninitsEntry = uninits.dup(); 787 scanStat(tree.body); 788 alive |= resolveContinues(tree); 789 scanCond(tree.cond); 790 if (log.nerrors != 0 || 791 loopPassTwo || 792 uninitsEntry.diffSet(uninitsWhenTrue).nextBit(firstadr)==-1) 793 break; 794 inits = initsWhenTrue; 795 uninits = uninitsEntry.andSet(uninitsWhenTrue); 796 loopPassTwo = true; 797 alive = true; 798 } while (true); 799 loopPassTwo = prevLoopPassTwo; 800 inits = initsWhenFalse; 801 uninits = uninitsWhenFalse; 802 alive = alive && !tree.cond.type.isTrue(); 803 alive |= resolveBreaks(tree, prevPendingExits); 804 } 805 806 public void visitWhileLoop(JCWhileLoop tree) { 807 ListBuffer<PendingExit> prevPendingExits = pendingExits; 808 boolean prevLoopPassTwo = loopPassTwo; 809 Bits initsCond; 810 Bits uninitsCond; 811 pendingExits = new ListBuffer<PendingExit>(); 812 do { 813 Bits uninitsEntry = uninits.dup(); 814 scanCond(tree.cond); 815 initsCond = initsWhenFalse; 816 uninitsCond = uninitsWhenFalse; 817 inits = initsWhenTrue; 818 uninits = uninitsWhenTrue; 819 alive = !tree.cond.type.isFalse(); 820 scanStat(tree.body); 821 alive |= resolveContinues(tree); 822 if (log.nerrors != 0 || 823 loopPassTwo || 824 uninitsEntry.diffSet(uninits).nextBit(firstadr) == -1) 825 break; 826 uninits = uninitsEntry.andSet(uninits); 827 loopPassTwo = true; 828 alive = true; 829 } while (true); 830 loopPassTwo = prevLoopPassTwo; 831 inits = initsCond; 832 uninits = uninitsCond; 833 alive = resolveBreaks(tree, prevPendingExits) || 834 !tree.cond.type.isTrue(); 835 } 836 837 public void visitForLoop(JCForLoop tree) { 838 ListBuffer<PendingExit> prevPendingExits = pendingExits; 839 boolean prevLoopPassTwo = loopPassTwo; 840 int nextadrPrev = nextadr; 841 scanStats(tree.init); 842 Bits initsCond; 843 Bits uninitsCond; 844 pendingExits = new ListBuffer<PendingExit>(); 845 do { 846 Bits uninitsEntry = uninits.dup(); 847 if (tree.cond != null) { 848 scanCond(tree.cond); 849 initsCond = initsWhenFalse; 850 uninitsCond = uninitsWhenFalse; 851 inits = initsWhenTrue; 852 uninits = uninitsWhenTrue; 853 alive = !tree.cond.type.isFalse(); 854 } else { 855 initsCond = inits.dup(); 856 initsCond.inclRange(firstadr, nextadr); 857 uninitsCond = uninits.dup(); 858 uninitsCond.inclRange(firstadr, nextadr); 859 alive = true; 860 } 861 scanStat(tree.body); 862 alive |= resolveContinues(tree); 863 scan(tree.step); 864 if (log.nerrors != 0 || 865 loopPassTwo || 866 uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1) 867 break; 868 uninits = uninitsEntry.andSet(uninits); 869 loopPassTwo = true; 870 alive = true; 871 } while (true); 872 loopPassTwo = prevLoopPassTwo; 873 inits = initsCond; 874 uninits = uninitsCond; 875 alive = resolveBreaks(tree, prevPendingExits) || 876 tree.cond != null && !tree.cond.type.isTrue(); 877 nextadr = nextadrPrev; 878 } 879 880 public void visitForeachLoop(JCEnhancedForLoop tree) { 881 visitVarDef(tree.var); 882 883 ListBuffer<PendingExit> prevPendingExits = pendingExits; 884 boolean prevLoopPassTwo = loopPassTwo; 885 int nextadrPrev = nextadr; 886 scan(tree.expr); 887 Bits initsStart = inits.dup(); 888 Bits uninitsStart = uninits.dup(); 889 890 letInit(tree.pos(), tree.var.sym); 891 pendingExits = new ListBuffer<PendingExit>(); 892 do { 893 Bits uninitsEntry = uninits.dup(); 894 scanStat(tree.body); 895 alive |= resolveContinues(tree); 896 if (log.nerrors != 0 || 897 loopPassTwo || 898 uninitsEntry.diffSet(uninits).nextBit(firstadr) == -1) 899 break; 900 uninits = uninitsEntry.andSet(uninits); 901 loopPassTwo = true; 902 alive = true; 903 } while (true); 904 loopPassTwo = prevLoopPassTwo; 905 inits = initsStart; 906 uninits = uninitsStart.andSet(uninits); 907 resolveBreaks(tree, prevPendingExits); 908 alive = true; 909 nextadr = nextadrPrev; 910 } 911 912 public void visitLabelled(JCLabeledStatement tree) { 913 ListBuffer<PendingExit> prevPendingExits = pendingExits; 914 pendingExits = new ListBuffer<PendingExit>(); 915 scanStat(tree.body); 916 alive |= resolveBreaks(tree, prevPendingExits); 917 } 918 919 public void visitSwitch(JCSwitch tree) { 920 ListBuffer<PendingExit> prevPendingExits = pendingExits; 921 pendingExits = new ListBuffer<PendingExit>(); 922 int nextadrPrev = nextadr; 923 scanExpr(tree.selector); 924 Bits initsSwitch = inits; 925 Bits uninitsSwitch = uninits.dup(); 926 boolean hasDefault = false; 927 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { 928 alive = true; 929 inits = initsSwitch.dup(); 930 uninits = uninits.andSet(uninitsSwitch); 931 JCCase c = l.head; 932 if (c.pat == null) 933 hasDefault = true; 934 else 935 scanExpr(c.pat); 936 scanStats(c.stats); 937 addVars(c.stats, initsSwitch, uninitsSwitch); 938 // Warn about fall-through if lint switch fallthrough enabled. 939 if (!loopPassTwo && 940 alive && 941 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) && 942 c.stats.nonEmpty() && l.tail.nonEmpty()) 943 log.warning(l.tail.head.pos(), 944 "possible.fall-through.into.case"); 945 } 946 if (!hasDefault) { 947 inits.andSet(initsSwitch); 948 alive = true; 949 } 950 alive |= resolveBreaks(tree, prevPendingExits); 951 nextadr = nextadrPrev; 952 } 953 // where 954 /** Add any variables defined in stats to inits and uninits. */ 955 private static void addVars(List<JCStatement> stats, Bits inits, 956 Bits uninits) { 957 for (;stats.nonEmpty(); stats = stats.tail) { 958 JCTree stat = stats.head; 959 if (stat.getTag() == JCTree.VARDEF) { 960 int adr = ((JCVariableDecl) stat).sym.adr; 961 inits.excl(adr); 962 uninits.incl(adr); 963 } 964 } 965 } 966 967 public void visitTry(JCTry tree) { 968 unrefdResources = List.nil(); 969 for (JCTree resource : tree.resources) { 970 if (resource instanceof JCVariableDecl) { 971 visitVarDef((JCVariableDecl) resource); 972 } else if (resource instanceof JCExpression) { 973 scanExpr((JCExpression) resource); 974 } else { 975 throw new AssertionError(tree); // parser error 976 } 977 } 978 List<Type> caughtPrev = caught; 979 List<Type> thrownPrev = thrown; 980 thrown = List.nil(); 981 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 982 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ? 983 ((JCTypeDisjoint)l.head.param.vartype).components : 984 List.of(l.head.param.vartype); 985 for (JCExpression ct : subClauses) { 986 caught = chk.incl(ct.type, caught); 987 } 988 } 989 Bits uninitsTryPrev = uninitsTry; 990 ListBuffer<PendingExit> prevPendingExits = pendingExits; 991 pendingExits = new ListBuffer<PendingExit>(); 992 Bits initsTry = inits.dup(); 993 uninitsTry = uninits.dup(); 994 for (JCTree resource : tree.resources) { 995 MethodSymbol topCloseMethod = (MethodSymbol)syms.autoCloseableType.tsym.members().lookup(names.close).sym; 996 MethodSymbol closeMethod = types.implementation(topCloseMethod, resource.type.tsym, types, true); 997 998 for (Type thrownType : closeMethod.getThrownTypes()) { 999 markThrown(tree.body, thrownType); 1000 } 1001 } 1002 scanStat(tree.body); 1003 List<Type> thrownInTry = thrown; 1004 thrown = thrownPrev; 1005 caught = caughtPrev; 1006 boolean aliveEnd = alive; 1007 uninitsTry.andSet(uninits); 1008 Bits initsEnd = inits; 1009 Bits uninitsEnd = uninits; 1010 int nextadrCatch = nextadr; 1011 1012 if (unrefdResources.nonEmpty()) { 1013 for (List<JCTree> l = tree.resources; l.nonEmpty(); l = l.tail) { 1014 if (l.head instanceof JCVariableDecl) { 1015 JCVariableDecl v = (JCVariableDecl) l.head; 1016 if (unrefdResources.contains(v.sym)) { 1017 log.warning(v.pos(), 1018 "automatic.resource.not.referenced", v.sym); 1019 } 1020 } 1021 } 1022 } 1023 1024 List<Type> caughtInTry = List.nil(); 1025 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 1026 alive = true; 1027 JCVariableDecl param = l.head.param; 1028 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ? 1029 ((JCTypeDisjoint)l.head.param.vartype).components : 1030 List.of(l.head.param.vartype); 1031 List<Type> ctypes = List.nil(); 1032 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry); 1033 for (JCExpression ct : subClauses) { 1034 Type exc = ct.type; 1035 ctypes = ctypes.append(exc); 1036 if (types.isSameType(exc, syms.objectType)) 1037 continue; 1038 if (chk.subset(exc, caughtInTry)) { 1039 log.error(l.head.pos(), 1040 "except.already.caught", exc); 1041 } else if (!chk.isUnchecked(l.head.pos(), exc) && 1042 exc.tsym != syms.throwableType.tsym && 1043 exc.tsym != syms.exceptionType.tsym && 1044 !chk.intersects(exc, thrownInTry)) { 1045 log.error(l.head.pos(), 1046 "except.never.thrown.in.try", exc); 1047 } 1048 caughtInTry = chk.incl(exc, caughtInTry); 1049 } 1050 inits = initsTry.dup(); 1051 uninits = uninitsTry.dup(); 1052 scan(param); 1053 inits.incl(param.sym.adr); 1054 uninits.excl(param.sym.adr); 1055 multicatchTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes)); 1056 scanStat(l.head.body); 1057 initsEnd.andSet(inits); 1058 uninitsEnd.andSet(uninits); 1059 nextadr = nextadrCatch; 1060 multicatchTypes.remove(param.sym); 1061 aliveEnd |= alive; 1062 } 1063 if (tree.finalizer != null) { 1064 List<Type> savedThrown = thrown; 1065 thrown = List.nil(); 1066 inits = initsTry.dup(); 1067 uninits = uninitsTry.dup(); 1068 ListBuffer<PendingExit> exits = pendingExits; 1069 pendingExits = prevPendingExits; 1070 alive = true; 1071 scanStat(tree.finalizer); 1072 if (!alive) { 1073 // discard exits and exceptions from try and finally 1074 thrown = chk.union(thrown, thrownPrev); 1075 if (!loopPassTwo && 1076 lint.isEnabled(Lint.LintCategory.FINALLY)) { 1077 log.warning(TreeInfo.diagEndPos(tree.finalizer), 1078 "finally.cannot.complete"); 1079 } 1080 } else { 1081 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry)); 1082 thrown = chk.union(thrown, savedThrown); 1083 uninits.andSet(uninitsEnd); 1084 // FIX: this doesn't preserve source order of exits in catch 1085 // versus finally! 1086 while (exits.nonEmpty()) { 1087 PendingExit exit = exits.next(); 1088 if (exit.inits != null) { 1089 exit.inits.orSet(inits); 1090 exit.uninits.andSet(uninits); 1091 } 1092 pendingExits.append(exit); 1093 } 1094 inits.orSet(initsEnd); 1095 alive = aliveEnd; 1096 } 1097 } else { 1098 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry)); 1099 inits = initsEnd; 1100 uninits = uninitsEnd; 1101 alive = aliveEnd; 1102 ListBuffer<PendingExit> exits = pendingExits; 1103 pendingExits = prevPendingExits; 1104 while (exits.nonEmpty()) pendingExits.append(exits.next()); 1105 } 1106 uninitsTry.andSet(uninitsTryPrev).andSet(uninits); 1107 } 1108 1109 public void visitConditional(JCConditional tree) { 1110 scanCond(tree.cond); 1111 Bits initsBeforeElse = initsWhenFalse; 1112 Bits uninitsBeforeElse = uninitsWhenFalse; 1113 inits = initsWhenTrue; 1114 uninits = uninitsWhenTrue; 1115 if (tree.truepart.type.tag == BOOLEAN && 1116 tree.falsepart.type.tag == BOOLEAN) { 1117 // if b and c are boolean valued, then 1118 // v is (un)assigned after a?b:c when true iff 1119 // v is (un)assigned after b when true and 1120 // v is (un)assigned after c when true 1121 scanCond(tree.truepart); 1122 Bits initsAfterThenWhenTrue = initsWhenTrue.dup(); 1123 Bits initsAfterThenWhenFalse = initsWhenFalse.dup(); 1124 Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup(); 1125 Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup(); 1126 inits = initsBeforeElse; 1127 uninits = uninitsBeforeElse; 1128 scanCond(tree.falsepart); 1129 initsWhenTrue.andSet(initsAfterThenWhenTrue); 1130 initsWhenFalse.andSet(initsAfterThenWhenFalse); 1131 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue); 1132 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse); 1133 } else { 1134 scanExpr(tree.truepart); 1135 Bits initsAfterThen = inits.dup(); 1136 Bits uninitsAfterThen = uninits.dup(); 1137 inits = initsBeforeElse; 1138 uninits = uninitsBeforeElse; 1139 scanExpr(tree.falsepart); 1140 inits.andSet(initsAfterThen); 1141 uninits.andSet(uninitsAfterThen); 1142 } 1143 } 1144 1145 public void visitIf(JCIf tree) { 1146 scanCond(tree.cond); 1147 Bits initsBeforeElse = initsWhenFalse; 1148 Bits uninitsBeforeElse = uninitsWhenFalse; 1149 inits = initsWhenTrue; 1150 uninits = uninitsWhenTrue; 1151 scanStat(tree.thenpart); 1152 if (tree.elsepart != null) { 1153 boolean aliveAfterThen = alive; 1154 alive = true; 1155 Bits initsAfterThen = inits.dup(); 1156 Bits uninitsAfterThen = uninits.dup(); 1157 inits = initsBeforeElse; 1158 uninits = uninitsBeforeElse; 1159 scanStat(tree.elsepart); 1160 inits.andSet(initsAfterThen); 1161 uninits.andSet(uninitsAfterThen); 1162 alive = alive | aliveAfterThen; 1163 } else { 1164 inits.andSet(initsBeforeElse); 1165 uninits.andSet(uninitsBeforeElse); 1166 alive = true; 1167 } 1168 } 1169 1170 1171 1172 public void visitBreak(JCBreak tree) { 1173 recordExit(tree); 1174 } 1175 1176 public void visitContinue(JCContinue tree) { 1177 recordExit(tree); 1178 } 1179 1180 public void visitReturn(JCReturn tree) { 1181 scanExpr(tree.expr); 1182 // if not initial constructor, should markDead instead of recordExit 1183 recordExit(tree); 1184 } 1185 1186 public void visitThrow(JCThrow tree) { 1187 scanExpr(tree.expr); 1188 Symbol sym = TreeInfo.symbol(tree.expr); 1189 if (sym != null && 1190 sym.kind == VAR && 1191 (sym.flags() & FINAL) != 0 && 1192 multicatchTypes.get(sym) != null && 1193 allowRethrowAnalysis) { 1194 for (Type t : multicatchTypes.get(sym)) { 1195 markThrown(tree, t); 1196 } 1197 } 1198 else { 1199 markThrown(tree, tree.expr.type); 1200 } 1201 markDead(); 1202 } 1203 1204 public void visitApply(JCMethodInvocation tree) { 1205 scanExpr(tree.meth); 1206 scanExprs(tree.args); 1207 for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail) 1208 markThrown(tree, l.head); 1209 } 1210 1211 public void visitNewClass(JCNewClass tree) { 1212 scanExpr(tree.encl); 1213 scanExprs(tree.args); 1214 // scan(tree.def); 1215 for (List<Type> l = tree.constructorType.getThrownTypes(); 1216 l.nonEmpty(); 1217 l = l.tail) { 1218 markThrown(tree, l.head); 1219 } 1220 List<Type> caughtPrev = caught; 1221 try { 1222 // If the new class expression defines an anonymous class, 1223 // analysis of the anonymous constructor may encounter thrown 1224 // types which are unsubstituted type variables. 1225 // However, since the constructor's actual thrown types have 1226 // already been marked as thrown, it is safe to simply include 1227 // each of the constructor's formal thrown types in the set of 1228 // 'caught/declared to be thrown' types, for the duration of 1229 // the class def analysis. 1230 if (tree.def != null) 1231 for (List<Type> l = tree.constructor.type.getThrownTypes(); 1232 l.nonEmpty(); 1233 l = l.tail) { 1234 caught = chk.incl(l.head, caught); 1235 } 1236 scan(tree.def); 1237 } 1238 finally { 1239 caught = caughtPrev; 1240 } 1241 } 1242 1243 public void visitNewArray(JCNewArray tree) { 1244 scanExprs(tree.dims); 1245 scanExprs(tree.elems); 1246 } 1247 1248 public void visitAssert(JCAssert tree) { 1249 Bits initsExit = inits.dup(); 1250 Bits uninitsExit = uninits.dup(); 1251 scanCond(tree.cond); 1252 uninitsExit.andSet(uninitsWhenTrue); 1253 if (tree.detail != null) { 1254 inits = initsWhenFalse; 1255 uninits = uninitsWhenFalse; 1256 scanExpr(tree.detail); 1257 } 1258 inits = initsExit; 1259 uninits = uninitsExit; 1260 } 1261 1262 public void visitAssign(JCAssign tree) { 1263 JCTree lhs = TreeInfo.skipParens(tree.lhs); 1264 if (!(lhs instanceof JCIdent)) scanExpr(lhs); 1265 scanExpr(tree.rhs); 1266 letInit(lhs); 1267 } 1268 1269 public void visitAssignop(JCAssignOp tree) { 1270 scanExpr(tree.lhs); 1271 scanExpr(tree.rhs); 1272 letInit(tree.lhs); 1273 } 1274 1275 public void visitUnary(JCUnary tree) { 1276 switch (tree.getTag()) { 1277 case JCTree.NOT: 1278 scanCond(tree.arg); 1279 Bits t = initsWhenFalse; 1280 initsWhenFalse = initsWhenTrue; 1281 initsWhenTrue = t; 1282 t = uninitsWhenFalse; 1283 uninitsWhenFalse = uninitsWhenTrue; 1284 uninitsWhenTrue = t; 1285 break; 1286 case JCTree.PREINC: case JCTree.POSTINC: 1287 case JCTree.PREDEC: case JCTree.POSTDEC: 1288 scanExpr(tree.arg); 1289 letInit(tree.arg); 1290 break; 1291 default: 1292 scanExpr(tree.arg); 1293 } 1294 } 1295 1296 public void visitBinary(JCBinary tree) { 1297 switch (tree.getTag()) { 1298 case JCTree.AND: 1299 scanCond(tree.lhs); 1300 Bits initsWhenFalseLeft = initsWhenFalse; 1301 Bits uninitsWhenFalseLeft = uninitsWhenFalse; 1302 inits = initsWhenTrue; 1303 uninits = uninitsWhenTrue; 1304 scanCond(tree.rhs); 1305 initsWhenFalse.andSet(initsWhenFalseLeft); 1306 uninitsWhenFalse.andSet(uninitsWhenFalseLeft); 1307 break; 1308 case JCTree.OR: 1309 scanCond(tree.lhs); 1310 Bits initsWhenTrueLeft = initsWhenTrue; 1311 Bits uninitsWhenTrueLeft = uninitsWhenTrue; 1312 inits = initsWhenFalse; 1313 uninits = uninitsWhenFalse; 1314 scanCond(tree.rhs); 1315 initsWhenTrue.andSet(initsWhenTrueLeft); 1316 uninitsWhenTrue.andSet(uninitsWhenTrueLeft); 1317 break; 1318 default: 1319 scanExpr(tree.lhs); 1320 scanExpr(tree.rhs); 1321 } 1322 } 1323 1324 public void visitAnnotatedType(JCAnnotatedType tree) { 1325 // annotations don't get scanned 1326 tree.underlyingType.accept(this); 1327 } 1328 1329 public void visitIdent(JCIdent tree) { 1330 if (tree.sym.kind == VAR) { 1331 checkInit(tree.pos(), (VarSymbol)tree.sym); 1332 referenced(tree.sym); 1333 } 1334 } 1335 1336 void referenced(Symbol sym) { 1337 if (unrefdResources != null && unrefdResources.contains(sym)) { 1338 ListBuffer<Symbol> lb = new ListBuffer<Symbol>(); 1339 for (List<Symbol> l = unrefdResources; l.nonEmpty(); l = l.tail) 1340 if (l.head != sym) 1341 lb.add(l.head); 1342 unrefdResources = lb.toList(); 1343 } 1344 } 1345 1346 public void visitTypeCast(JCTypeCast tree) { 1347 super.visitTypeCast(tree); 1348 if (!tree.type.isErroneous() 1349 && lint.isEnabled(Lint.LintCategory.CAST) 1350 && types.isSameType(tree.expr.type, tree.clazz.type) 1351 && !(ignoreAnnotatedCasts && containsTypeAnnotation(tree.clazz))) { 1352 log.warning(tree.pos(), "redundant.cast", tree.expr.type); 1353 } 1354 } 1355 1356 public void visitTopLevel(JCCompilationUnit tree) { 1357 // Do nothing for TopLevel since each class is visited individually 1358 } 1359 1360 /************************************************************************** 1361 * utility methods for ignoring type-annotated casts lint checking 1362 *************************************************************************/ 1363 private static final boolean ignoreAnnotatedCasts = true; 1364 private static class AnnotationFinder extends TreeScanner { 1365 public boolean foundTypeAnno = false; 1366 public void visitAnnotation(JCAnnotation tree) { 1367 foundTypeAnno = foundTypeAnno || (tree instanceof JCTypeAnnotation); 1368 } 1369 } 1370 1371 private boolean containsTypeAnnotation(JCTree e) { 1372 AnnotationFinder finder = new AnnotationFinder(); 1373 finder.scan(e); 1374 return finder.foundTypeAnno; 1375 } 1376 1377 /************************************************************************** 1378 * main method 1379 *************************************************************************/ 1380 1381 /** Perform definite assignment/unassignment analysis on a tree. 1382 */ 1383 public void analyzeTree(JCTree tree, TreeMaker make) { 1384 try { 1385 this.make = make; 1386 inits = new Bits(); 1387 uninits = new Bits(); 1388 uninitsTry = new Bits(); 1389 initsWhenTrue = initsWhenFalse = 1390 uninitsWhenTrue = uninitsWhenFalse = null; 1391 if (vars == null) 1392 vars = new VarSymbol[32]; 1393 else 1394 for (int i=0; i<vars.length; i++) 1395 vars[i] = null; 1396 firstadr = 0; 1397 nextadr = 0; 1398 pendingExits = new ListBuffer<PendingExit>(); 1399 multicatchTypes = new HashMap<Symbol, List<Type>>(); 1400 alive = true; 1401 this.thrown = this.caught = null; 1402 this.classDef = null; 1403 scan(tree); 1404 } finally { 1405 // note that recursive invocations of this method fail hard 1406 inits = uninits = uninitsTry = null; 1407 initsWhenTrue = initsWhenFalse = 1408 uninitsWhenTrue = uninitsWhenFalse = null; 1409 if (vars != null) for (int i=0; i<vars.length; i++) 1410 vars[i] = null; 1411 firstadr = 0; 1412 nextadr = 0; 1413 pendingExits = null; 1414 this.make = null; 1415 this.thrown = this.caught = null; 1416 this.classDef = null; 1417 } 1418 } 1419 }