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