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