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