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