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