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