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