1 /* 2 * Copyright (c) 1999, 2018, 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.source.tree.LambdaExpressionTree.BodyKind; 33 import com.sun.tools.javac.code.*; 34 import com.sun.tools.javac.code.Scope.WriteableScope; 35 import com.sun.tools.javac.code.Source.Feature; 36 import com.sun.tools.javac.resources.CompilerProperties.Errors; 37 import com.sun.tools.javac.resources.CompilerProperties.Warnings; 38 import com.sun.tools.javac.tree.*; 39 import com.sun.tools.javac.util.*; 40 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; 41 import com.sun.tools.javac.util.JCDiagnostic.Error; 42 import com.sun.tools.javac.util.JCDiagnostic.Warning; 43 44 import com.sun.tools.javac.code.Symbol.*; 45 import com.sun.tools.javac.tree.JCTree.*; 46 47 import static com.sun.tools.javac.code.Flags.*; 48 import static com.sun.tools.javac.code.Flags.BLOCK; 49 import static com.sun.tools.javac.code.Kinds.Kind.*; 50 import static com.sun.tools.javac.code.TypeTag.BOOLEAN; 51 import static com.sun.tools.javac.code.TypeTag.VOID; 52 import static com.sun.tools.javac.tree.JCTree.Tag.*; 53 54 /** This pass implements dataflow analysis for Java programs though 55 * different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that 56 * every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that 57 * every checked exception that is thrown is declared or caught. Definite assignment analysis 58 * (see AssignAnalyzer) ensures that each variable is assigned when used. Definite 59 * unassignment analysis (see AssignAnalyzer) in ensures that no final variable 60 * is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer) 61 * determines that local variables accessed within the scope of an inner class/lambda 62 * are either final or effectively-final. 63 * 64 * <p>The JLS has a number of problems in the 65 * specification of these flow analysis problems. This implementation 66 * attempts to address those issues. 67 * 68 * <p>First, there is no accommodation for a finally clause that cannot 69 * complete normally. For liveness analysis, an intervening finally 70 * clause can cause a break, continue, or return not to reach its 71 * target. For exception analysis, an intervening finally clause can 72 * cause any exception to be "caught". For DA/DU analysis, the finally 73 * clause can prevent a transfer of control from propagating DA/DU 74 * state to the target. In addition, code in the finally clause can 75 * affect the DA/DU status of variables. 76 * 77 * <p>For try statements, we introduce the idea of a variable being 78 * definitely unassigned "everywhere" in a block. A variable V is 79 * "unassigned everywhere" in a block iff it is unassigned at the 80 * beginning of the block and there is no reachable assignment to V 81 * in the block. An assignment V=e is reachable iff V is not DA 82 * after e. Then we can say that V is DU at the beginning of the 83 * catch block iff V is DU everywhere in the try block. Similarly, V 84 * is DU at the beginning of the finally block iff V is DU everywhere 85 * in the try block and in every catch block. Specifically, the 86 * following bullet is added to 16.2.2 87 * <pre> 88 * V is <em>unassigned everywhere</em> in a block if it is 89 * unassigned before the block and there is no reachable 90 * assignment to V within the block. 91 * </pre> 92 * <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all 93 * try blocks is changed to 94 * <pre> 95 * V is definitely unassigned before a catch block iff V is 96 * definitely unassigned everywhere in the try block. 97 * </pre> 98 * <p>The last bullet (and all of its sub-bullets) for try blocks that 99 * have a finally block is changed to 100 * <pre> 101 * V is definitely unassigned before the finally block iff 102 * V is definitely unassigned everywhere in the try block 103 * and everywhere in each catch block of the try statement. 104 * </pre> 105 * <p>In addition, 106 * <pre> 107 * V is definitely assigned at the end of a constructor iff 108 * V is definitely assigned after the block that is the body 109 * of the constructor and V is definitely assigned at every 110 * return that can return from the constructor. 111 * </pre> 112 * <p>In addition, each continue statement with the loop as its target 113 * is treated as a jump to the end of the loop body, and "intervening" 114 * finally clauses are treated as follows: V is DA "due to the 115 * continue" iff V is DA before the continue statement or V is DA at 116 * the end of any intervening finally block. V is DU "due to the 117 * continue" iff any intervening finally cannot complete normally or V 118 * is DU at the end of every intervening finally block. This "due to 119 * the continue" concept is then used in the spec for the loops. 120 * 121 * <p>Similarly, break statements must consider intervening finally 122 * blocks. For liveness analysis, a break statement for which any 123 * intervening finally cannot complete normally is not considered to 124 * cause the target statement to be able to complete normally. Then 125 * we say V is DA "due to the break" iff V is DA before the break or 126 * V is DA at the end of any intervening finally block. V is DU "due 127 * to the break" iff any intervening finally cannot complete normally 128 * or V is DU at the break and at the end of every intervening 129 * finally block. (I suspect this latter condition can be 130 * simplified.) This "due to the break" is then used in the spec for 131 * all statements that can be "broken". 132 * 133 * <p>The return statement is treated similarly. V is DA "due to a 134 * return statement" iff V is DA before the return statement or V is 135 * DA at the end of any intervening finally block. Note that we 136 * don't have to worry about the return expression because this 137 * concept is only used for construcrors. 138 * 139 * <p>There is no spec in the JLS for when a variable is definitely 140 * assigned at the end of a constructor, which is needed for final 141 * fields (8.3.1.2). We implement the rule that V is DA at the end 142 * of the constructor iff it is DA and the end of the body of the 143 * constructor and V is DA "due to" every return of the constructor. 144 * 145 * <p>Intervening finally blocks similarly affect exception analysis. An 146 * intervening finally that cannot complete normally allows us to ignore 147 * an otherwise uncaught exception. 148 * 149 * <p>To implement the semantics of intervening finally clauses, all 150 * nonlocal transfers (break, continue, return, throw, method call that 151 * can throw a checked exception, and a constructor invocation that can 152 * thrown a checked exception) are recorded in a queue, and removed 153 * from the queue when we complete processing the target of the 154 * nonlocal transfer. This allows us to modify the queue in accordance 155 * with the above rules when we encounter a finally clause. The only 156 * exception to this [no pun intended] is that checked exceptions that 157 * are known to be caught or declared to be caught in the enclosing 158 * method are not recorded in the queue, but instead are recorded in a 159 * global variable "{@code Set<Type> thrown}" that records the type of all 160 * exceptions that can be thrown. 161 * 162 * <p>Other minor issues the treatment of members of other classes 163 * (always considered DA except that within an anonymous class 164 * constructor, where DA status from the enclosing scope is 165 * preserved), treatment of the case expression (V is DA before the 166 * case expression iff V is DA after the switch expression), 167 * treatment of variables declared in a switch block (the implied 168 * DA/DU status after the switch expression is DU and not DA for 169 * variables defined in a switch block), the treatment of boolean ?: 170 * expressions (The JLS rules only handle b and c non-boolean; the 171 * new rule is that if b and c are boolean valued, then V is 172 * (un)assigned after a?b:c when true/false iff V is (un)assigned 173 * after b when true/false and V is (un)assigned after c when 174 * true/false). 175 * 176 * <p>There is the remaining question of what syntactic forms constitute a 177 * reference to a variable. It is conventional to allow this.x on the 178 * left-hand-side to initialize a final instance field named x, yet 179 * this.x isn't considered a "use" when appearing on a right-hand-side 180 * in most implementations. Should parentheses affect what is 181 * considered a variable reference? The simplest rule would be to 182 * allow unqualified forms only, parentheses optional, and phase out 183 * support for assigning to a final field via this.x. 184 * 185 * <p><b>This is NOT part of any supported API. 186 * If you write code that depends on this, you do so at your own risk. 187 * This code and its internal interfaces are subject to change or 188 * deletion without notice.</b> 189 */ 190 public class Flow { 191 protected static final Context.Key<Flow> flowKey = new Context.Key<>(); 192 193 private final Names names; 194 private final Log log; 195 private final Symtab syms; 196 private final Types types; 197 private final Check chk; 198 private TreeMaker make; 199 private final Resolve rs; 200 private final JCDiagnostic.Factory diags; 201 private Env<AttrContext> attrEnv; 202 private Lint lint; 203 private final boolean allowEffectivelyFinalInInnerClasses; 204 205 public static Flow instance(Context context) { 206 Flow instance = context.get(flowKey); 207 if (instance == null) 208 instance = new Flow(context); 209 return instance; 210 } 211 212 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { 213 new AliveAnalyzer().analyzeTree(env, make); 214 new AssignAnalyzer().analyzeTree(env); 215 new FlowAnalyzer().analyzeTree(env, make); 216 new CaptureAnalyzer().analyzeTree(env, make); 217 } 218 219 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) { 220 Log.DiagnosticHandler diagHandler = null; 221 //we need to disable diagnostics temporarily; the problem is that if 222 //a lambda expression contains e.g. an unreachable statement, an error 223 //message will be reported and will cause compilation to skip the flow analyis 224 //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis 225 //related errors, which will allow for more errors to be detected 226 if (!speculative) { 227 diagHandler = new Log.DiscardDiagnosticHandler(log); 228 } 229 try { 230 new LambdaAliveAnalyzer().analyzeTree(env, that, make); 231 } finally { 232 if (!speculative) { 233 log.popDiagnosticHandler(diagHandler); 234 } 235 } 236 } 237 238 public List<Type> analyzeLambdaThrownTypes(final Env<AttrContext> env, 239 JCLambda that, TreeMaker make) { 240 //we need to disable diagnostics temporarily; the problem is that if 241 //a lambda expression contains e.g. an unreachable statement, an error 242 //message will be reported and will cause compilation to skip the flow analyis 243 //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis 244 //related errors, which will allow for more errors to be detected 245 Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log); 246 try { 247 new LambdaAssignAnalyzer(env).analyzeTree(env, that); 248 LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer(); 249 flowAnalyzer.analyzeTree(env, that, make); 250 return flowAnalyzer.inferredThrownTypes; 251 } finally { 252 log.popDiagnosticHandler(diagHandler); 253 } 254 } 255 256 /** 257 * Definite assignment scan mode 258 */ 259 enum FlowKind { 260 /** 261 * This is the normal DA/DU analysis mode 262 */ 263 NORMAL("var.might.already.be.assigned", false), 264 /** 265 * This is the speculative DA/DU analysis mode used to speculatively 266 * derive assertions within loop bodies 267 */ 268 SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true); 269 270 final String errKey; 271 final boolean isFinal; 272 273 FlowKind(String errKey, boolean isFinal) { 274 this.errKey = errKey; 275 this.isFinal = isFinal; 276 } 277 278 boolean isFinal() { 279 return isFinal; 280 } 281 } 282 283 protected Flow(Context context) { 284 context.put(flowKey, this); 285 names = Names.instance(context); 286 log = Log.instance(context); 287 syms = Symtab.instance(context); 288 types = Types.instance(context); 289 chk = Check.instance(context); 290 lint = Lint.instance(context); 291 rs = Resolve.instance(context); 292 diags = JCDiagnostic.Factory.instance(context); 293 Source source = Source.instance(context); 294 allowEffectivelyFinalInInnerClasses = Feature.EFFECTIVELY_FINAL_IN_INNER_CLASSES.allowedInSource(source); 295 } 296 297 /** 298 * Base visitor class for all visitors implementing dataflow analysis logic. 299 * This class define the shared logic for handling jumps (break/continue statements). 300 */ 301 static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner { 302 303 enum JumpKind { 304 BREAK(JCTree.Tag.BREAK) { 305 @Override 306 JCTree getTarget(JCTree tree) { 307 return ((JCBreak)tree).target; 308 } 309 }, 310 CONTINUE(JCTree.Tag.CONTINUE) { 311 @Override 312 JCTree getTarget(JCTree tree) { 313 return ((JCContinue)tree).target; 314 } 315 }; 316 317 final JCTree.Tag treeTag; 318 319 private JumpKind(Tag treeTag) { 320 this.treeTag = treeTag; 321 } 322 323 abstract JCTree getTarget(JCTree tree); 324 } 325 326 /** The currently pending exits that go from current inner blocks 327 * to an enclosing block, in source order. 328 */ 329 ListBuffer<P> pendingExits; 330 331 /** A pending exit. These are the statements return, break, and 332 * continue. In addition, exception-throwing expressions or 333 * statements are put here when not known to be caught. This 334 * will typically result in an error unless it is within a 335 * try-finally whose finally block cannot complete normally. 336 */ 337 static class PendingExit { 338 JCTree tree; 339 340 PendingExit(JCTree tree) { 341 this.tree = tree; 342 } 343 344 void resolveJump() { 345 //do nothing 346 } 347 } 348 349 abstract void markDead(); 350 351 /** Record an outward transfer of control. */ 352 void recordExit(P pe) { 353 pendingExits.append(pe); 354 markDead(); 355 } 356 357 /** Resolve all jumps of this statement. */ 358 private boolean resolveJump(JCTree tree, 359 ListBuffer<P> oldPendingExits, 360 JumpKind jk) { 361 boolean resolved = false; 362 List<P> exits = pendingExits.toList(); 363 pendingExits = oldPendingExits; 364 for (; exits.nonEmpty(); exits = exits.tail) { 365 P exit = exits.head; 366 if (exit.tree.hasTag(jk.treeTag) && 367 jk.getTarget(exit.tree) == tree) { 368 exit.resolveJump(); 369 resolved = true; 370 } else { 371 pendingExits.append(exit); 372 } 373 } 374 return resolved; 375 } 376 377 /** Resolve all continues of this statement. */ 378 boolean resolveContinues(JCTree tree) { 379 return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE); 380 } 381 382 /** Resolve all breaks of this statement. */ 383 boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) { 384 return resolveJump(tree, oldPendingExits, JumpKind.BREAK); 385 } 386 387 @Override 388 public void scan(JCTree tree) { 389 if (tree != null && ( 390 tree.type == null || 391 tree.type != Type.stuckType)) { 392 super.scan(tree); 393 } 394 } 395 396 public void visitPackageDef(JCPackageDecl tree) { 397 // Do nothing for PackageDecl 398 } 399 } 400 401 /** 402 * This pass implements the first step of the dataflow analysis, namely 403 * the liveness analysis check. This checks that every statement is reachable. 404 * The output of this analysis pass are used by other analyzers. This analyzer 405 * sets the 'finallyCanCompleteNormally' field in the JCTry class. 406 */ 407 class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> { 408 409 /** A flag that indicates whether the last statement could 410 * complete normally. 411 */ 412 private boolean alive; 413 414 @Override 415 void markDead() { 416 alive = false; 417 } 418 419 /************************************************************************* 420 * Visitor methods for statements and definitions 421 *************************************************************************/ 422 423 /** Analyze a definition. 424 */ 425 void scanDef(JCTree tree) { 426 scanStat(tree); 427 if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) { 428 log.error(tree.pos(), 429 Errors.InitializerMustBeAbleToCompleteNormally); 430 } 431 } 432 433 /** Analyze a statement. Check that statement is reachable. 434 */ 435 void scanStat(JCTree tree) { 436 if (!alive && tree != null) { 437 log.error(tree.pos(), Errors.UnreachableStmt); 438 if (!tree.hasTag(SKIP)) alive = true; 439 } 440 scan(tree); 441 } 442 443 /** Analyze list of statements. 444 */ 445 void scanStats(List<? extends JCStatement> trees) { 446 if (trees != null) 447 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail) 448 scanStat(l.head); 449 } 450 451 /* ------------ Visitor methods for various sorts of trees -------------*/ 452 453 public void visitClassDef(JCClassDecl tree) { 454 if (tree.sym == null) return; 455 boolean alivePrev = alive; 456 ListBuffer<PendingExit> pendingExitsPrev = pendingExits; 457 Lint lintPrev = lint; 458 459 pendingExits = new ListBuffer<>(); 460 lint = lint.augment(tree.sym); 461 462 try { 463 // process all the static initializers 464 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 465 if (!l.head.hasTag(METHODDEF) && 466 (TreeInfo.flags(l.head) & STATIC) != 0) { 467 scanDef(l.head); 468 } 469 } 470 471 // process all the instance initializers 472 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 473 if (!l.head.hasTag(METHODDEF) && 474 (TreeInfo.flags(l.head) & STATIC) == 0) { 475 scanDef(l.head); 476 } 477 } 478 479 // process all the methods 480 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 481 if (l.head.hasTag(METHODDEF)) { 482 scan(l.head); 483 } 484 } 485 } finally { 486 pendingExits = pendingExitsPrev; 487 alive = alivePrev; 488 lint = lintPrev; 489 } 490 } 491 492 public void visitMethodDef(JCMethodDecl tree) { 493 if (tree.body == null) return; 494 Lint lintPrev = lint; 495 496 lint = lint.augment(tree.sym); 497 498 Assert.check(pendingExits.isEmpty()); 499 500 try { 501 alive = true; 502 scanStat(tree.body); 503 504 if (alive && !tree.sym.type.getReturnType().hasTag(VOID)) 505 log.error(TreeInfo.diagEndPos(tree.body), Errors.MissingRetStmt); 506 507 List<PendingExit> exits = pendingExits.toList(); 508 pendingExits = new ListBuffer<>(); 509 while (exits.nonEmpty()) { 510 PendingExit exit = exits.head; 511 exits = exits.tail; 512 Assert.check(exit.tree.hasTag(RETURN)); 513 } 514 } finally { 515 lint = lintPrev; 516 } 517 } 518 519 public void visitVarDef(JCVariableDecl tree) { 520 if (tree.init != null) { 521 Lint lintPrev = lint; 522 lint = lint.augment(tree.sym); 523 try{ 524 scan(tree.init); 525 } finally { 526 lint = lintPrev; 527 } 528 } 529 } 530 531 public void visitBlock(JCBlock tree) { 532 scanStats(tree.stats); 533 } 534 535 public void visitDoLoop(JCDoWhileLoop tree) { 536 ListBuffer<PendingExit> prevPendingExits = pendingExits; 537 pendingExits = new ListBuffer<>(); 538 scanStat(tree.body); 539 alive |= resolveContinues(tree); 540 scan(tree.cond); 541 alive = alive && !tree.cond.type.isTrue(); 542 alive |= resolveBreaks(tree, prevPendingExits); 543 } 544 545 public void visitWhileLoop(JCWhileLoop tree) { 546 ListBuffer<PendingExit> prevPendingExits = pendingExits; 547 pendingExits = new ListBuffer<>(); 548 scan(tree.cond); 549 alive = !tree.cond.type.isFalse(); 550 scanStat(tree.body); 551 alive |= resolveContinues(tree); 552 alive = resolveBreaks(tree, prevPendingExits) || 553 !tree.cond.type.isTrue(); 554 } 555 556 public void visitForLoop(JCForLoop tree) { 557 ListBuffer<PendingExit> prevPendingExits = pendingExits; 558 scanStats(tree.init); 559 pendingExits = new ListBuffer<>(); 560 if (tree.cond != null) { 561 scan(tree.cond); 562 alive = !tree.cond.type.isFalse(); 563 } else { 564 alive = true; 565 } 566 scanStat(tree.body); 567 alive |= resolveContinues(tree); 568 scan(tree.step); 569 alive = resolveBreaks(tree, prevPendingExits) || 570 tree.cond != null && !tree.cond.type.isTrue(); 571 } 572 573 public void visitForeachLoop(JCEnhancedForLoop tree) { 574 visitVarDef(tree.var); 575 ListBuffer<PendingExit> prevPendingExits = pendingExits; 576 scan(tree.expr); 577 pendingExits = new ListBuffer<>(); 578 scanStat(tree.body); 579 alive |= resolveContinues(tree); 580 resolveBreaks(tree, prevPendingExits); 581 alive = true; 582 } 583 584 public void visitLabelled(JCLabeledStatement tree) { 585 ListBuffer<PendingExit> prevPendingExits = pendingExits; 586 pendingExits = new ListBuffer<>(); 587 scanStat(tree.body); 588 alive |= resolveBreaks(tree, prevPendingExits); 589 } 590 591 public void visitSwitch(JCSwitch tree) { 592 ListBuffer<PendingExit> prevPendingExits = pendingExits; 593 pendingExits = new ListBuffer<>(); 594 scan(tree.selector); 595 boolean hasDefault = false; 596 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { 597 alive = true; 598 JCCase c = l.head; 599 if (c.pat == null) 600 hasDefault = true; 601 else 602 scan(c.pat); 603 scanStats(c.stats); 604 // Warn about fall-through if lint switch fallthrough enabled. 605 if (alive && 606 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) && 607 c.stats.nonEmpty() && l.tail.nonEmpty()) 608 log.warning(Lint.LintCategory.FALLTHROUGH, 609 l.tail.head.pos(), 610 Warnings.PossibleFallThroughIntoCase); 611 } 612 if (!hasDefault) { 613 alive = true; 614 } 615 alive |= resolveBreaks(tree, prevPendingExits); 616 } 617 618 public void visitTry(JCTry tree) { 619 ListBuffer<PendingExit> prevPendingExits = pendingExits; 620 pendingExits = new ListBuffer<>(); 621 for (JCTree resource : tree.resources) { 622 if (resource instanceof JCVariableDecl) { 623 JCVariableDecl vdecl = (JCVariableDecl) resource; 624 visitVarDef(vdecl); 625 } else if (resource instanceof JCExpression) { 626 scan((JCExpression) resource); 627 } else { 628 throw new AssertionError(tree); // parser error 629 } 630 } 631 632 scanStat(tree.body); 633 boolean aliveEnd = alive; 634 635 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 636 alive = true; 637 JCVariableDecl param = l.head.param; 638 scan(param); 639 scanStat(l.head.body); 640 aliveEnd |= alive; 641 } 642 if (tree.finalizer != null) { 643 ListBuffer<PendingExit> exits = pendingExits; 644 pendingExits = prevPendingExits; 645 alive = true; 646 scanStat(tree.finalizer); 647 tree.finallyCanCompleteNormally = alive; 648 if (!alive) { 649 if (lint.isEnabled(Lint.LintCategory.FINALLY)) { 650 log.warning(Lint.LintCategory.FINALLY, 651 TreeInfo.diagEndPos(tree.finalizer), 652 Warnings.FinallyCannotComplete); 653 } 654 } else { 655 while (exits.nonEmpty()) { 656 pendingExits.append(exits.next()); 657 } 658 alive = aliveEnd; 659 } 660 } else { 661 alive = aliveEnd; 662 ListBuffer<PendingExit> exits = pendingExits; 663 pendingExits = prevPendingExits; 664 while (exits.nonEmpty()) pendingExits.append(exits.next()); 665 } 666 } 667 668 @Override 669 public void visitIf(JCIf tree) { 670 scan(tree.cond); 671 scanStat(tree.thenpart); 672 if (tree.elsepart != null) { 673 boolean aliveAfterThen = alive; 674 alive = true; 675 scanStat(tree.elsepart); 676 alive = alive | aliveAfterThen; 677 } else { 678 alive = true; 679 } 680 } 681 682 public void visitBreak(JCBreak tree) { 683 recordExit(new PendingExit(tree)); 684 } 685 686 public void visitContinue(JCContinue tree) { 687 recordExit(new PendingExit(tree)); 688 } 689 690 public void visitReturn(JCReturn tree) { 691 scan(tree.expr); 692 recordExit(new PendingExit(tree)); 693 } 694 695 public void visitThrow(JCThrow tree) { 696 scan(tree.expr); 697 markDead(); 698 } 699 700 public void visitApply(JCMethodInvocation tree) { 701 scan(tree.meth); 702 scan(tree.args); 703 } 704 705 public void visitNewClass(JCNewClass tree) { 706 scan(tree.encl); 707 scan(tree.args); 708 if (tree.def != null) { 709 scan(tree.def); 710 } 711 } 712 713 @Override 714 public void visitLambda(JCLambda tree) { 715 if (tree.type != null && 716 tree.type.isErroneous()) { 717 return; 718 } 719 720 ListBuffer<PendingExit> prevPending = pendingExits; 721 boolean prevAlive = alive; 722 try { 723 pendingExits = new ListBuffer<>(); 724 alive = true; 725 scanStat(tree.body); 726 tree.canCompleteNormally = alive; 727 } 728 finally { 729 pendingExits = prevPending; 730 alive = prevAlive; 731 } 732 } 733 734 public void visitModuleDef(JCModuleDecl tree) { 735 // Do nothing for modules 736 } 737 738 /************************************************************************** 739 * main method 740 *************************************************************************/ 741 742 /** Perform definite assignment/unassignment analysis on a tree. 743 */ 744 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { 745 analyzeTree(env, env.tree, make); 746 } 747 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { 748 try { 749 attrEnv = env; 750 Flow.this.make = make; 751 pendingExits = new ListBuffer<>(); 752 alive = true; 753 scan(tree); 754 } finally { 755 pendingExits = null; 756 Flow.this.make = null; 757 } 758 } 759 } 760 761 /** 762 * This pass implements the second step of the dataflow analysis, namely 763 * the exception analysis. This is to ensure that every checked exception that is 764 * thrown is declared or caught. The analyzer uses some info that has been set by 765 * the liveliness analyzer. 766 */ 767 class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> { 768 769 /** A flag that indicates whether the last statement could 770 * complete normally. 771 */ 772 HashMap<Symbol, List<Type>> preciseRethrowTypes; 773 774 /** The current class being defined. 775 */ 776 JCClassDecl classDef; 777 778 /** The list of possibly thrown declarable exceptions. 779 */ 780 List<Type> thrown; 781 782 /** The list of exceptions that are either caught or declared to be 783 * thrown. 784 */ 785 List<Type> caught; 786 787 class FlowPendingExit extends BaseAnalyzer.PendingExit { 788 789 Type thrown; 790 791 FlowPendingExit(JCTree tree, Type thrown) { 792 super(tree); 793 this.thrown = thrown; 794 } 795 } 796 797 @Override 798 void markDead() { 799 //do nothing 800 } 801 802 /*-------------------- Exceptions ----------------------*/ 803 804 /** Complain that pending exceptions are not caught. 805 */ 806 void errorUncaught() { 807 for (FlowPendingExit exit = pendingExits.next(); 808 exit != null; 809 exit = pendingExits.next()) { 810 if (classDef != null && 811 classDef.pos == exit.tree.pos) { 812 log.error(exit.tree.pos(), 813 Errors.UnreportedExceptionDefaultConstructor(exit.thrown)); 814 } else if (exit.tree.hasTag(VARDEF) && 815 ((JCVariableDecl)exit.tree).sym.isResourceVariable()) { 816 log.error(exit.tree.pos(), 817 Errors.UnreportedExceptionImplicitClose(exit.thrown, 818 ((JCVariableDecl)exit.tree).sym.name)); 819 } else { 820 log.error(exit.tree.pos(), 821 Errors.UnreportedExceptionNeedToCatchOrThrow(exit.thrown)); 822 } 823 } 824 } 825 826 /** Record that exception is potentially thrown and check that it 827 * is caught. 828 */ 829 void markThrown(JCTree tree, Type exc) { 830 if (!chk.isUnchecked(tree.pos(), exc)) { 831 if (!chk.isHandled(exc, caught)) { 832 pendingExits.append(new FlowPendingExit(tree, exc)); 833 } 834 thrown = chk.incl(exc, thrown); 835 } 836 } 837 838 /************************************************************************* 839 * Visitor methods for statements and definitions 840 *************************************************************************/ 841 842 /* ------------ Visitor methods for various sorts of trees -------------*/ 843 844 public void visitClassDef(JCClassDecl tree) { 845 if (tree.sym == null) return; 846 847 JCClassDecl classDefPrev = classDef; 848 List<Type> thrownPrev = thrown; 849 List<Type> caughtPrev = caught; 850 ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits; 851 Lint lintPrev = lint; 852 boolean anonymousClass = tree.name == names.empty; 853 pendingExits = new ListBuffer<>(); 854 if (!anonymousClass) { 855 caught = List.nil(); 856 } 857 classDef = tree; 858 thrown = List.nil(); 859 lint = lint.augment(tree.sym); 860 861 try { 862 // process all the static initializers 863 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 864 if (!l.head.hasTag(METHODDEF) && 865 (TreeInfo.flags(l.head) & STATIC) != 0) { 866 scan(l.head); 867 errorUncaught(); 868 } 869 } 870 871 // add intersection of all thrown clauses of initial constructors 872 // to set of caught exceptions, unless class is anonymous. 873 if (!anonymousClass) { 874 boolean firstConstructor = true; 875 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 876 if (TreeInfo.isInitialConstructor(l.head)) { 877 List<Type> mthrown = 878 ((JCMethodDecl) l.head).sym.type.getThrownTypes(); 879 if (firstConstructor) { 880 caught = mthrown; 881 firstConstructor = false; 882 } else { 883 caught = chk.intersect(mthrown, caught); 884 } 885 } 886 } 887 } 888 889 // process all the instance initializers 890 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 891 if (!l.head.hasTag(METHODDEF) && 892 (TreeInfo.flags(l.head) & STATIC) == 0) { 893 scan(l.head); 894 errorUncaught(); 895 } 896 } 897 898 // in an anonymous class, add the set of thrown exceptions to 899 // the throws clause of the synthetic constructor and propagate 900 // outwards. 901 // Changing the throws clause on the fly is okay here because 902 // the anonymous constructor can't be invoked anywhere else, 903 // and its type hasn't been cached. 904 if (anonymousClass) { 905 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 906 if (TreeInfo.isConstructor(l.head)) { 907 JCMethodDecl mdef = (JCMethodDecl)l.head; 908 scan(mdef); 909 mdef.thrown = make.Types(thrown); 910 mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown); 911 } 912 } 913 thrownPrev = chk.union(thrown, thrownPrev); 914 } 915 916 // process all the methods 917 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 918 if (anonymousClass && TreeInfo.isConstructor(l.head)) 919 continue; // there can never be an uncaught exception. 920 if (l.head.hasTag(METHODDEF)) { 921 scan(l.head); 922 errorUncaught(); 923 } 924 } 925 926 thrown = thrownPrev; 927 } finally { 928 pendingExits = pendingExitsPrev; 929 caught = caughtPrev; 930 classDef = classDefPrev; 931 lint = lintPrev; 932 } 933 } 934 935 public void visitMethodDef(JCMethodDecl tree) { 936 if (tree.body == null) return; 937 938 List<Type> caughtPrev = caught; 939 List<Type> mthrown = tree.sym.type.getThrownTypes(); 940 Lint lintPrev = lint; 941 942 lint = lint.augment(tree.sym); 943 944 Assert.check(pendingExits.isEmpty()); 945 946 try { 947 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { 948 JCVariableDecl def = l.head; 949 scan(def); 950 } 951 if (TreeInfo.isInitialConstructor(tree)) 952 caught = chk.union(caught, mthrown); 953 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK) 954 caught = mthrown; 955 // else we are in an instance initializer block; 956 // leave caught unchanged. 957 958 scan(tree.body); 959 960 List<FlowPendingExit> exits = pendingExits.toList(); 961 pendingExits = new ListBuffer<>(); 962 while (exits.nonEmpty()) { 963 FlowPendingExit exit = exits.head; 964 exits = exits.tail; 965 if (exit.thrown == null) { 966 Assert.check(exit.tree.hasTag(RETURN)); 967 } else { 968 // uncaught throws will be reported later 969 pendingExits.append(exit); 970 } 971 } 972 } finally { 973 caught = caughtPrev; 974 lint = lintPrev; 975 } 976 } 977 978 public void visitVarDef(JCVariableDecl tree) { 979 if (tree.init != null) { 980 Lint lintPrev = lint; 981 lint = lint.augment(tree.sym); 982 try{ 983 scan(tree.init); 984 } finally { 985 lint = lintPrev; 986 } 987 } 988 } 989 990 public void visitBlock(JCBlock tree) { 991 scan(tree.stats); 992 } 993 994 public void visitDoLoop(JCDoWhileLoop tree) { 995 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 996 pendingExits = new ListBuffer<>(); 997 scan(tree.body); 998 resolveContinues(tree); 999 scan(tree.cond); 1000 resolveBreaks(tree, prevPendingExits); 1001 } 1002 1003 public void visitWhileLoop(JCWhileLoop tree) { 1004 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1005 pendingExits = new ListBuffer<>(); 1006 scan(tree.cond); 1007 scan(tree.body); 1008 resolveContinues(tree); 1009 resolveBreaks(tree, prevPendingExits); 1010 } 1011 1012 public void visitForLoop(JCForLoop tree) { 1013 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1014 scan(tree.init); 1015 pendingExits = new ListBuffer<>(); 1016 if (tree.cond != null) { 1017 scan(tree.cond); 1018 } 1019 scan(tree.body); 1020 resolveContinues(tree); 1021 scan(tree.step); 1022 resolveBreaks(tree, prevPendingExits); 1023 } 1024 1025 public void visitForeachLoop(JCEnhancedForLoop tree) { 1026 visitVarDef(tree.var); 1027 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1028 scan(tree.expr); 1029 pendingExits = new ListBuffer<>(); 1030 scan(tree.body); 1031 resolveContinues(tree); 1032 resolveBreaks(tree, prevPendingExits); 1033 } 1034 1035 public void visitLabelled(JCLabeledStatement tree) { 1036 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1037 pendingExits = new ListBuffer<>(); 1038 scan(tree.body); 1039 resolveBreaks(tree, prevPendingExits); 1040 } 1041 1042 public void visitSwitch(JCSwitch tree) { 1043 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1044 pendingExits = new ListBuffer<>(); 1045 scan(tree.selector); 1046 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { 1047 JCCase c = l.head; 1048 if (c.pat != null) { 1049 scan(c.pat); 1050 } 1051 scan(c.stats); 1052 } 1053 resolveBreaks(tree, prevPendingExits); 1054 } 1055 1056 public void visitTry(JCTry tree) { 1057 List<Type> caughtPrev = caught; 1058 List<Type> thrownPrev = thrown; 1059 thrown = List.nil(); 1060 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 1061 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ? 1062 ((JCTypeUnion)l.head.param.vartype).alternatives : 1063 List.of(l.head.param.vartype); 1064 for (JCExpression ct : subClauses) { 1065 caught = chk.incl(ct.type, caught); 1066 } 1067 } 1068 1069 ListBuffer<FlowPendingExit> prevPendingExits = pendingExits; 1070 pendingExits = new ListBuffer<>(); 1071 for (JCTree resource : tree.resources) { 1072 if (resource instanceof JCVariableDecl) { 1073 JCVariableDecl vdecl = (JCVariableDecl) resource; 1074 visitVarDef(vdecl); 1075 } else if (resource instanceof JCExpression) { 1076 scan((JCExpression) resource); 1077 } else { 1078 throw new AssertionError(tree); // parser error 1079 } 1080 } 1081 for (JCTree resource : tree.resources) { 1082 List<Type> closeableSupertypes = resource.type.isCompound() ? 1083 types.interfaces(resource.type).prepend(types.supertype(resource.type)) : 1084 List.of(resource.type); 1085 for (Type sup : closeableSupertypes) { 1086 if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) { 1087 Symbol closeMethod = rs.resolveQualifiedMethod(tree, 1088 attrEnv, 1089 types.skipTypeVars(sup, false), 1090 names.close, 1091 List.nil(), 1092 List.nil()); 1093 Type mt = types.memberType(resource.type, closeMethod); 1094 if (closeMethod.kind == MTH) { 1095 for (Type t : mt.getThrownTypes()) { 1096 markThrown(resource, t); 1097 } 1098 } 1099 } 1100 } 1101 } 1102 scan(tree.body); 1103 List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)); 1104 thrown = thrownPrev; 1105 caught = caughtPrev; 1106 1107 List<Type> caughtInTry = List.nil(); 1108 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 1109 JCVariableDecl param = l.head.param; 1110 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ? 1111 ((JCTypeUnion)l.head.param.vartype).alternatives : 1112 List.of(l.head.param.vartype); 1113 List<Type> ctypes = List.nil(); 1114 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry); 1115 for (JCExpression ct : subClauses) { 1116 Type exc = ct.type; 1117 if (exc != syms.unknownType) { 1118 ctypes = ctypes.append(exc); 1119 if (types.isSameType(exc, syms.objectType)) 1120 continue; 1121 checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry); 1122 caughtInTry = chk.incl(exc, caughtInTry); 1123 } 1124 } 1125 scan(param); 1126 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes)); 1127 scan(l.head.body); 1128 preciseRethrowTypes.remove(param.sym); 1129 } 1130 if (tree.finalizer != null) { 1131 List<Type> savedThrown = thrown; 1132 thrown = List.nil(); 1133 ListBuffer<FlowPendingExit> exits = pendingExits; 1134 pendingExits = prevPendingExits; 1135 scan(tree.finalizer); 1136 if (!tree.finallyCanCompleteNormally) { 1137 // discard exits and exceptions from try and finally 1138 thrown = chk.union(thrown, thrownPrev); 1139 } else { 1140 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry)); 1141 thrown = chk.union(thrown, savedThrown); 1142 // FIX: this doesn't preserve source order of exits in catch 1143 // versus finally! 1144 while (exits.nonEmpty()) { 1145 pendingExits.append(exits.next()); 1146 } 1147 } 1148 } else { 1149 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry)); 1150 ListBuffer<FlowPendingExit> exits = pendingExits; 1151 pendingExits = prevPendingExits; 1152 while (exits.nonEmpty()) pendingExits.append(exits.next()); 1153 } 1154 } 1155 1156 @Override 1157 public void visitIf(JCIf tree) { 1158 scan(tree.cond); 1159 scan(tree.thenpart); 1160 if (tree.elsepart != null) { 1161 scan(tree.elsepart); 1162 } 1163 } 1164 1165 void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) { 1166 if (chk.subset(exc, caughtInTry)) { 1167 log.error(pos, Errors.ExceptAlreadyCaught(exc)); 1168 } else if (!chk.isUnchecked(pos, exc) && 1169 !isExceptionOrThrowable(exc) && 1170 !chk.intersects(exc, thrownInTry)) { 1171 log.error(pos, Errors.ExceptNeverThrownInTry(exc)); 1172 } else { 1173 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry); 1174 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an 1175 // unchecked exception, the result list would not be empty, as the augmented 1176 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked 1177 // exception, that would have been covered in the branch above 1178 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() && 1179 !isExceptionOrThrowable(exc)) { 1180 Warning key = catchableThrownTypes.length() == 1 ? 1181 Warnings.UnreachableCatch(catchableThrownTypes) : 1182 Warnings.UnreachableCatch1(catchableThrownTypes); 1183 log.warning(pos, key); 1184 } 1185 } 1186 } 1187 //where 1188 private boolean isExceptionOrThrowable(Type exc) { 1189 return exc.tsym == syms.throwableType.tsym || 1190 exc.tsym == syms.exceptionType.tsym; 1191 } 1192 1193 public void visitBreak(JCBreak tree) { 1194 recordExit(new FlowPendingExit(tree, null)); 1195 } 1196 1197 public void visitContinue(JCContinue tree) { 1198 recordExit(new FlowPendingExit(tree, null)); 1199 } 1200 1201 public void visitReturn(JCReturn tree) { 1202 scan(tree.expr); 1203 recordExit(new FlowPendingExit(tree, null)); 1204 } 1205 1206 public void visitThrow(JCThrow tree) { 1207 scan(tree.expr); 1208 Symbol sym = TreeInfo.symbol(tree.expr); 1209 if (sym != null && 1210 sym.kind == VAR && 1211 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 && 1212 preciseRethrowTypes.get(sym) != null) { 1213 for (Type t : preciseRethrowTypes.get(sym)) { 1214 markThrown(tree, t); 1215 } 1216 } 1217 else { 1218 markThrown(tree, tree.expr.type); 1219 } 1220 markDead(); 1221 } 1222 1223 public void visitApply(JCMethodInvocation tree) { 1224 scan(tree.meth); 1225 scan(tree.args); 1226 for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail) 1227 markThrown(tree, l.head); 1228 } 1229 1230 public void visitNewClass(JCNewClass tree) { 1231 scan(tree.encl); 1232 scan(tree.args); 1233 // scan(tree.def); 1234 for (List<Type> l = tree.constructorType.getThrownTypes(); 1235 l.nonEmpty(); 1236 l = l.tail) { 1237 markThrown(tree, l.head); 1238 } 1239 List<Type> caughtPrev = caught; 1240 try { 1241 // If the new class expression defines an anonymous class, 1242 // analysis of the anonymous constructor may encounter thrown 1243 // types which are unsubstituted type variables. 1244 // However, since the constructor's actual thrown types have 1245 // already been marked as thrown, it is safe to simply include 1246 // each of the constructor's formal thrown types in the set of 1247 // 'caught/declared to be thrown' types, for the duration of 1248 // the class def analysis. 1249 if (tree.def != null) 1250 for (List<Type> l = tree.constructor.type.getThrownTypes(); 1251 l.nonEmpty(); 1252 l = l.tail) { 1253 caught = chk.incl(l.head, caught); 1254 } 1255 scan(tree.def); 1256 } 1257 finally { 1258 caught = caughtPrev; 1259 } 1260 } 1261 1262 @Override 1263 public void visitLambda(JCLambda tree) { 1264 if (tree.type != null && 1265 tree.type.isErroneous()) { 1266 return; 1267 } 1268 List<Type> prevCaught = caught; 1269 List<Type> prevThrown = thrown; 1270 ListBuffer<FlowPendingExit> prevPending = pendingExits; 1271 try { 1272 pendingExits = new ListBuffer<>(); 1273 caught = tree.getDescriptorType(types).getThrownTypes(); 1274 thrown = List.nil(); 1275 scan(tree.body); 1276 List<FlowPendingExit> exits = pendingExits.toList(); 1277 pendingExits = new ListBuffer<>(); 1278 while (exits.nonEmpty()) { 1279 FlowPendingExit exit = exits.head; 1280 exits = exits.tail; 1281 if (exit.thrown == null) { 1282 Assert.check(exit.tree.hasTag(RETURN)); 1283 } else { 1284 // uncaught throws will be reported later 1285 pendingExits.append(exit); 1286 } 1287 } 1288 1289 errorUncaught(); 1290 } finally { 1291 pendingExits = prevPending; 1292 caught = prevCaught; 1293 thrown = prevThrown; 1294 } 1295 } 1296 1297 public void visitModuleDef(JCModuleDecl tree) { 1298 // Do nothing for modules 1299 } 1300 1301 /************************************************************************** 1302 * main method 1303 *************************************************************************/ 1304 1305 /** Perform definite assignment/unassignment analysis on a tree. 1306 */ 1307 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { 1308 analyzeTree(env, env.tree, make); 1309 } 1310 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { 1311 try { 1312 attrEnv = env; 1313 Flow.this.make = make; 1314 pendingExits = new ListBuffer<>(); 1315 preciseRethrowTypes = new HashMap<>(); 1316 this.thrown = this.caught = null; 1317 this.classDef = null; 1318 scan(tree); 1319 } finally { 1320 pendingExits = null; 1321 Flow.this.make = null; 1322 this.thrown = this.caught = null; 1323 this.classDef = null; 1324 } 1325 } 1326 } 1327 1328 /** 1329 * Specialized pass that performs reachability analysis on a lambda 1330 */ 1331 class LambdaAliveAnalyzer extends AliveAnalyzer { 1332 1333 boolean inLambda; 1334 1335 @Override 1336 public void visitReturn(JCReturn tree) { 1337 //ignore lambda return expression (which might not even be attributed) 1338 recordExit(new PendingExit(tree)); 1339 } 1340 1341 @Override 1342 public void visitLambda(JCLambda tree) { 1343 if (inLambda || tree.getBodyKind() == BodyKind.EXPRESSION) { 1344 return; 1345 } 1346 inLambda = true; 1347 try { 1348 super.visitLambda(tree); 1349 } finally { 1350 inLambda = false; 1351 } 1352 } 1353 1354 @Override 1355 public void visitClassDef(JCClassDecl tree) { 1356 //skip 1357 } 1358 } 1359 1360 /** 1361 * Specialized pass that performs DA/DU on a lambda 1362 */ 1363 class LambdaAssignAnalyzer extends AssignAnalyzer { 1364 WriteableScope enclosedSymbols; 1365 boolean inLambda; 1366 1367 LambdaAssignAnalyzer(Env<AttrContext> env) { 1368 enclosedSymbols = WriteableScope.create(env.enclClass.sym); 1369 } 1370 1371 @Override 1372 public void visitLambda(JCLambda tree) { 1373 if (inLambda) { 1374 return; 1375 } 1376 inLambda = true; 1377 try { 1378 super.visitLambda(tree); 1379 } finally { 1380 inLambda = false; 1381 } 1382 } 1383 1384 @Override 1385 public void visitVarDef(JCVariableDecl tree) { 1386 enclosedSymbols.enter(tree.sym); 1387 super.visitVarDef(tree); 1388 } 1389 @Override 1390 protected boolean trackable(VarSymbol sym) { 1391 return enclosedSymbols.includes(sym) && 1392 sym.owner.kind == MTH; 1393 } 1394 1395 @Override 1396 public void visitClassDef(JCClassDecl tree) { 1397 //skip 1398 } 1399 } 1400 1401 /** 1402 * Specialized pass that performs inference of thrown types for lambdas. 1403 */ 1404 class LambdaFlowAnalyzer extends FlowAnalyzer { 1405 List<Type> inferredThrownTypes; 1406 boolean inLambda; 1407 @Override 1408 public void visitLambda(JCLambda tree) { 1409 if ((tree.type != null && 1410 tree.type.isErroneous()) || inLambda) { 1411 return; 1412 } 1413 List<Type> prevCaught = caught; 1414 List<Type> prevThrown = thrown; 1415 ListBuffer<FlowPendingExit> prevPending = pendingExits; 1416 inLambda = true; 1417 try { 1418 pendingExits = new ListBuffer<>(); 1419 caught = List.of(syms.throwableType); 1420 thrown = List.nil(); 1421 scan(tree.body); 1422 inferredThrownTypes = thrown; 1423 } finally { 1424 pendingExits = prevPending; 1425 caught = prevCaught; 1426 thrown = prevThrown; 1427 inLambda = false; 1428 } 1429 } 1430 @Override 1431 public void visitClassDef(JCClassDecl tree) { 1432 //skip 1433 } 1434 } 1435 1436 /** 1437 * This pass implements (i) definite assignment analysis, which ensures that 1438 * each variable is assigned when used and (ii) definite unassignment analysis, 1439 * which ensures that no final variable is assigned more than once. This visitor 1440 * depends on the results of the liveliness analyzer. This pass is also used to mark 1441 * effectively-final local variables/parameters. 1442 */ 1443 1444 public class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> { 1445 1446 /** The set of definitely assigned variables. 1447 */ 1448 final Bits inits; 1449 1450 /** The set of definitely unassigned variables. 1451 */ 1452 final Bits uninits; 1453 1454 /** The set of variables that are definitely unassigned everywhere 1455 * in current try block. This variable is maintained lazily; it is 1456 * updated only when something gets removed from uninits, 1457 * typically by being assigned in reachable code. To obtain the 1458 * correct set of variables which are definitely unassigned 1459 * anywhere in current try block, intersect uninitsTry and 1460 * uninits. 1461 */ 1462 final Bits uninitsTry; 1463 1464 /** When analyzing a condition, inits and uninits are null. 1465 * Instead we have: 1466 */ 1467 final Bits initsWhenTrue; 1468 final Bits initsWhenFalse; 1469 final Bits uninitsWhenTrue; 1470 final Bits uninitsWhenFalse; 1471 1472 /** A mapping from addresses to variable symbols. 1473 */ 1474 protected JCVariableDecl[] vardecls; 1475 1476 /** The current class being defined. 1477 */ 1478 JCClassDecl classDef; 1479 1480 /** The first variable sequence number in this class definition. 1481 */ 1482 int firstadr; 1483 1484 /** The next available variable sequence number. 1485 */ 1486 protected int nextadr; 1487 1488 /** The first variable sequence number in a block that can return. 1489 */ 1490 protected int returnadr; 1491 1492 /** The list of unreferenced automatic resources. 1493 */ 1494 WriteableScope unrefdResources; 1495 1496 /** Modified when processing a loop body the second time for DU analysis. */ 1497 FlowKind flowKind = FlowKind.NORMAL; 1498 1499 /** The starting position of the analyzed tree */ 1500 int startPos; 1501 1502 public class AssignPendingExit extends BaseAnalyzer.PendingExit { 1503 1504 final Bits inits; 1505 final Bits uninits; 1506 final Bits exit_inits = new Bits(true); 1507 final Bits exit_uninits = new Bits(true); 1508 1509 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) { 1510 super(tree); 1511 this.inits = inits; 1512 this.uninits = uninits; 1513 this.exit_inits.assign(inits); 1514 this.exit_uninits.assign(uninits); 1515 } 1516 1517 @Override 1518 public void resolveJump() { 1519 inits.andSet(exit_inits); 1520 uninits.andSet(exit_uninits); 1521 } 1522 } 1523 1524 public AssignAnalyzer() { 1525 this.inits = new Bits(); 1526 uninits = new Bits(); 1527 uninitsTry = new Bits(); 1528 initsWhenTrue = new Bits(true); 1529 initsWhenFalse = new Bits(true); 1530 uninitsWhenTrue = new Bits(true); 1531 uninitsWhenFalse = new Bits(true); 1532 } 1533 1534 private boolean isInitialConstructor = false; 1535 1536 @Override 1537 protected void markDead() { 1538 if (!isInitialConstructor) { 1539 inits.inclRange(returnadr, nextadr); 1540 } else { 1541 for (int address = returnadr; address < nextadr; address++) { 1542 if (!(isFinalUninitializedStaticField(vardecls[address].sym))) { 1543 inits.incl(address); 1544 } 1545 } 1546 } 1547 uninits.inclRange(returnadr, nextadr); 1548 } 1549 1550 /*-------------- Processing variables ----------------------*/ 1551 1552 /** Do we need to track init/uninit state of this symbol? 1553 * I.e. is symbol either a local or a blank final variable? 1554 */ 1555 protected boolean trackable(VarSymbol sym) { 1556 return 1557 sym.pos >= startPos && 1558 ((sym.owner.kind == MTH || 1559 isFinalUninitializedField(sym))); 1560 } 1561 1562 boolean isFinalUninitializedField(VarSymbol sym) { 1563 return sym.owner.kind == TYP && 1564 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL && 1565 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)); 1566 } 1567 1568 boolean isFinalUninitializedStaticField(VarSymbol sym) { 1569 return isFinalUninitializedField(sym) && sym.isStatic(); 1570 } 1571 1572 /** Initialize new trackable variable by setting its address field 1573 * to the next available sequence number and entering it under that 1574 * index into the vars array. 1575 */ 1576 void newVar(JCVariableDecl varDecl) { 1577 VarSymbol sym = varDecl.sym; 1578 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr); 1579 if ((sym.flags() & FINAL) == 0) { 1580 sym.flags_field |= EFFECTIVELY_FINAL; 1581 } 1582 sym.adr = nextadr; 1583 vardecls[nextadr] = varDecl; 1584 inits.excl(nextadr); 1585 uninits.incl(nextadr); 1586 nextadr++; 1587 } 1588 1589 /** Record an initialization of a trackable variable. 1590 */ 1591 void letInit(DiagnosticPosition pos, VarSymbol sym) { 1592 if (sym.adr >= firstadr && trackable(sym)) { 1593 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) { 1594 if (!uninits.isMember(sym.adr)) { 1595 //assignment targeting an effectively final variable 1596 //makes the variable lose its status of effectively final 1597 //if the variable is _not_ definitively unassigned 1598 sym.flags_field &= ~EFFECTIVELY_FINAL; 1599 } else { 1600 uninit(sym); 1601 } 1602 } 1603 else if ((sym.flags() & FINAL) != 0) { 1604 if ((sym.flags() & PARAMETER) != 0) { 1605 if ((sym.flags() & UNION) != 0) { //multi-catch parameter 1606 log.error(pos, Errors.MulticatchParameterMayNotBeAssigned(sym)); 1607 } 1608 else { 1609 log.error(pos, 1610 Errors.FinalParameterMayNotBeAssigned(sym)); 1611 } 1612 } else if (!uninits.isMember(sym.adr)) { 1613 log.error(pos, diags.errorKey(flowKind.errKey, sym)); 1614 } else { 1615 uninit(sym); 1616 } 1617 } 1618 inits.incl(sym.adr); 1619 } else if ((sym.flags() & FINAL) != 0) { 1620 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym)); 1621 } 1622 } 1623 //where 1624 void uninit(VarSymbol sym) { 1625 if (!inits.isMember(sym.adr)) { 1626 // reachable assignment 1627 uninits.excl(sym.adr); 1628 uninitsTry.excl(sym.adr); 1629 } else { 1630 //log.rawWarning(pos, "unreachable assignment");//DEBUG 1631 uninits.excl(sym.adr); 1632 } 1633 } 1634 1635 /** If tree is either a simple name or of the form this.name or 1636 * C.this.name, and tree represents a trackable variable, 1637 * record an initialization of the variable. 1638 */ 1639 void letInit(JCTree tree) { 1640 tree = TreeInfo.skipParens(tree); 1641 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) { 1642 Symbol sym = TreeInfo.symbol(tree); 1643 if (sym.kind == VAR) { 1644 letInit(tree.pos(), (VarSymbol)sym); 1645 } 1646 } 1647 } 1648 1649 /** Check that trackable variable is initialized. 1650 */ 1651 void checkInit(DiagnosticPosition pos, VarSymbol sym) { 1652 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym)); 1653 } 1654 1655 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) { 1656 if ((sym.adr >= firstadr || sym.owner.kind != TYP) && 1657 trackable(sym) && 1658 !inits.isMember(sym.adr)) { 1659 log.error(pos, errkey); 1660 inits.incl(sym.adr); 1661 } 1662 } 1663 1664 /** Utility method to reset several Bits instances. 1665 */ 1666 private void resetBits(Bits... bits) { 1667 for (Bits b : bits) { 1668 b.reset(); 1669 } 1670 } 1671 1672 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets 1673 */ 1674 void split(boolean setToNull) { 1675 initsWhenFalse.assign(inits); 1676 uninitsWhenFalse.assign(uninits); 1677 initsWhenTrue.assign(inits); 1678 uninitsWhenTrue.assign(uninits); 1679 if (setToNull) { 1680 resetBits(inits, uninits); 1681 } 1682 } 1683 1684 /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets. 1685 */ 1686 protected void merge() { 1687 inits.assign(initsWhenFalse.andSet(initsWhenTrue)); 1688 uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue)); 1689 } 1690 1691 /* ************************************************************************ 1692 * Visitor methods for statements and definitions 1693 *************************************************************************/ 1694 1695 /** Analyze an expression. Make sure to set (un)inits rather than 1696 * (un)initsWhenTrue(WhenFalse) on exit. 1697 */ 1698 void scanExpr(JCTree tree) { 1699 if (tree != null) { 1700 scan(tree); 1701 if (inits.isReset()) { 1702 merge(); 1703 } 1704 } 1705 } 1706 1707 /** Analyze a list of expressions. 1708 */ 1709 void scanExprs(List<? extends JCExpression> trees) { 1710 if (trees != null) 1711 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail) 1712 scanExpr(l.head); 1713 } 1714 1715 /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse) 1716 * rather than (un)inits on exit. 1717 */ 1718 void scanCond(JCTree tree) { 1719 if (tree.type.isFalse()) { 1720 if (inits.isReset()) merge(); 1721 initsWhenTrue.assign(inits); 1722 initsWhenTrue.inclRange(firstadr, nextadr); 1723 uninitsWhenTrue.assign(uninits); 1724 uninitsWhenTrue.inclRange(firstadr, nextadr); 1725 initsWhenFalse.assign(inits); 1726 uninitsWhenFalse.assign(uninits); 1727 } else if (tree.type.isTrue()) { 1728 if (inits.isReset()) merge(); 1729 initsWhenFalse.assign(inits); 1730 initsWhenFalse.inclRange(firstadr, nextadr); 1731 uninitsWhenFalse.assign(uninits); 1732 uninitsWhenFalse.inclRange(firstadr, nextadr); 1733 initsWhenTrue.assign(inits); 1734 uninitsWhenTrue.assign(uninits); 1735 } else { 1736 scan(tree); 1737 if (!inits.isReset()) 1738 split(tree.type != syms.unknownType); 1739 } 1740 if (tree.type != syms.unknownType) { 1741 resetBits(inits, uninits); 1742 } 1743 } 1744 1745 /* ------------ Visitor methods for various sorts of trees -------------*/ 1746 1747 public void visitClassDef(JCClassDecl tree) { 1748 if (tree.sym == null) { 1749 return; 1750 } 1751 1752 Lint lintPrev = lint; 1753 lint = lint.augment(tree.sym); 1754 try { 1755 if (tree.sym == null) { 1756 return; 1757 } 1758 1759 JCClassDecl classDefPrev = classDef; 1760 int firstadrPrev = firstadr; 1761 int nextadrPrev = nextadr; 1762 ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits; 1763 1764 pendingExits = new ListBuffer<>(); 1765 if (tree.name != names.empty) { 1766 firstadr = nextadr; 1767 } 1768 classDef = tree; 1769 try { 1770 // define all the static fields 1771 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 1772 if (l.head.hasTag(VARDEF)) { 1773 JCVariableDecl def = (JCVariableDecl)l.head; 1774 if ((def.mods.flags & STATIC) != 0) { 1775 VarSymbol sym = def.sym; 1776 if (trackable(sym)) { 1777 newVar(def); 1778 } 1779 } 1780 } 1781 } 1782 1783 // process all the static initializers 1784 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 1785 if (!l.head.hasTag(METHODDEF) && 1786 (TreeInfo.flags(l.head) & STATIC) != 0) { 1787 scan(l.head); 1788 } 1789 } 1790 1791 // define all the instance fields 1792 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 1793 if (l.head.hasTag(VARDEF)) { 1794 JCVariableDecl def = (JCVariableDecl)l.head; 1795 if ((def.mods.flags & STATIC) == 0) { 1796 VarSymbol sym = def.sym; 1797 if (trackable(sym)) { 1798 newVar(def); 1799 } 1800 } 1801 } 1802 } 1803 1804 // process all the instance initializers 1805 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 1806 if (!l.head.hasTag(METHODDEF) && 1807 (TreeInfo.flags(l.head) & STATIC) == 0) { 1808 scan(l.head); 1809 } 1810 } 1811 1812 // process all the methods 1813 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) { 1814 if (l.head.hasTag(METHODDEF)) { 1815 scan(l.head); 1816 } 1817 } 1818 } finally { 1819 pendingExits = pendingExitsPrev; 1820 nextadr = nextadrPrev; 1821 firstadr = firstadrPrev; 1822 classDef = classDefPrev; 1823 } 1824 } finally { 1825 lint = lintPrev; 1826 } 1827 } 1828 1829 public void visitMethodDef(JCMethodDecl tree) { 1830 if (tree.body == null) { 1831 return; 1832 } 1833 1834 /* MemberEnter can generate synthetic methods ignore them 1835 */ 1836 if ((tree.sym.flags() & SYNTHETIC) != 0) { 1837 return; 1838 } 1839 1840 Lint lintPrev = lint; 1841 lint = lint.augment(tree.sym); 1842 try { 1843 if (tree.body == null) { 1844 return; 1845 } 1846 /* Ignore synthetic methods, except for translated lambda methods. 1847 */ 1848 if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) { 1849 return; 1850 } 1851 1852 final Bits initsPrev = new Bits(inits); 1853 final Bits uninitsPrev = new Bits(uninits); 1854 int nextadrPrev = nextadr; 1855 int firstadrPrev = firstadr; 1856 int returnadrPrev = returnadr; 1857 1858 Assert.check(pendingExits.isEmpty()); 1859 boolean lastInitialConstructor = isInitialConstructor; 1860 try { 1861 isInitialConstructor = TreeInfo.isInitialConstructor(tree); 1862 1863 if (!isInitialConstructor) { 1864 firstadr = nextadr; 1865 } 1866 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { 1867 JCVariableDecl def = l.head; 1868 scan(def); 1869 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag"); 1870 /* If we are executing the code from Gen, then there can be 1871 * synthetic or mandated variables, ignore them. 1872 */ 1873 initParam(def); 1874 } 1875 // else we are in an instance initializer block; 1876 // leave caught unchanged. 1877 scan(tree.body); 1878 1879 if (isInitialConstructor) { 1880 boolean isSynthesized = (tree.sym.flags() & 1881 GENERATEDCONSTR) != 0; 1882 for (int i = firstadr; i < nextadr; i++) { 1883 JCVariableDecl vardecl = vardecls[i]; 1884 VarSymbol var = vardecl.sym; 1885 if (var.owner == classDef.sym) { 1886 // choose the diagnostic position based on whether 1887 // the ctor is default(synthesized) or not 1888 if (isSynthesized) { 1889 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), 1890 var, Errors.VarNotInitializedInDefaultConstructor(var)); 1891 } else { 1892 checkInit(TreeInfo.diagEndPos(tree.body), var); 1893 } 1894 } 1895 } 1896 } 1897 List<AssignPendingExit> exits = pendingExits.toList(); 1898 pendingExits = new ListBuffer<>(); 1899 while (exits.nonEmpty()) { 1900 AssignPendingExit exit = exits.head; 1901 exits = exits.tail; 1902 Assert.check(exit.tree.hasTag(RETURN), exit.tree); 1903 if (isInitialConstructor) { 1904 inits.assign(exit.exit_inits); 1905 for (int i = firstadr; i < nextadr; i++) { 1906 checkInit(exit.tree.pos(), vardecls[i].sym); 1907 } 1908 } 1909 } 1910 } finally { 1911 inits.assign(initsPrev); 1912 uninits.assign(uninitsPrev); 1913 nextadr = nextadrPrev; 1914 firstadr = firstadrPrev; 1915 returnadr = returnadrPrev; 1916 isInitialConstructor = lastInitialConstructor; 1917 } 1918 } finally { 1919 lint = lintPrev; 1920 } 1921 } 1922 1923 protected void initParam(JCVariableDecl def) { 1924 inits.incl(def.sym.adr); 1925 uninits.excl(def.sym.adr); 1926 } 1927 1928 public void visitVarDef(JCVariableDecl tree) { 1929 Lint lintPrev = lint; 1930 lint = lint.augment(tree.sym); 1931 try{ 1932 boolean track = trackable(tree.sym); 1933 if (track && tree.sym.owner.kind == MTH) { 1934 newVar(tree); 1935 } 1936 if (tree.init != null) { 1937 scanExpr(tree.init); 1938 if (track) { 1939 letInit(tree.pos(), tree.sym); 1940 } 1941 } 1942 } finally { 1943 lint = lintPrev; 1944 } 1945 } 1946 1947 public void visitBlock(JCBlock tree) { 1948 int nextadrPrev = nextadr; 1949 scan(tree.stats); 1950 nextadr = nextadrPrev; 1951 } 1952 1953 public void visitDoLoop(JCDoWhileLoop tree) { 1954 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; 1955 FlowKind prevFlowKind = flowKind; 1956 flowKind = FlowKind.NORMAL; 1957 final Bits initsSkip = new Bits(true); 1958 final Bits uninitsSkip = new Bits(true); 1959 pendingExits = new ListBuffer<>(); 1960 int prevErrors = log.nerrors; 1961 do { 1962 final Bits uninitsEntry = new Bits(uninits); 1963 uninitsEntry.excludeFrom(nextadr); 1964 scan(tree.body); 1965 resolveContinues(tree); 1966 scanCond(tree.cond); 1967 if (!flowKind.isFinal()) { 1968 initsSkip.assign(initsWhenFalse); 1969 uninitsSkip.assign(uninitsWhenFalse); 1970 } 1971 if (log.nerrors != prevErrors || 1972 flowKind.isFinal() || 1973 new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1) 1974 break; 1975 inits.assign(initsWhenTrue); 1976 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue)); 1977 flowKind = FlowKind.SPECULATIVE_LOOP; 1978 } while (true); 1979 flowKind = prevFlowKind; 1980 inits.assign(initsSkip); 1981 uninits.assign(uninitsSkip); 1982 resolveBreaks(tree, prevPendingExits); 1983 } 1984 1985 public void visitWhileLoop(JCWhileLoop tree) { 1986 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; 1987 FlowKind prevFlowKind = flowKind; 1988 flowKind = FlowKind.NORMAL; 1989 final Bits initsSkip = new Bits(true); 1990 final Bits uninitsSkip = new Bits(true); 1991 pendingExits = new ListBuffer<>(); 1992 int prevErrors = log.nerrors; 1993 final Bits uninitsEntry = new Bits(uninits); 1994 uninitsEntry.excludeFrom(nextadr); 1995 do { 1996 scanCond(tree.cond); 1997 if (!flowKind.isFinal()) { 1998 initsSkip.assign(initsWhenFalse) ; 1999 uninitsSkip.assign(uninitsWhenFalse); 2000 } 2001 inits.assign(initsWhenTrue); 2002 uninits.assign(uninitsWhenTrue); 2003 scan(tree.body); 2004 resolveContinues(tree); 2005 if (log.nerrors != prevErrors || 2006 flowKind.isFinal() || 2007 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) { 2008 break; 2009 } 2010 uninits.assign(uninitsEntry.andSet(uninits)); 2011 flowKind = FlowKind.SPECULATIVE_LOOP; 2012 } while (true); 2013 flowKind = prevFlowKind; 2014 //a variable is DA/DU after the while statement, if it's DA/DU assuming the 2015 //branch is not taken AND if it's DA/DU before any break statement 2016 inits.assign(initsSkip); 2017 uninits.assign(uninitsSkip); 2018 resolveBreaks(tree, prevPendingExits); 2019 } 2020 2021 public void visitForLoop(JCForLoop tree) { 2022 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; 2023 FlowKind prevFlowKind = flowKind; 2024 flowKind = FlowKind.NORMAL; 2025 int nextadrPrev = nextadr; 2026 scan(tree.init); 2027 final Bits initsSkip = new Bits(true); 2028 final Bits uninitsSkip = new Bits(true); 2029 pendingExits = new ListBuffer<>(); 2030 int prevErrors = log.nerrors; 2031 do { 2032 final Bits uninitsEntry = new Bits(uninits); 2033 uninitsEntry.excludeFrom(nextadr); 2034 if (tree.cond != null) { 2035 scanCond(tree.cond); 2036 if (!flowKind.isFinal()) { 2037 initsSkip.assign(initsWhenFalse); 2038 uninitsSkip.assign(uninitsWhenFalse); 2039 } 2040 inits.assign(initsWhenTrue); 2041 uninits.assign(uninitsWhenTrue); 2042 } else if (!flowKind.isFinal()) { 2043 initsSkip.assign(inits); 2044 initsSkip.inclRange(firstadr, nextadr); 2045 uninitsSkip.assign(uninits); 2046 uninitsSkip.inclRange(firstadr, nextadr); 2047 } 2048 scan(tree.body); 2049 resolveContinues(tree); 2050 scan(tree.step); 2051 if (log.nerrors != prevErrors || 2052 flowKind.isFinal() || 2053 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) 2054 break; 2055 uninits.assign(uninitsEntry.andSet(uninits)); 2056 flowKind = FlowKind.SPECULATIVE_LOOP; 2057 } while (true); 2058 flowKind = prevFlowKind; 2059 //a variable is DA/DU after a for loop, if it's DA/DU assuming the 2060 //branch is not taken AND if it's DA/DU before any break statement 2061 inits.assign(initsSkip); 2062 uninits.assign(uninitsSkip); 2063 resolveBreaks(tree, prevPendingExits); 2064 nextadr = nextadrPrev; 2065 } 2066 2067 public void visitForeachLoop(JCEnhancedForLoop tree) { 2068 visitVarDef(tree.var); 2069 2070 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; 2071 FlowKind prevFlowKind = flowKind; 2072 flowKind = FlowKind.NORMAL; 2073 int nextadrPrev = nextadr; 2074 scan(tree.expr); 2075 final Bits initsStart = new Bits(inits); 2076 final Bits uninitsStart = new Bits(uninits); 2077 2078 letInit(tree.pos(), tree.var.sym); 2079 pendingExits = new ListBuffer<>(); 2080 int prevErrors = log.nerrors; 2081 do { 2082 final Bits uninitsEntry = new Bits(uninits); 2083 uninitsEntry.excludeFrom(nextadr); 2084 scan(tree.body); 2085 resolveContinues(tree); 2086 if (log.nerrors != prevErrors || 2087 flowKind.isFinal() || 2088 new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) 2089 break; 2090 uninits.assign(uninitsEntry.andSet(uninits)); 2091 flowKind = FlowKind.SPECULATIVE_LOOP; 2092 } while (true); 2093 flowKind = prevFlowKind; 2094 inits.assign(initsStart); 2095 uninits.assign(uninitsStart.andSet(uninits)); 2096 resolveBreaks(tree, prevPendingExits); 2097 nextadr = nextadrPrev; 2098 } 2099 2100 public void visitLabelled(JCLabeledStatement tree) { 2101 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; 2102 pendingExits = new ListBuffer<>(); 2103 scan(tree.body); 2104 resolveBreaks(tree, prevPendingExits); 2105 } 2106 2107 public void visitSwitch(JCSwitch tree) { 2108 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; 2109 pendingExits = new ListBuffer<>(); 2110 int nextadrPrev = nextadr; 2111 scanExpr(tree.selector); 2112 final Bits initsSwitch = new Bits(inits); 2113 final Bits uninitsSwitch = new Bits(uninits); 2114 boolean hasDefault = false; 2115 for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) { 2116 inits.assign(initsSwitch); 2117 uninits.assign(uninits.andSet(uninitsSwitch)); 2118 JCCase c = l.head; 2119 if (c.pat == null) { 2120 hasDefault = true; 2121 } else { 2122 scanExpr(c.pat); 2123 } 2124 if (hasDefault) { 2125 inits.assign(initsSwitch); 2126 uninits.assign(uninits.andSet(uninitsSwitch)); 2127 } 2128 scan(c.stats); 2129 addVars(c.stats, initsSwitch, uninitsSwitch); 2130 if (!hasDefault) { 2131 inits.assign(initsSwitch); 2132 uninits.assign(uninits.andSet(uninitsSwitch)); 2133 } 2134 // Warn about fall-through if lint switch fallthrough enabled. 2135 } 2136 if (!hasDefault) { 2137 inits.andSet(initsSwitch); 2138 } 2139 resolveBreaks(tree, prevPendingExits); 2140 nextadr = nextadrPrev; 2141 } 2142 // where 2143 /** Add any variables defined in stats to inits and uninits. */ 2144 private void addVars(List<JCStatement> stats, final Bits inits, 2145 final Bits uninits) { 2146 for (;stats.nonEmpty(); stats = stats.tail) { 2147 JCTree stat = stats.head; 2148 if (stat.hasTag(VARDEF)) { 2149 int adr = ((JCVariableDecl) stat).sym.adr; 2150 inits.excl(adr); 2151 uninits.incl(adr); 2152 } 2153 } 2154 } 2155 2156 public void visitTry(JCTry tree) { 2157 ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>(); 2158 final Bits uninitsTryPrev = new Bits(uninitsTry); 2159 ListBuffer<AssignPendingExit> prevPendingExits = pendingExits; 2160 pendingExits = new ListBuffer<>(); 2161 final Bits initsTry = new Bits(inits); 2162 uninitsTry.assign(uninits); 2163 for (JCTree resource : tree.resources) { 2164 if (resource instanceof JCVariableDecl) { 2165 JCVariableDecl vdecl = (JCVariableDecl) resource; 2166 visitVarDef(vdecl); 2167 unrefdResources.enter(vdecl.sym); 2168 resourceVarDecls.append(vdecl); 2169 } else if (resource instanceof JCExpression) { 2170 scanExpr((JCExpression) resource); 2171 } else { 2172 throw new AssertionError(tree); // parser error 2173 } 2174 } 2175 scan(tree.body); 2176 uninitsTry.andSet(uninits); 2177 final Bits initsEnd = new Bits(inits); 2178 final Bits uninitsEnd = new Bits(uninits); 2179 int nextadrCatch = nextadr; 2180 2181 if (!resourceVarDecls.isEmpty() && 2182 lint.isEnabled(Lint.LintCategory.TRY)) { 2183 for (JCVariableDecl resVar : resourceVarDecls) { 2184 if (unrefdResources.includes(resVar.sym)) { 2185 log.warning(Lint.LintCategory.TRY, resVar.pos(), 2186 Warnings.TryResourceNotReferenced(resVar.sym)); 2187 unrefdResources.remove(resVar.sym); 2188 } 2189 } 2190 } 2191 2192 /* The analysis of each catch should be independent. 2193 * Each one should have the same initial values of inits and 2194 * uninits. 2195 */ 2196 final Bits initsCatchPrev = new Bits(initsTry); 2197 final Bits uninitsCatchPrev = new Bits(uninitsTry); 2198 2199 for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) { 2200 JCVariableDecl param = l.head.param; 2201 inits.assign(initsCatchPrev); 2202 uninits.assign(uninitsCatchPrev); 2203 scan(param); 2204 /* If this is a TWR and we are executing the code from Gen, 2205 * then there can be synthetic variables, ignore them. 2206 */ 2207 initParam(param); 2208 scan(l.head.body); 2209 initsEnd.andSet(inits); 2210 uninitsEnd.andSet(uninits); 2211 nextadr = nextadrCatch; 2212 } 2213 if (tree.finalizer != null) { 2214 inits.assign(initsTry); 2215 uninits.assign(uninitsTry); 2216 ListBuffer<AssignPendingExit> exits = pendingExits; 2217 pendingExits = prevPendingExits; 2218 scan(tree.finalizer); 2219 if (!tree.finallyCanCompleteNormally) { 2220 // discard exits and exceptions from try and finally 2221 } else { 2222 uninits.andSet(uninitsEnd); 2223 // FIX: this doesn't preserve source order of exits in catch 2224 // versus finally! 2225 while (exits.nonEmpty()) { 2226 AssignPendingExit exit = exits.next(); 2227 if (exit.exit_inits != null) { 2228 exit.exit_inits.orSet(inits); 2229 exit.exit_uninits.andSet(uninits); 2230 } 2231 pendingExits.append(exit); 2232 } 2233 inits.orSet(initsEnd); 2234 } 2235 } else { 2236 inits.assign(initsEnd); 2237 uninits.assign(uninitsEnd); 2238 ListBuffer<AssignPendingExit> exits = pendingExits; 2239 pendingExits = prevPendingExits; 2240 while (exits.nonEmpty()) pendingExits.append(exits.next()); 2241 } 2242 uninitsTry.andSet(uninitsTryPrev).andSet(uninits); 2243 } 2244 2245 public void visitConditional(JCConditional tree) { 2246 scanCond(tree.cond); 2247 final Bits initsBeforeElse = new Bits(initsWhenFalse); 2248 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); 2249 inits.assign(initsWhenTrue); 2250 uninits.assign(uninitsWhenTrue); 2251 if (tree.truepart.type.hasTag(BOOLEAN) && 2252 tree.falsepart.type.hasTag(BOOLEAN)) { 2253 // if b and c are boolean valued, then 2254 // v is (un)assigned after a?b:c when true iff 2255 // v is (un)assigned after b when true and 2256 // v is (un)assigned after c when true 2257 scanCond(tree.truepart); 2258 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue); 2259 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse); 2260 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue); 2261 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse); 2262 inits.assign(initsBeforeElse); 2263 uninits.assign(uninitsBeforeElse); 2264 scanCond(tree.falsepart); 2265 initsWhenTrue.andSet(initsAfterThenWhenTrue); 2266 initsWhenFalse.andSet(initsAfterThenWhenFalse); 2267 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue); 2268 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse); 2269 } else { 2270 scanExpr(tree.truepart); 2271 final Bits initsAfterThen = new Bits(inits); 2272 final Bits uninitsAfterThen = new Bits(uninits); 2273 inits.assign(initsBeforeElse); 2274 uninits.assign(uninitsBeforeElse); 2275 scanExpr(tree.falsepart); 2276 inits.andSet(initsAfterThen); 2277 uninits.andSet(uninitsAfterThen); 2278 } 2279 } 2280 2281 public void visitIf(JCIf tree) { 2282 scanCond(tree.cond); 2283 final Bits initsBeforeElse = new Bits(initsWhenFalse); 2284 final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse); 2285 inits.assign(initsWhenTrue); 2286 uninits.assign(uninitsWhenTrue); 2287 scan(tree.thenpart); 2288 if (tree.elsepart != null) { 2289 final Bits initsAfterThen = new Bits(inits); 2290 final Bits uninitsAfterThen = new Bits(uninits); 2291 inits.assign(initsBeforeElse); 2292 uninits.assign(uninitsBeforeElse); 2293 scan(tree.elsepart); 2294 inits.andSet(initsAfterThen); 2295 uninits.andSet(uninitsAfterThen); 2296 } else { 2297 inits.andSet(initsBeforeElse); 2298 uninits.andSet(uninitsBeforeElse); 2299 } 2300 } 2301 2302 @Override 2303 public void visitBreak(JCBreak tree) { 2304 recordExit(new AssignPendingExit(tree, inits, uninits)); 2305 } 2306 2307 @Override 2308 public void visitContinue(JCContinue tree) { 2309 recordExit(new AssignPendingExit(tree, inits, uninits)); 2310 } 2311 2312 @Override 2313 public void visitReturn(JCReturn tree) { 2314 scanExpr(tree.expr); 2315 recordExit(new AssignPendingExit(tree, inits, uninits)); 2316 } 2317 2318 public void visitThrow(JCThrow tree) { 2319 scanExpr(tree.expr); 2320 markDead(); 2321 } 2322 2323 public void visitApply(JCMethodInvocation tree) { 2324 scanExpr(tree.meth); 2325 scanExprs(tree.args); 2326 } 2327 2328 public void visitNewClass(JCNewClass tree) { 2329 scanExpr(tree.encl); 2330 scanExprs(tree.args); 2331 scan(tree.def); 2332 } 2333 2334 @Override 2335 public void visitLambda(JCLambda tree) { 2336 final Bits prevUninits = new Bits(uninits); 2337 final Bits prevInits = new Bits(inits); 2338 int returnadrPrev = returnadr; 2339 int nextadrPrev = nextadr; 2340 ListBuffer<AssignPendingExit> prevPending = pendingExits; 2341 try { 2342 returnadr = nextadr; 2343 pendingExits = new ListBuffer<>(); 2344 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) { 2345 JCVariableDecl def = l.head; 2346 scan(def); 2347 inits.incl(def.sym.adr); 2348 uninits.excl(def.sym.adr); 2349 } 2350 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) { 2351 scanExpr(tree.body); 2352 } else { 2353 scan(tree.body); 2354 } 2355 } 2356 finally { 2357 returnadr = returnadrPrev; 2358 uninits.assign(prevUninits); 2359 inits.assign(prevInits); 2360 pendingExits = prevPending; 2361 nextadr = nextadrPrev; 2362 } 2363 } 2364 2365 public void visitNewArray(JCNewArray tree) { 2366 scanExprs(tree.dims); 2367 scanExprs(tree.elems); 2368 } 2369 2370 public void visitAssert(JCAssert tree) { 2371 final Bits initsExit = new Bits(inits); 2372 final Bits uninitsExit = new Bits(uninits); 2373 scanCond(tree.cond); 2374 uninitsExit.andSet(uninitsWhenTrue); 2375 if (tree.detail != null) { 2376 inits.assign(initsWhenFalse); 2377 uninits.assign(uninitsWhenFalse); 2378 scanExpr(tree.detail); 2379 } 2380 inits.assign(initsExit); 2381 uninits.assign(uninitsExit); 2382 } 2383 2384 public void visitAssign(JCAssign tree) { 2385 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs)) 2386 scanExpr(tree.lhs); 2387 scanExpr(tree.rhs); 2388 letInit(tree.lhs); 2389 } 2390 2391 // check fields accessed through this.<field> are definitely 2392 // assigned before reading their value 2393 public void visitSelect(JCFieldAccess tree) { 2394 super.visitSelect(tree); 2395 if (TreeInfo.isThisQualifier(tree.selected) && 2396 tree.sym.kind == VAR) { 2397 checkInit(tree.pos(), (VarSymbol)tree.sym); 2398 } 2399 } 2400 2401 public void visitAssignop(JCAssignOp tree) { 2402 scanExpr(tree.lhs); 2403 scanExpr(tree.rhs); 2404 letInit(tree.lhs); 2405 } 2406 2407 public void visitUnary(JCUnary tree) { 2408 switch (tree.getTag()) { 2409 case NOT: 2410 scanCond(tree.arg); 2411 final Bits t = new Bits(initsWhenFalse); 2412 initsWhenFalse.assign(initsWhenTrue); 2413 initsWhenTrue.assign(t); 2414 t.assign(uninitsWhenFalse); 2415 uninitsWhenFalse.assign(uninitsWhenTrue); 2416 uninitsWhenTrue.assign(t); 2417 break; 2418 case PREINC: case POSTINC: 2419 case PREDEC: case POSTDEC: 2420 scanExpr(tree.arg); 2421 letInit(tree.arg); 2422 break; 2423 default: 2424 scanExpr(tree.arg); 2425 } 2426 } 2427 2428 public void visitBinary(JCBinary tree) { 2429 switch (tree.getTag()) { 2430 case AND: 2431 scanCond(tree.lhs); 2432 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse); 2433 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse); 2434 inits.assign(initsWhenTrue); 2435 uninits.assign(uninitsWhenTrue); 2436 scanCond(tree.rhs); 2437 initsWhenFalse.andSet(initsWhenFalseLeft); 2438 uninitsWhenFalse.andSet(uninitsWhenFalseLeft); 2439 break; 2440 case OR: 2441 scanCond(tree.lhs); 2442 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue); 2443 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue); 2444 inits.assign(initsWhenFalse); 2445 uninits.assign(uninitsWhenFalse); 2446 scanCond(tree.rhs); 2447 initsWhenTrue.andSet(initsWhenTrueLeft); 2448 uninitsWhenTrue.andSet(uninitsWhenTrueLeft); 2449 break; 2450 default: 2451 scanExpr(tree.lhs); 2452 scanExpr(tree.rhs); 2453 } 2454 } 2455 2456 public void visitIdent(JCIdent tree) { 2457 if (tree.sym.kind == VAR) { 2458 checkInit(tree.pos(), (VarSymbol)tree.sym); 2459 referenced(tree.sym); 2460 } 2461 } 2462 2463 void referenced(Symbol sym) { 2464 unrefdResources.remove(sym); 2465 } 2466 2467 public void visitAnnotatedType(JCAnnotatedType tree) { 2468 // annotations don't get scanned 2469 tree.underlyingType.accept(this); 2470 } 2471 2472 public void visitModuleDef(JCModuleDecl tree) { 2473 // Do nothing for modules 2474 } 2475 2476 /************************************************************************** 2477 * main method 2478 *************************************************************************/ 2479 2480 /** Perform definite assignment/unassignment analysis on a tree. 2481 */ 2482 public void analyzeTree(Env<?> env) { 2483 analyzeTree(env, env.tree); 2484 } 2485 2486 public void analyzeTree(Env<?> env, JCTree tree) { 2487 try { 2488 startPos = tree.pos().getStartPosition(); 2489 2490 if (vardecls == null) 2491 vardecls = new JCVariableDecl[32]; 2492 else 2493 for (int i=0; i<vardecls.length; i++) 2494 vardecls[i] = null; 2495 firstadr = 0; 2496 nextadr = 0; 2497 pendingExits = new ListBuffer<>(); 2498 this.classDef = null; 2499 unrefdResources = WriteableScope.create(env.enclClass.sym); 2500 scan(tree); 2501 } finally { 2502 // note that recursive invocations of this method fail hard 2503 startPos = -1; 2504 resetBits(inits, uninits, uninitsTry, initsWhenTrue, 2505 initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse); 2506 if (vardecls != null) { 2507 for (int i=0; i<vardecls.length; i++) 2508 vardecls[i] = null; 2509 } 2510 firstadr = 0; 2511 nextadr = 0; 2512 pendingExits = null; 2513 this.classDef = null; 2514 unrefdResources = null; 2515 } 2516 } 2517 } 2518 2519 /** 2520 * This pass implements the last step of the dataflow analysis, namely 2521 * the effectively-final analysis check. This checks that every local variable 2522 * reference from a lambda body/local inner class is either final or effectively final. 2523 * Additional this also checks that every variable that is used as an operand to 2524 * try-with-resources is final or effectively final. 2525 * As effectively final variables are marked as such during DA/DU, this pass must run after 2526 * AssignAnalyzer. 2527 */ 2528 class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> { 2529 2530 JCTree currentTree; //local class or lambda 2531 2532 @Override 2533 void markDead() { 2534 //do nothing 2535 } 2536 2537 @SuppressWarnings("fallthrough") 2538 void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) { 2539 if (currentTree != null && 2540 sym.owner.kind == MTH && 2541 sym.pos < currentTree.getStartPosition()) { 2542 switch (currentTree.getTag()) { 2543 case CLASSDEF: 2544 if (!allowEffectivelyFinalInInnerClasses) { 2545 if ((sym.flags() & FINAL) == 0) { 2546 reportInnerClsNeedsFinalError(pos, sym); 2547 } 2548 break; 2549 } 2550 case LAMBDA: 2551 if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) { 2552 reportEffectivelyFinalError(pos, sym); 2553 } 2554 } 2555 } 2556 } 2557 2558 @SuppressWarnings("fallthrough") 2559 void letInit(JCTree tree) { 2560 tree = TreeInfo.skipParens(tree); 2561 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) { 2562 Symbol sym = TreeInfo.symbol(tree); 2563 if (currentTree != null && 2564 sym.kind == VAR && 2565 sym.owner.kind == MTH && 2566 ((VarSymbol)sym).pos < currentTree.getStartPosition()) { 2567 switch (currentTree.getTag()) { 2568 case CLASSDEF: 2569 if (!allowEffectivelyFinalInInnerClasses) { 2570 reportInnerClsNeedsFinalError(tree, sym); 2571 break; 2572 } 2573 case LAMBDA: 2574 reportEffectivelyFinalError(tree, sym); 2575 } 2576 } 2577 } 2578 } 2579 2580 void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) { 2581 String subKey = currentTree.hasTag(LAMBDA) ? 2582 "lambda" : "inner.cls"; 2583 log.error(pos, Errors.CantRefNonEffectivelyFinalVar(sym, diags.fragment(subKey))); 2584 } 2585 2586 void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) { 2587 log.error(pos, 2588 Errors.LocalVarAccessedFromIclsNeedsFinal(sym)); 2589 } 2590 2591 /************************************************************************* 2592 * Visitor methods for statements and definitions 2593 *************************************************************************/ 2594 2595 /* ------------ Visitor methods for various sorts of trees -------------*/ 2596 2597 public void visitClassDef(JCClassDecl tree) { 2598 JCTree prevTree = currentTree; 2599 try { 2600 currentTree = tree.sym.isLocal() ? tree : null; 2601 super.visitClassDef(tree); 2602 } finally { 2603 currentTree = prevTree; 2604 } 2605 } 2606 2607 @Override 2608 public void visitLambda(JCLambda tree) { 2609 JCTree prevTree = currentTree; 2610 try { 2611 currentTree = tree; 2612 super.visitLambda(tree); 2613 } finally { 2614 currentTree = prevTree; 2615 } 2616 } 2617 2618 @Override 2619 public void visitIdent(JCIdent tree) { 2620 if (tree.sym.kind == VAR) { 2621 checkEffectivelyFinal(tree, (VarSymbol)tree.sym); 2622 } 2623 } 2624 2625 public void visitAssign(JCAssign tree) { 2626 JCTree lhs = TreeInfo.skipParens(tree.lhs); 2627 if (!(lhs instanceof JCIdent)) { 2628 scan(lhs); 2629 } 2630 scan(tree.rhs); 2631 letInit(lhs); 2632 } 2633 2634 public void visitAssignop(JCAssignOp tree) { 2635 scan(tree.lhs); 2636 scan(tree.rhs); 2637 letInit(tree.lhs); 2638 } 2639 2640 public void visitUnary(JCUnary tree) { 2641 switch (tree.getTag()) { 2642 case PREINC: case POSTINC: 2643 case PREDEC: case POSTDEC: 2644 scan(tree.arg); 2645 letInit(tree.arg); 2646 break; 2647 default: 2648 scan(tree.arg); 2649 } 2650 } 2651 2652 public void visitTry(JCTry tree) { 2653 for (JCTree resource : tree.resources) { 2654 if (!resource.hasTag(VARDEF)) { 2655 Symbol var = TreeInfo.symbol(resource); 2656 if (var != null && (var.flags() & (FINAL | EFFECTIVELY_FINAL)) == 0) { 2657 log.error(resource.pos(), Errors.TryWithResourcesExprEffectivelyFinalVar(var)); 2658 } 2659 } 2660 } 2661 super.visitTry(tree); 2662 } 2663 2664 public void visitModuleDef(JCModuleDecl tree) { 2665 // Do nothing for modules 2666 } 2667 2668 /************************************************************************** 2669 * main method 2670 *************************************************************************/ 2671 2672 /** Perform definite assignment/unassignment analysis on a tree. 2673 */ 2674 public void analyzeTree(Env<AttrContext> env, TreeMaker make) { 2675 analyzeTree(env, env.tree, make); 2676 } 2677 public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) { 2678 try { 2679 attrEnv = env; 2680 Flow.this.make = make; 2681 pendingExits = new ListBuffer<>(); 2682 scan(tree); 2683 } finally { 2684 pendingExits = null; 2685 Flow.this.make = null; 2686 } 2687 } 2688 } 2689 }