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