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