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