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