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