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