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