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