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 closeMethod = 996 (MethodSymbol)resource.type.tsym.members().lookup(names.close).sym; 997 for (Type thrownType : closeMethod.getThrownTypes()) { 998 markThrown(tree.body, thrownType); 999 } 1000 } 1001 scanStat(tree.body); 1002 List<Type> thrownInTry = thrown; 1003 thrown = thrownPrev; 1004 caught = caughtPrev; 1005 boolean aliveEnd = alive; 1006 uninitsTry.andSet(uninits); 1007 Bits initsEnd = inits; 1008 Bits uninitsEnd = uninits; 1009 int nextadrCatch = nextadr; 1010 1011 if (unrefdResources.nonEmpty()) { 1012 for (List<JCTree> l = tree.resources; l.nonEmpty(); l = l.tail) { 1013 if (l.head instanceof JCVariableDecl) { 1014 JCVariableDecl v = (JCVariableDecl) l.head; 1015 if (unrefdResources.contains(v.sym)) { 1016 log.warning(v.pos(), 1017 "automatic.resource.not.referenced", v.sym); 1018 } 1019 } 1020 } 1021 } 1022 1023 List<Type> caughtInTry = List.nil(); 1024 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 1025 alive = true; 1026 JCVariableDecl param = l.head.param; 1027 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ? 1028 ((JCTypeDisjoint)l.head.param.vartype).components : 1029 List.of(l.head.param.vartype); 1030 List<Type> ctypes = List.nil(); 1031 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry); 1032 for (JCExpression ct : subClauses) { 1033 Type exc = ct.type; 1034 ctypes = ctypes.append(exc); 1035 if (types.isSameType(exc, syms.objectType)) 1036 continue; 1037 if (chk.subset(exc, caughtInTry)) { 1038 log.error(l.head.pos(), 1039 "except.already.caught", exc); 1040 } else if (!chk.isUnchecked(l.head.pos(), exc) && 1041 exc.tsym != syms.throwableType.tsym && 1042 exc.tsym != syms.exceptionType.tsym && 1043 !chk.intersects(exc, thrownInTry)) { 1044 log.error(l.head.pos(), 1045 "except.never.thrown.in.try", exc); 1046 } 1047 caughtInTry = chk.incl(exc, caughtInTry); 1048 } 1049 inits = initsTry.dup(); 1050 uninits = uninitsTry.dup(); 1051 scan(param); 1052 inits.incl(param.sym.adr); 1053 uninits.excl(param.sym.adr); 1054 multicatchTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes)); 1055 scanStat(l.head.body); 1056 initsEnd.andSet(inits); 1057 uninitsEnd.andSet(uninits); 1058 nextadr = nextadrCatch; 1059 multicatchTypes.remove(param.sym); 1060 aliveEnd |= alive; 1061 } 1062 if (tree.finalizer != null) { 1063 List<Type> savedThrown = thrown; 1064 thrown = List.nil(); 1065 inits = initsTry.dup(); 1066 uninits = uninitsTry.dup(); 1067 ListBuffer<PendingExit> exits = pendingExits; 1068 pendingExits = prevPendingExits; 1069 alive = true; 1070 scanStat(tree.finalizer); 1071 if (!alive) { 1072 // discard exits and exceptions from try and finally 1073 thrown = chk.union(thrown, thrownPrev); 1074 if (!loopPassTwo && 1075 lint.isEnabled(Lint.LintCategory.FINALLY)) { 1076 log.warning(TreeInfo.diagEndPos(tree.finalizer), 1077 "finally.cannot.complete"); 1078 } 1079 } else { 1080 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry)); 1081 thrown = chk.union(thrown, savedThrown); 1082 uninits.andSet(uninitsEnd); 1083 // FIX: this doesn't preserve source order of exits in catch 1084 // versus finally! 1085 while (exits.nonEmpty()) { 1086 PendingExit exit = exits.next(); 1087 if (exit.inits != null) { 1088 exit.inits.orSet(inits); 1089 exit.uninits.andSet(uninits); 1090 } 1091 pendingExits.append(exit); 1092 } 1093 inits.orSet(initsEnd); 1094 alive = aliveEnd; 1095 } 1096 } else { 1097 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry)); 1098 inits = initsEnd; 1099 uninits = uninitsEnd; 1100 alive = aliveEnd; 1101 ListBuffer<PendingExit> exits = pendingExits; 1102 pendingExits = prevPendingExits; 1103 while (exits.nonEmpty()) pendingExits.append(exits.next()); 1104 } 1105 uninitsTry.andSet(uninitsTryPrev).andSet(uninits); 1106 } 1107 1108 public void visitConditional(JCConditional tree) { 1109 scanCond(tree.cond); 1110 Bits initsBeforeElse = initsWhenFalse; 1111 Bits uninitsBeforeElse = uninitsWhenFalse; 1112 inits = initsWhenTrue; 1113 uninits = uninitsWhenTrue; 1114 if (tree.truepart.type.tag == BOOLEAN && 1115 tree.falsepart.type.tag == BOOLEAN) { 1116 // if b and c are boolean valued, then 1117 // v is (un)assigned after a?b:c when true iff 1118 // v is (un)assigned after b when true and 1119 // v is (un)assigned after c when true 1120 scanCond(tree.truepart); 1121 Bits initsAfterThenWhenTrue = initsWhenTrue.dup(); 1122 Bits initsAfterThenWhenFalse = initsWhenFalse.dup(); 1123 Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup(); 1124 Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup(); 1125 inits = initsBeforeElse; 1126 uninits = uninitsBeforeElse; 1127 scanCond(tree.falsepart); 1128 initsWhenTrue.andSet(initsAfterThenWhenTrue); 1129 initsWhenFalse.andSet(initsAfterThenWhenFalse); 1130 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue); 1131 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse); 1132 } else { 1133 scanExpr(tree.truepart); 1134 Bits initsAfterThen = inits.dup(); 1135 Bits uninitsAfterThen = uninits.dup(); 1136 inits = initsBeforeElse; 1137 uninits = uninitsBeforeElse; 1138 scanExpr(tree.falsepart); 1139 inits.andSet(initsAfterThen); 1140 uninits.andSet(uninitsAfterThen); 1141 } 1142 } 1143 1144 public void visitIf(JCIf tree) { 1145 scanCond(tree.cond); 1146 Bits initsBeforeElse = initsWhenFalse; 1147 Bits uninitsBeforeElse = uninitsWhenFalse; 1148 inits = initsWhenTrue; 1149 uninits = uninitsWhenTrue; 1150 scanStat(tree.thenpart); 1151 if (tree.elsepart != null) { 1152 boolean aliveAfterThen = alive; 1153 alive = true; 1154 Bits initsAfterThen = inits.dup(); 1155 Bits uninitsAfterThen = uninits.dup(); 1156 inits = initsBeforeElse; 1157 uninits = uninitsBeforeElse; 1158 scanStat(tree.elsepart); 1159 inits.andSet(initsAfterThen); 1160 uninits.andSet(uninitsAfterThen); 1161 alive = alive | aliveAfterThen; 1162 } else { 1163 inits.andSet(initsBeforeElse); 1164 uninits.andSet(uninitsBeforeElse); 1165 alive = true; 1166 } 1167 } 1168 1169 1170 1171 public void visitBreak(JCBreak tree) { 1172 recordExit(tree); 1173 } 1174 1175 public void visitContinue(JCContinue tree) { 1176 recordExit(tree); 1177 } 1178 1179 public void visitReturn(JCReturn tree) { 1180 scanExpr(tree.expr); 1181 // if not initial constructor, should markDead instead of recordExit 1182 recordExit(tree); 1183 } 1184 1185 public void visitThrow(JCThrow tree) { 1186 scanExpr(tree.expr); 1187 Symbol sym = TreeInfo.symbol(tree.expr); 1188 if (sym != null && 1189 sym.kind == VAR && 1190 (sym.flags() & FINAL) != 0 && 1191 multicatchTypes.get(sym) != null && 1192 allowRethrowAnalysis) { 1193 for (Type t : multicatchTypes.get(sym)) { 1194 markThrown(tree, t); 1195 } 1196 } 1197 else { 1198 markThrown(tree, tree.expr.type); 1199 } 1200 markDead(); 1201 } 1202 1203 public void visitApply(JCMethodInvocation tree) { 1204 scanExpr(tree.meth); 1205 scanExprs(tree.args); 1206 for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail) 1207 markThrown(tree, l.head); 1208 } 1209 1210 public void visitNewClass(JCNewClass tree) { 1211 scanExpr(tree.encl); 1212 scanExprs(tree.args); 1213 // scan(tree.def); 1214 for (List<Type> l = tree.constructorType.getThrownTypes(); 1215 l.nonEmpty(); 1216 l = l.tail) { 1217 markThrown(tree, l.head); 1218 } 1219 List<Type> caughtPrev = caught; 1220 try { 1221 // If the new class expression defines an anonymous class, 1222 // analysis of the anonymous constructor may encounter thrown 1223 // types which are unsubstituted type variables. 1224 // However, since the constructor's actual thrown types have 1225 // already been marked as thrown, it is safe to simply include 1226 // each of the constructor's formal thrown types in the set of 1227 // 'caught/declared to be thrown' types, for the duration of 1228 // the class def analysis. 1229 if (tree.def != null) 1230 for (List<Type> l = tree.constructor.type.getThrownTypes(); 1231 l.nonEmpty(); 1232 l = l.tail) { 1233 caught = chk.incl(l.head, caught); 1234 } 1235 scan(tree.def); 1236 } 1237 finally { 1238 caught = caughtPrev; 1239 } 1240 } 1241 1242 public void visitNewArray(JCNewArray tree) { 1243 scanExprs(tree.dims); 1244 scanExprs(tree.elems); 1245 } 1246 1247 public void visitAssert(JCAssert tree) { 1248 Bits initsExit = inits.dup(); 1249 Bits uninitsExit = uninits.dup(); 1250 scanCond(tree.cond); 1251 uninitsExit.andSet(uninitsWhenTrue); 1252 if (tree.detail != null) { 1253 inits = initsWhenFalse; 1254 uninits = uninitsWhenFalse; 1255 scanExpr(tree.detail); 1256 } 1257 inits = initsExit; 1258 uninits = uninitsExit; 1259 } 1260 1261 public void visitAssign(JCAssign tree) { 1262 JCTree lhs = TreeInfo.skipParens(tree.lhs); 1263 if (!(lhs instanceof JCIdent)) scanExpr(lhs); 1264 scanExpr(tree.rhs); 1265 letInit(lhs); 1266 } 1267 1268 public void visitAssignop(JCAssignOp tree) { 1269 scanExpr(tree.lhs); 1270 scanExpr(tree.rhs); 1271 letInit(tree.lhs); 1272 } 1273 1274 public void visitUnary(JCUnary tree) { 1275 switch (tree.getTag()) { 1276 case JCTree.NOT: 1277 scanCond(tree.arg); 1278 Bits t = initsWhenFalse; 1279 initsWhenFalse = initsWhenTrue; 1280 initsWhenTrue = t; 1281 t = uninitsWhenFalse; 1282 uninitsWhenFalse = uninitsWhenTrue; 1283 uninitsWhenTrue = t; 1284 break; 1285 case JCTree.PREINC: case JCTree.POSTINC: 1286 case JCTree.PREDEC: case JCTree.POSTDEC: 1287 scanExpr(tree.arg); 1288 letInit(tree.arg); 1289 break; 1290 default: 1291 scanExpr(tree.arg); 1292 } 1293 } 1294 1295 public void visitBinary(JCBinary tree) { 1296 switch (tree.getTag()) { 1297 case JCTree.AND: 1298 scanCond(tree.lhs); 1299 Bits initsWhenFalseLeft = initsWhenFalse; 1300 Bits uninitsWhenFalseLeft = uninitsWhenFalse; 1301 inits = initsWhenTrue; 1302 uninits = uninitsWhenTrue; 1303 scanCond(tree.rhs); 1304 initsWhenFalse.andSet(initsWhenFalseLeft); 1305 uninitsWhenFalse.andSet(uninitsWhenFalseLeft); 1306 break; 1307 case JCTree.OR: 1308 scanCond(tree.lhs); 1309 Bits initsWhenTrueLeft = initsWhenTrue; 1310 Bits uninitsWhenTrueLeft = uninitsWhenTrue; 1311 inits = initsWhenFalse; 1312 uninits = uninitsWhenFalse; 1313 scanCond(tree.rhs); 1314 initsWhenTrue.andSet(initsWhenTrueLeft); 1315 uninitsWhenTrue.andSet(uninitsWhenTrueLeft); 1316 break; 1317 default: 1318 scanExpr(tree.lhs); 1319 scanExpr(tree.rhs); 1320 } 1321 } 1322 1323 public void visitAnnotatedType(JCAnnotatedType tree) { 1324 // annotations don't get scanned 1325 tree.underlyingType.accept(this); 1326 } 1327 1328 public void visitIdent(JCIdent tree) { 1329 if (tree.sym.kind == VAR) { 1330 checkInit(tree.pos(), (VarSymbol)tree.sym); 1331 referenced(tree.sym); 1332 } 1333 } 1334 1335 void referenced(Symbol sym) { 1336 if (unrefdResources != null && unrefdResources.contains(sym)) { 1337 ListBuffer<Symbol> lb = new ListBuffer<Symbol>(); 1338 for (List<Symbol> l = unrefdResources; l.nonEmpty(); l = l.tail) 1339 if (l.head != sym) 1340 lb.add(l.head); 1341 unrefdResources = lb.toList(); 1342 } 1343 } 1344 1345 public void visitTypeCast(JCTypeCast tree) { 1346 super.visitTypeCast(tree); 1347 if (!tree.type.isErroneous() 1348 && lint.isEnabled(Lint.LintCategory.CAST) 1349 && types.isSameType(tree.expr.type, tree.clazz.type) 1350 && !(ignoreAnnotatedCasts && containsTypeAnnotation(tree.clazz))) { 1351 log.warning(tree.pos(), "redundant.cast", tree.expr.type); 1352 } 1353 } 1354 1355 public void visitTopLevel(JCCompilationUnit tree) { 1356 // Do nothing for TopLevel since each class is visited individually 1357 } 1358 1359 /************************************************************************** 1360 * utility methods for ignoring type-annotated casts lint checking 1361 *************************************************************************/ 1362 private static final boolean ignoreAnnotatedCasts = true; 1363 private static class AnnotationFinder extends TreeScanner { 1364 public boolean foundTypeAnno = false; 1365 public void visitAnnotation(JCAnnotation tree) { 1366 foundTypeAnno = foundTypeAnno || (tree instanceof JCTypeAnnotation); 1367 } 1368 } 1369 1370 private boolean containsTypeAnnotation(JCTree e) { 1371 AnnotationFinder finder = new AnnotationFinder(); 1372 finder.scan(e); 1373 return finder.foundTypeAnno; 1374 } 1375 1376 /************************************************************************** 1377 * main method 1378 *************************************************************************/ 1379 1380 /** Perform definite assignment/unassignment analysis on a tree. 1381 */ 1382 public void analyzeTree(JCTree tree, TreeMaker make) { 1383 try { 1384 this.make = make; 1385 inits = new Bits(); 1386 uninits = new Bits(); 1387 uninitsTry = new Bits(); 1388 initsWhenTrue = initsWhenFalse = 1389 uninitsWhenTrue = uninitsWhenFalse = null; 1390 if (vars == null) 1391 vars = new VarSymbol[32]; 1392 else 1393 for (int i=0; i<vars.length; i++) 1394 vars[i] = null; 1395 firstadr = 0; 1396 nextadr = 0; 1397 pendingExits = new ListBuffer<PendingExit>(); 1398 multicatchTypes = new HashMap<Symbol, List<Type>>(); 1399 alive = true; 1400 this.thrown = this.caught = null; 1401 this.classDef = null; 1402 scan(tree); 1403 } finally { 1404 // note that recursive invocations of this method fail hard 1405 inits = uninits = uninitsTry = null; 1406 initsWhenTrue = initsWhenFalse = 1407 uninitsWhenTrue = uninitsWhenFalse = null; 1408 if (vars != null) for (int i=0; i<vars.length; i++) 1409 vars[i] = null; 1410 firstadr = 0; 1411 nextadr = 0; 1412 pendingExits = null; 1413 this.make = null; 1414 this.thrown = this.caught = null; 1415 this.classDef = null; 1416 } 1417 } 1418 }