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