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