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