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