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