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