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