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 breaksOutOf(Env<AttrContext> env, JCTree loop, 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             SnippetBreakAnalyzer analyzer = new SnippetBreakAnalyzer();
 301 
 302             analyzer.analyzeTree(env, body, make);
 303             return analyzer.breaksOut();
 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             List<PatternDescription> patterns = List.from(patternSet);
 779             try {
 780                 boolean repeat = true;
 781                 while (repeat) {
 782                     List<PatternDescription> updatedPatterns;
 783                     updatedPatterns = reduceBindingPatterns(selector.type, patterns);
 784                     updatedPatterns = reduceNestedPatterns(updatedPatterns);
 785                     updatedPatterns = reduceRecordPatterns(updatedPatterns);
 786                     repeat = updatedPatterns != patterns;
 787                     patterns = updatedPatterns;
 788                     if (checkCovered(selector.type, patterns)) {
 789                         return true;
 790                     }
 791                 }
 792                 return checkCovered(selector.type, patterns);
 793             } catch (CompletionFailure cf) {
 794                 chk.completionError(selector.pos(), cf);
 795                 return true; //error recovery
 796             }
 797         }
 798 
 799         private boolean checkCovered(Type seltype, List<PatternDescription> patterns) {
 800             for (Type seltypeComponent : components(seltype)) {
 801                 for (PatternDescription pd : patterns) {
 802                     if (pd instanceof BindingPattern bp &&
 803                         types.isSubtype(seltypeComponent, types.erasure(bp.type))) {
 804                         return true;
 805                     }
 806                 }
 807             }
 808             return false;
 809         }
 810 
 811         private List<Type> components(Type seltype) {
 812             return switch (seltype.getTag()) {
 813                 case CLASS -> {
 814                     if (seltype.isCompound()) {
 815                         if (seltype.isIntersection()) {
 816                             yield ((Type.IntersectionClassType) seltype).getComponents()
 817                                                                         .stream()
 818                                                                         .flatMap(t -> components(t).stream())
 819                                                                         .collect(List.collector());
 820                         }
 821                         yield List.nil();
 822                     }
 823                     yield List.of(types.erasure(seltype));
 824                 }
 825                 case TYPEVAR -> components(((TypeVar) seltype).getUpperBound());
 826                 default -> List.of(types.erasure(seltype));
 827             };
 828         }
 829 
 830         /* In a set of patterns, search for a sub-set of binding patterns that
 831          * in combination exhaust their sealed supertype. If such a sub-set
 832          * is found, it is removed, and replaced with a binding pattern
 833          * for the sealed supertype.
 834          */
 835         private List<PatternDescription> reduceBindingPatterns(Type selectorType, List<PatternDescription> patterns) {
 836             Set<Symbol> existingBindings = patterns.stream()
 837                                                    .filter(pd -> pd instanceof BindingPattern)
 838                                                    .map(pd -> ((BindingPattern) pd).type.tsym)
 839                                                    .collect(Collectors.toSet());
 840 
 841             for (PatternDescription pdOne : patterns) {
 842                 if (pdOne instanceof BindingPattern bpOne) {
 843                     Set<PatternDescription> toRemove = new HashSet<>();
 844                     Set<PatternDescription> toAdd = new HashSet<>();
 845 
 846                     for (Type sup : types.directSupertypes(bpOne.type)) {
 847                         ClassSymbol clazz = (ClassSymbol) sup.tsym;
 848 
 849                         if (clazz.isSealed() && clazz.isAbstract() &&
 850                             //if a binding pattern for clazz already exists, no need to analyze it again:
 851                             !existingBindings.contains(clazz)) {
 852                             ListBuffer<PatternDescription> bindings = new ListBuffer<>();
 853                             //do not reduce to types unrelated to the selector type:
 854                             Type clazzErasure = types.erasure(clazz.type);
 855                             if (components(selectorType).stream()
 856                                                         .map(types::erasure)
 857                                                         .noneMatch(c -> types.isSubtype(clazzErasure, c))) {
 858                                 continue;
 859                             }
 860 
 861                             Set<Symbol> permitted = allPermittedSubTypes(clazz, csym -> {
 862                                 Type instantiated;
 863                                 if (csym.type.allparams().isEmpty()) {
 864                                     instantiated = csym.type;
 865                                 } else {
 866                                     instantiated = infer.instantiatePatternType(selectorType, csym);
 867                                 }
 868 
 869                                 return instantiated != null && types.isCastable(selectorType, instantiated);
 870                             });
 871 
 872                             for (PatternDescription pdOther : patterns) {
 873                                 if (pdOther instanceof BindingPattern bpOther) {
 874                                     boolean reduces = false;
 875                                     Set<Symbol> currentPermittedSubTypes =
 876                                             allPermittedSubTypes((ClassSymbol) bpOther.type.tsym, s -> true);
 877 
 878                                     PERMITTED: for (Iterator<Symbol> it = permitted.iterator(); it.hasNext();) {
 879                                         Symbol perm = it.next();
 880 
 881                                         for (Symbol currentPermitted : currentPermittedSubTypes) {
 882                                             if (types.isSubtype(types.erasure(currentPermitted.type),
 883                                                                 types.erasure(perm.type))) {
 884                                                 it.remove();
 885                                                 continue PERMITTED;
 886                                             }
 887                                         }
 888                                         if (types.isSubtype(types.erasure(perm.type),
 889                                                             types.erasure(bpOther.type))) {
 890                                             it.remove();
 891                                             reduces = true;
 892                                         }
 893                                     }
 894 
 895                                     if (reduces) {
 896                                         bindings.append(pdOther);
 897                                     }
 898                                 }
 899                             }
 900 
 901                             if (permitted.isEmpty()) {
 902                                 toRemove.addAll(bindings);
 903                                 toAdd.add(new BindingPattern(clazz.type));
 904                             }
 905                         }
 906                     }
 907 
 908                     if (!toAdd.isEmpty() || !toRemove.isEmpty()) {
 909                         for (PatternDescription pd : toRemove) {
 910                             patterns = List.filter(patterns, pd);
 911                         }
 912                         for (PatternDescription pd : toAdd) {
 913                             patterns = patterns.prepend(pd);
 914                         }
 915                         return patterns;
 916                     }
 917                 }
 918             }
 919             return patterns;
 920         }
 921 
 922         private Set<Symbol> allPermittedSubTypes(ClassSymbol root, Predicate<ClassSymbol> accept) {
 923             Set<Symbol> permitted = new HashSet<>();
 924             List<ClassSymbol> permittedSubtypesClosure = List.of(root);
 925 
 926             while (permittedSubtypesClosure.nonEmpty()) {
 927                 ClassSymbol current = permittedSubtypesClosure.head;
 928 
 929                 permittedSubtypesClosure = permittedSubtypesClosure.tail;
 930 
 931                 if (current.isSealed() && current.isAbstract()) {
 932                     for (Symbol sym : current.permitted) {
 933                         ClassSymbol csym = (ClassSymbol) sym;
 934 
 935                         if (accept.test(csym)) {
 936                             permittedSubtypesClosure = permittedSubtypesClosure.prepend(csym);
 937                             permitted.add(csym);
 938                         }
 939                     }
 940                 }
 941             }
 942 
 943             return permitted;
 944         }
 945 
 946         /* Among the set of patterns, find sub-set of patterns such:
 947          * $record($prefix$, $nested, $suffix$)
 948          * Where $record, $prefix$ and $suffix$ is the same for each pattern
 949          * in the set, and the patterns only differ in one "column" in
 950          * the $nested pattern.
 951          * Then, the set of $nested patterns is taken, and passed recursively
 952          * to reduceNestedPatterns and to reduceBindingPatterns, to
 953          * simplify the pattern. If that succeeds, the original found sub-set
 954          * of patterns is replaced with a new set of patterns of the form:
 955          * $record($prefix$, $resultOfReduction, $suffix$)
 956          */
 957         private List<PatternDescription> reduceNestedPatterns(List<PatternDescription> patterns) {
 958             /* implementation note:
 959              * finding a sub-set of patterns that only differ in a single
 960              * column is time-consuming task, so this method speeds it up by:
 961              * - group the patterns by their record class
 962              * - for each column (nested pattern) do:
 963              * -- group patterns by their hash
 964              * -- in each such by-hash group, find sub-sets that only differ in
 965              *    the chosen column, and then call reduceBindingPatterns and reduceNestedPatterns
 966              *    on patterns in the chosen column, as described above
 967              */
 968             var groupByRecordClass =
 969                     patterns.stream()
 970                             .filter(pd -> pd instanceof RecordPattern)
 971                             .map(pd -> (RecordPattern) pd)
 972                             .collect(groupingBy(pd -> (ClassSymbol) pd.recordType.tsym));
 973 
 974             for (var e : groupByRecordClass.entrySet()) {
 975                 int nestedPatternsCount = e.getKey().getRecordComponents().size();
 976 
 977                 for (int mismatchingCandidate = 0;
 978                      mismatchingCandidate < nestedPatternsCount;
 979                      mismatchingCandidate++) {
 980                     int mismatchingCandidateFin = mismatchingCandidate;
 981                     var groupByHashes =
 982                             e.getValue()
 983                              .stream()
 984                              //error recovery, ignore patterns with incorrect number of nested patterns:
 985                              .filter(pd -> pd.nested.length == nestedPatternsCount)
 986                              .collect(groupingBy(pd -> pd.hashCode(mismatchingCandidateFin)));
 987                     for (var candidates : groupByHashes.values()) {
 988                         var candidatesArr = candidates.toArray(RecordPattern[]::new);
 989 
 990                         for (int firstCandidate = 0;
 991                              firstCandidate < candidatesArr.length;
 992                              firstCandidate++) {
 993                             RecordPattern rpOne = candidatesArr[firstCandidate];
 994                             ListBuffer<RecordPattern> join = new ListBuffer<>();
 995 
 996                             join.append(rpOne);
 997 
 998                             NEXT_PATTERN: for (int nextCandidate = 0;
 999                                                nextCandidate < candidatesArr.length;
1000                                                nextCandidate++) {
1001                                 if (firstCandidate == nextCandidate) {
1002                                     continue;
1003                                 }
1004 
1005                                 RecordPattern rpOther = candidatesArr[nextCandidate];
1006                                 if (rpOne.recordType.tsym == rpOther.recordType.tsym) {
1007                                     for (int i = 0; i < rpOne.nested.length; i++) {
1008                                         if (i != mismatchingCandidate &&
1009                                             !rpOne.nested[i].equals(rpOther.nested[i])) {
1010                                             continue NEXT_PATTERN;
1011                                         }
1012                                     }
1013                                     join.append(rpOther);
1014                                 }
1015                             }
1016 
1017                             var nestedPatterns = join.stream().map(rp -> rp.nested[mismatchingCandidateFin]).collect(List.collector());
1018                             var updatedPatterns = reduceNestedPatterns(nestedPatterns);
1019 
1020                             updatedPatterns = reduceRecordPatterns(updatedPatterns);
1021                             updatedPatterns = reduceBindingPatterns(rpOne.fullComponentTypes()[mismatchingCandidateFin], updatedPatterns);
1022 
1023                             if (nestedPatterns != updatedPatterns) {
1024                                 ListBuffer<PatternDescription> result = new ListBuffer<>();
1025                                 Set<PatternDescription> toRemove = Collections.newSetFromMap(new IdentityHashMap<>());
1026 
1027                                 toRemove.addAll(join);
1028 
1029                                 for (PatternDescription p : patterns) {
1030                                     if (!toRemove.contains(p)) {
1031                                         result.append(p);
1032                                     }
1033                                 }
1034 
1035                                 for (PatternDescription nested : updatedPatterns) {
1036                                     PatternDescription[] newNested =
1037                                             Arrays.copyOf(rpOne.nested, rpOne.nested.length);
1038                                     newNested[mismatchingCandidateFin] = nested;
1039                                     result.append(new RecordPattern(rpOne.recordType(),
1040                                                                     rpOne.fullComponentTypes(),
1041                                                                     newNested));
1042                                 }
1043                                 return result.toList();
1044                             }
1045                         }
1046                     }
1047                 }
1048             }
1049             return patterns;
1050         }
1051 
1052         /* In the set of patterns, find those for which, given:
1053          * $record($nested1, $nested2, ...)
1054          * all the $nestedX pattern cover the given record component,
1055          * and replace those with a simple binding pattern over $record.
1056          */
1057         private List<PatternDescription> reduceRecordPatterns(List<PatternDescription> patterns) {
1058             var newPatterns = new ListBuffer<PatternDescription>();
1059             boolean modified = false;
1060             for (PatternDescription pd : patterns) {
1061                 if (pd instanceof RecordPattern rpOne) {
1062                     PatternDescription reducedPattern = reduceRecordPattern(rpOne);
1063                     if (reducedPattern != rpOne) {
1064                         newPatterns.append(reducedPattern);
1065                         modified = true;
1066                         continue;
1067                     }
1068                 }
1069                 newPatterns.append(pd);
1070             }
1071             return modified ? newPatterns.toList() : patterns;
1072                 }
1073 
1074         private PatternDescription reduceRecordPattern(PatternDescription pattern) {
1075             if (pattern instanceof RecordPattern rpOne) {
1076                 Type[] componentType = rpOne.fullComponentTypes();
1077                 //error recovery, ignore patterns with incorrect number of nested patterns:
1078                 if (componentType.length != rpOne.nested.length) {
1079                     return pattern;
1080                 }
1081                 PatternDescription[] reducedNestedPatterns = null;
1082                 boolean covered = true;
1083                 for (int i = 0; i < componentType.length; i++) {
1084                     PatternDescription newNested = reduceRecordPattern(rpOne.nested[i]);
1085                     if (newNested != rpOne.nested[i]) {
1086                         if (reducedNestedPatterns == null) {
1087                             reducedNestedPatterns = Arrays.copyOf(rpOne.nested, rpOne.nested.length);
1088                         }
1089                         reducedNestedPatterns[i] = newNested;
1090                     }
1091 
1092                     covered &= newNested instanceof BindingPattern bp &&
1093                                types.isSubtype(types.erasure(componentType[i]), types.erasure(bp.type));
1094                 }
1095                 if (covered) {
1096                     return new BindingPattern(rpOne.recordType);
1097                 } else if (reducedNestedPatterns != null) {
1098                     return new RecordPattern(rpOne.recordType, rpOne.fullComponentTypes(), reducedNestedPatterns);
1099                 }
1100             }
1101             return pattern;
1102         }
1103 
1104         public void visitTry(JCTry tree) {
1105             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1106             pendingExits = new ListBuffer<>();
1107             for (JCTree resource : tree.resources) {
1108                 if (resource instanceof JCVariableDecl variableDecl) {
1109                     visitVarDef(variableDecl);
1110                 } else if (resource instanceof JCExpression expression) {
1111                     scan(expression);
1112                 } else {
1113                     throw new AssertionError(tree);  // parser error
1114                 }
1115             }
1116 
1117             scanStat(tree.body);
1118             Liveness aliveEnd = alive;
1119 
1120             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1121                 alive = Liveness.ALIVE;
1122                 JCVariableDecl param = l.head.param;
1123                 scan(param);
1124                 scanStat(l.head.body);
1125                 aliveEnd = aliveEnd.or(alive);
1126             }
1127             if (tree.finalizer != null) {
1128                 ListBuffer<PendingExit> exits = pendingExits;
1129                 pendingExits = prevPendingExits;
1130                 alive = Liveness.ALIVE;
1131                 scanStat(tree.finalizer);
1132                 tree.finallyCanCompleteNormally = alive != Liveness.DEAD;
1133                 if (alive == Liveness.DEAD) {
1134                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
1135                         log.warning(Lint.LintCategory.FINALLY,
1136                                 TreeInfo.diagEndPos(tree.finalizer),
1137                                 Warnings.FinallyCannotComplete);
1138                     }
1139                 } else {
1140                     while (exits.nonEmpty()) {
1141                         pendingExits.append(exits.next());
1142                     }
1143                     alive = aliveEnd;
1144                 }
1145             } else {
1146                 alive = aliveEnd;
1147                 ListBuffer<PendingExit> exits = pendingExits;
1148                 pendingExits = prevPendingExits;
1149                 while (exits.nonEmpty()) pendingExits.append(exits.next());
1150             }
1151         }
1152 
1153         @Override
1154         public void visitIf(JCIf tree) {
1155             scan(tree.cond);
1156             scanStat(tree.thenpart);
1157             if (tree.elsepart != null) {
1158                 Liveness aliveAfterThen = alive;
1159                 alive = Liveness.ALIVE;
1160                 scanStat(tree.elsepart);
1161                 alive = alive.or(aliveAfterThen);
1162             } else {
1163                 alive = Liveness.ALIVE;
1164             }
1165         }
1166 
1167         public void visitBreak(JCBreak tree) {
1168             recordExit(new PendingExit(tree));
1169         }
1170 
1171         @Override
1172         public void visitYield(JCYield tree) {
1173             scan(tree.value);
1174             recordExit(new PendingExit(tree));
1175         }
1176 
1177         public void visitContinue(JCContinue tree) {
1178             recordExit(new PendingExit(tree));
1179         }
1180 
1181         public void visitReturn(JCReturn tree) {
1182             scan(tree.expr);
1183             recordExit(new PendingExit(tree));
1184         }
1185 
1186         public void visitThrow(JCThrow tree) {
1187             scan(tree.expr);
1188             markDead();
1189         }
1190 
1191         public void visitApply(JCMethodInvocation tree) {
1192             scan(tree.meth);
1193             scan(tree.args);
1194         }
1195 
1196         public void visitNewClass(JCNewClass tree) {
1197             scan(tree.encl);
1198             scan(tree.args);
1199             if (tree.def != null) {
1200                 scan(tree.def);
1201             }
1202         }
1203 
1204         @Override
1205         public void visitLambda(JCLambda tree) {
1206             if (tree.type != null &&
1207                     tree.type.isErroneous()) {
1208                 return;
1209             }
1210 
1211             ListBuffer<PendingExit> prevPending = pendingExits;
1212             Liveness prevAlive = alive;
1213             try {
1214                 pendingExits = new ListBuffer<>();
1215                 alive = Liveness.ALIVE;
1216                 scanStat(tree.body);
1217                 tree.canCompleteNormally = alive != Liveness.DEAD;
1218             }
1219             finally {
1220                 pendingExits = prevPending;
1221                 alive = prevAlive;
1222             }
1223         }
1224 
1225         public void visitModuleDef(JCModuleDecl tree) {
1226             // Do nothing for modules
1227         }
1228 
1229     /**************************************************************************
1230      * main method
1231      *************************************************************************/
1232 
1233         /** Perform definite assignment/unassignment analysis on a tree.
1234          */
1235         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
1236             analyzeTree(env, env.tree, make);
1237         }
1238         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
1239             try {
1240                 attrEnv = env;
1241                 Flow.this.make = make;
1242                 pendingExits = new ListBuffer<>();
1243                 alive = Liveness.ALIVE;
1244                 scan(tree);
1245             } finally {
1246                 pendingExits = null;
1247                 Flow.this.make = null;
1248             }
1249         }
1250     }
1251 
1252     /**
1253      * This pass implements the second step of the dataflow analysis, namely
1254      * the exception analysis. This is to ensure that every checked exception that is
1255      * thrown is declared or caught. The analyzer uses some info that has been set by
1256      * the liveliness analyzer.
1257      */
1258     class FlowAnalyzer extends BaseAnalyzer {
1259 
1260         /** A flag that indicates whether the last statement could
1261          *  complete normally.
1262          */
1263         HashMap<Symbol, List<Type>> preciseRethrowTypes;
1264 
1265         /** The current class being defined.
1266          */
1267         JCClassDecl classDef;
1268 
1269         /** The list of possibly thrown declarable exceptions.
1270          */
1271         List<Type> thrown;
1272 
1273         /** The list of exceptions that are either caught or declared to be
1274          *  thrown.
1275          */
1276         List<Type> caught;
1277 
1278         class ThrownPendingExit extends BaseAnalyzer.PendingExit {
1279 
1280             Type thrown;
1281 
1282             ThrownPendingExit(JCTree tree, Type thrown) {
1283                 super(tree);
1284                 this.thrown = thrown;
1285             }
1286         }
1287 
1288         @Override
1289         void markDead() {
1290             //do nothing
1291         }
1292 
1293         /*-------------------- Exceptions ----------------------*/
1294 
1295         /** Complain that pending exceptions are not caught.
1296          */
1297         void errorUncaught() {
1298             for (PendingExit exit = pendingExits.next();
1299                  exit != null;
1300                  exit = pendingExits.next()) {
1301                 if (exit instanceof ThrownPendingExit thrownExit) {
1302                     if (classDef != null &&
1303                         classDef.pos == exit.tree.pos) {
1304                         log.error(exit.tree.pos(),
1305                                   Errors.UnreportedExceptionDefaultConstructor(thrownExit.thrown));
1306                     } else if (exit.tree.hasTag(VARDEF) &&
1307                             ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
1308                         log.error(exit.tree.pos(),
1309                                   Errors.UnreportedExceptionImplicitClose(thrownExit.thrown,
1310                                                                           ((JCVariableDecl)exit.tree).sym.name));
1311                     } else {
1312                         log.error(exit.tree.pos(),
1313                                   Errors.UnreportedExceptionNeedToCatchOrThrow(thrownExit.thrown));
1314                     }
1315                 } else {
1316                     Assert.check(log.hasErrorOn(exit.tree.pos()));
1317                 }
1318             }
1319         }
1320 
1321         /** Record that exception is potentially thrown and check that it
1322          *  is caught.
1323          */
1324         void markThrown(JCTree tree, Type exc) {
1325             if (!chk.isUnchecked(tree.pos(), exc)) {
1326                 if (!chk.isHandled(exc, caught)) {
1327                     pendingExits.append(new ThrownPendingExit(tree, exc));
1328                 }
1329                 thrown = chk.incl(exc, thrown);
1330             }
1331         }
1332 
1333     /*************************************************************************
1334      * Visitor methods for statements and definitions
1335      *************************************************************************/
1336 
1337         /* ------------ Visitor methods for various sorts of trees -------------*/
1338 
1339         public void visitClassDef(JCClassDecl tree) {
1340             if (tree.sym == null) return;
1341 
1342             JCClassDecl classDefPrev = classDef;
1343             List<Type> thrownPrev = thrown;
1344             List<Type> caughtPrev = caught;
1345             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
1346             Lint lintPrev = lint;
1347             boolean anonymousClass = tree.name == names.empty;
1348             pendingExits = new ListBuffer<>();
1349             if (!anonymousClass) {
1350                 caught = List.nil();
1351             }
1352             classDef = tree;
1353             thrown = List.nil();
1354             lint = lint.augment(tree.sym);
1355 
1356             try {
1357                 // process all the static initializers
1358                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1359                     if (!l.head.hasTag(METHODDEF) &&
1360                         (TreeInfo.flags(l.head) & STATIC) != 0) {
1361                         scan(l.head);
1362                         errorUncaught();
1363                     }
1364                 }
1365 
1366                 // add intersection of all throws clauses of initial constructors
1367                 // to set of caught exceptions, unless class is anonymous.
1368                 if (!anonymousClass) {
1369                     boolean firstConstructor = true;
1370                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1371                         if (TreeInfo.isInitialConstructor(l.head)) {
1372                             List<Type> mthrown =
1373                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
1374                             if (firstConstructor) {
1375                                 caught = mthrown;
1376                                 firstConstructor = false;
1377                             } else {
1378                                 caught = chk.intersect(mthrown, caught);
1379                             }
1380                         }
1381                     }
1382                 }
1383 
1384                 // process all the instance initializers
1385                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1386                     if (!l.head.hasTag(METHODDEF) &&
1387                         (TreeInfo.flags(l.head) & STATIC) == 0) {
1388                         scan(l.head);
1389                         errorUncaught();
1390                     }
1391                 }
1392 
1393                 // in an anonymous class, add the set of thrown exceptions to
1394                 // the throws clause of the synthetic constructor and propagate
1395                 // outwards.
1396                 // Changing the throws clause on the fly is okay here because
1397                 // the anonymous constructor can't be invoked anywhere else,
1398                 // and its type hasn't been cached.
1399                 if (anonymousClass) {
1400                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1401                         if (TreeInfo.isConstructor(l.head)) {
1402                             JCMethodDecl mdef = (JCMethodDecl)l.head;
1403                             scan(mdef);
1404                             mdef.thrown = make.Types(thrown);
1405                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
1406                         }
1407                     }
1408                     thrownPrev = chk.union(thrown, thrownPrev);
1409                 }
1410 
1411                 // process all the methods
1412                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1413                     if (anonymousClass && TreeInfo.isConstructor(l.head))
1414                         continue; // there can never be an uncaught exception.
1415                     if (l.head.hasTag(METHODDEF)) {
1416                         scan(l.head);
1417                         errorUncaught();
1418                     }
1419                 }
1420 
1421                 thrown = thrownPrev;
1422             } finally {
1423                 pendingExits = pendingExitsPrev;
1424                 caught = caughtPrev;
1425                 classDef = classDefPrev;
1426                 lint = lintPrev;
1427             }
1428         }
1429 
1430         public void visitMethodDef(JCMethodDecl tree) {
1431             if (tree.body == null) return;
1432 
1433             List<Type> caughtPrev = caught;
1434             List<Type> mthrown = tree.sym.type.getThrownTypes();
1435             Lint lintPrev = lint;
1436 
1437             lint = lint.augment(tree.sym);
1438 
1439             Assert.check(pendingExits.isEmpty());
1440 
1441             try {
1442                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1443                     JCVariableDecl def = l.head;
1444                     scan(def);
1445                 }
1446                 if (TreeInfo.isInitialConstructor(tree))
1447                     caught = chk.union(caught, mthrown);
1448                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
1449                     caught = mthrown;
1450                 // else we are in an instance initializer block;
1451                 // leave caught unchanged.
1452 
1453                 scan(tree.body);
1454 
1455                 List<PendingExit> exits = pendingExits.toList();
1456                 pendingExits = new ListBuffer<>();
1457                 while (exits.nonEmpty()) {
1458                     PendingExit exit = exits.head;
1459                     exits = exits.tail;
1460                     if (!(exit instanceof ThrownPendingExit)) {
1461                         Assert.check(exit.tree.hasTag(RETURN) ||
1462                                          log.hasErrorOn(exit.tree.pos()));
1463                     } else {
1464                         // uncaught throws will be reported later
1465                         pendingExits.append(exit);
1466                     }
1467                 }
1468             } finally {
1469                 caught = caughtPrev;
1470                 lint = lintPrev;
1471             }
1472         }
1473 
1474         public void visitVarDef(JCVariableDecl tree) {
1475             if (tree.init != null) {
1476                 Lint lintPrev = lint;
1477                 lint = lint.augment(tree.sym);
1478                 try{
1479                     scan(tree.init);
1480                 } finally {
1481                     lint = lintPrev;
1482                 }
1483             }
1484         }
1485 
1486         public void visitBlock(JCBlock tree) {
1487             scan(tree.stats);
1488         }
1489 
1490         public void visitDoLoop(JCDoWhileLoop tree) {
1491             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1492             pendingExits = new ListBuffer<>();
1493             scan(tree.body);
1494             resolveContinues(tree);
1495             scan(tree.cond);
1496             resolveBreaks(tree, prevPendingExits);
1497         }
1498 
1499         public void visitWhileLoop(JCWhileLoop tree) {
1500             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1501             pendingExits = new ListBuffer<>();
1502             scan(tree.cond);
1503             scan(tree.body);
1504             resolveContinues(tree);
1505             resolveBreaks(tree, prevPendingExits);
1506         }
1507 
1508         public void visitForLoop(JCForLoop tree) {
1509             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1510             scan(tree.init);
1511             pendingExits = new ListBuffer<>();
1512             if (tree.cond != null) {
1513                 scan(tree.cond);
1514             }
1515             scan(tree.body);
1516             resolveContinues(tree);
1517             scan(tree.step);
1518             resolveBreaks(tree, prevPendingExits);
1519         }
1520 
1521         public void visitForeachLoop(JCEnhancedForLoop tree) {
1522             visitVarDef(tree.var);
1523             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1524             scan(tree.expr);
1525             pendingExits = new ListBuffer<>();
1526             scan(tree.body);
1527             resolveContinues(tree);
1528             resolveBreaks(tree, prevPendingExits);
1529         }
1530 
1531         public void visitLabelled(JCLabeledStatement tree) {
1532             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1533             pendingExits = new ListBuffer<>();
1534             scan(tree.body);
1535             resolveBreaks(tree, prevPendingExits);
1536         }
1537 
1538         public void visitSwitch(JCSwitch tree) {
1539             handleSwitch(tree, tree.selector, tree.cases);
1540         }
1541 
1542         @Override
1543         public void visitSwitchExpression(JCSwitchExpression tree) {
1544             handleSwitch(tree, tree.selector, tree.cases);
1545         }
1546 
1547         private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
1548             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1549             pendingExits = new ListBuffer<>();
1550             scan(selector);
1551             for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
1552                 JCCase c = l.head;
1553                 scan(c.labels);
1554                 scan(c.stats);
1555             }
1556             if (tree.hasTag(SWITCH_EXPRESSION)) {
1557                 resolveYields(tree, prevPendingExits);
1558             } else {
1559                 resolveBreaks(tree, prevPendingExits);
1560             }
1561         }
1562 
1563         public void visitTry(JCTry tree) {
1564             List<Type> caughtPrev = caught;
1565             List<Type> thrownPrev = thrown;
1566             thrown = List.nil();
1567             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1568                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1569                         ((JCTypeUnion)l.head.param.vartype).alternatives :
1570                         List.of(l.head.param.vartype);
1571                 for (JCExpression ct : subClauses) {
1572                     caught = chk.incl(ct.type, caught);
1573                 }
1574             }
1575 
1576             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1577             pendingExits = new ListBuffer<>();
1578             for (JCTree resource : tree.resources) {
1579                 if (resource instanceof JCVariableDecl variableDecl) {
1580                     visitVarDef(variableDecl);
1581                 } else if (resource instanceof JCExpression expression) {
1582                     scan(expression);
1583                 } else {
1584                     throw new AssertionError(tree);  // parser error
1585                 }
1586             }
1587             for (JCTree resource : tree.resources) {
1588                 List<Type> closeableSupertypes = resource.type.isCompound() ?
1589                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1590                     List.of(resource.type);
1591                 for (Type sup : closeableSupertypes) {
1592                     if (types.asSuper(sup.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) != null) {
1593                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1594                                 attrEnv,
1595                                 types.skipTypeVars(sup, false),
1596                                 names.close,
1597                                 List.nil(),
1598                                 List.nil());
1599                         Type mt = types.memberType(resource.type, closeMethod);
1600                         if (closeMethod.kind == MTH) {
1601                             for (Type t : mt.getThrownTypes()) {
1602                                 markThrown(resource, t);
1603                             }
1604                         }
1605                     }
1606                 }
1607             }
1608             scan(tree.body);
1609             List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1610             thrown = thrownPrev;
1611             caught = caughtPrev;
1612 
1613             List<Type> caughtInTry = List.nil();
1614             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1615                 JCVariableDecl param = l.head.param;
1616                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1617                         ((JCTypeUnion)l.head.param.vartype).alternatives :
1618                         List.of(l.head.param.vartype);
1619                 List<Type> ctypes = List.nil();
1620                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
1621                 for (JCExpression ct : subClauses) {
1622                     Type exc = ct.type;
1623                     if (exc != syms.unknownType) {
1624                         ctypes = ctypes.append(exc);
1625                         if (types.isSameType(exc, syms.objectType))
1626                             continue;
1627                         var pos = subClauses.size() > 1 ? ct.pos() : l.head.pos();
1628                         checkCaughtType(pos, exc, thrownInTry, caughtInTry);
1629                         caughtInTry = chk.incl(exc, caughtInTry);
1630                     }
1631                 }
1632                 scan(param);
1633                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
1634                 scan(l.head.body);
1635                 preciseRethrowTypes.remove(param.sym);
1636             }
1637             if (tree.finalizer != null) {
1638                 List<Type> savedThrown = thrown;
1639                 thrown = List.nil();
1640                 ListBuffer<PendingExit> exits = pendingExits;
1641                 pendingExits = prevPendingExits;
1642                 scan(tree.finalizer);
1643                 if (!tree.finallyCanCompleteNormally) {
1644                     // discard exits and exceptions from try and finally
1645                     thrown = chk.union(thrown, thrownPrev);
1646                 } else {
1647                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1648                     thrown = chk.union(thrown, savedThrown);
1649                     // FIX: this doesn't preserve source order of exits in catch
1650                     // versus finally!
1651                     while (exits.nonEmpty()) {
1652                         pendingExits.append(exits.next());
1653                     }
1654                 }
1655             } else {
1656                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1657                 ListBuffer<PendingExit> exits = pendingExits;
1658                 pendingExits = prevPendingExits;
1659                 while (exits.nonEmpty()) pendingExits.append(exits.next());
1660             }
1661         }
1662 
1663         @Override
1664         public void visitIf(JCIf tree) {
1665             scan(tree.cond);
1666             scan(tree.thenpart);
1667             if (tree.elsepart != null) {
1668                 scan(tree.elsepart);
1669             }
1670         }
1671 
1672         @Override
1673         public void visitStringTemplate(JCStringTemplate tree) {
1674             JCExpression processor = tree.processor;
1675 
1676             if (processor != null) {
1677                 scan(processor);
1678                 Type interfaceType = types.asSuper(processor.type, syms.processorType.tsym);
1679 
1680                 if (interfaceType != null) {
1681                     List<Type> typeArguments = interfaceType.getTypeArguments();
1682 
1683                     if (typeArguments.size() == 2) {
1684                         Type throwType = typeArguments.tail.head;
1685 
1686                         if (throwType != null) {
1687                             markThrown(tree, throwType);
1688                         }
1689                     }
1690                 }
1691             }
1692 
1693             scan(tree.expressions);
1694         }
1695 
1696         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
1697             if (chk.subset(exc, caughtInTry)) {
1698                 log.error(pos, Errors.ExceptAlreadyCaught(exc));
1699             } else if (!chk.isUnchecked(pos, exc) &&
1700                     !isExceptionOrThrowable(exc) &&
1701                     !chk.intersects(exc, thrownInTry)) {
1702                 log.error(pos, Errors.ExceptNeverThrownInTry(exc));
1703             } else {
1704                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
1705                 // 'catchableThrownTypes' cannot possibly be empty - if 'exc' was an
1706                 // unchecked exception, the result list would not be empty, as the augmented
1707                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
1708                 // exception, that would have been covered in the branch above
1709                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
1710                         !isExceptionOrThrowable(exc)) {
1711                     Warning key = catchableThrownTypes.length() == 1 ?
1712                             Warnings.UnreachableCatch(catchableThrownTypes) :
1713                             Warnings.UnreachableCatch1(catchableThrownTypes);
1714                     log.warning(pos, key);
1715                 }
1716             }
1717         }
1718         //where
1719             private boolean isExceptionOrThrowable(Type exc) {
1720                 return exc.tsym == syms.throwableType.tsym ||
1721                     exc.tsym == syms.exceptionType.tsym;
1722             }
1723 
1724         public void visitBreak(JCBreak tree) {
1725             recordExit(new PendingExit(tree));
1726         }
1727 
1728         public void visitYield(JCYield tree) {
1729             scan(tree.value);
1730             recordExit(new PendingExit(tree));
1731         }
1732 
1733         public void visitContinue(JCContinue tree) {
1734             recordExit(new PendingExit(tree));
1735         }
1736 
1737         public void visitReturn(JCReturn tree) {
1738             scan(tree.expr);
1739             recordExit(new PendingExit(tree));
1740         }
1741 
1742         public void visitThrow(JCThrow tree) {
1743             scan(tree.expr);
1744             Symbol sym = TreeInfo.symbol(tree.expr);
1745             if (sym != null &&
1746                 sym.kind == VAR &&
1747                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
1748                 preciseRethrowTypes.get(sym) != null) {
1749                 for (Type t : preciseRethrowTypes.get(sym)) {
1750                     markThrown(tree, t);
1751                 }
1752             }
1753             else {
1754                 markThrown(tree, tree.expr.type);
1755             }
1756             markDead();
1757         }
1758 
1759         public void visitApply(JCMethodInvocation tree) {
1760             scan(tree.meth);
1761             scan(tree.args);
1762             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
1763                 markThrown(tree, l.head);
1764         }
1765 
1766         public void visitNewClass(JCNewClass tree) {
1767             scan(tree.encl);
1768             scan(tree.args);
1769            // scan(tree.def);
1770             for (List<Type> l = tree.constructorType.getThrownTypes();
1771                  l.nonEmpty();
1772                  l = l.tail) {
1773                 markThrown(tree, l.head);
1774             }
1775             List<Type> caughtPrev = caught;
1776             try {
1777                 // If the new class expression defines an anonymous class,
1778                 // analysis of the anonymous constructor may encounter thrown
1779                 // types which are unsubstituted type variables.
1780                 // However, since the constructor's actual thrown types have
1781                 // already been marked as thrown, it is safe to simply include
1782                 // each of the constructor's formal thrown types in the set of
1783                 // 'caught/declared to be thrown' types, for the duration of
1784                 // the class def analysis.
1785                 if (tree.def != null)
1786                     for (List<Type> l = tree.constructor.type.getThrownTypes();
1787                          l.nonEmpty();
1788                          l = l.tail) {
1789                         caught = chk.incl(l.head, caught);
1790                     }
1791                 scan(tree.def);
1792             }
1793             finally {
1794                 caught = caughtPrev;
1795             }
1796         }
1797 
1798         @Override
1799         public void visitLambda(JCLambda tree) {
1800             if (tree.type != null &&
1801                     tree.type.isErroneous()) {
1802                 return;
1803             }
1804             List<Type> prevCaught = caught;
1805             List<Type> prevThrown = thrown;
1806             ListBuffer<PendingExit> prevPending = pendingExits;
1807             try {
1808                 pendingExits = new ListBuffer<>();
1809                 caught = tree.getDescriptorType(types).getThrownTypes();
1810                 thrown = List.nil();
1811                 scan(tree.body);
1812                 List<PendingExit> exits = pendingExits.toList();
1813                 pendingExits = new ListBuffer<>();
1814                 while (exits.nonEmpty()) {
1815                     PendingExit exit = exits.head;
1816                     exits = exits.tail;
1817                     if (!(exit instanceof ThrownPendingExit)) {
1818                         Assert.check(exit.tree.hasTag(RETURN) ||
1819                                         log.hasErrorOn(exit.tree.pos()));
1820                     } else {
1821                         // uncaught throws will be reported later
1822                         pendingExits.append(exit);
1823                     }
1824                 }
1825 
1826                 errorUncaught();
1827             } finally {
1828                 pendingExits = prevPending;
1829                 caught = prevCaught;
1830                 thrown = prevThrown;
1831             }
1832         }
1833 
1834         public void visitModuleDef(JCModuleDecl tree) {
1835             // Do nothing for modules
1836         }
1837 
1838     /**************************************************************************
1839      * main method
1840      *************************************************************************/
1841 
1842         /** Perform definite assignment/unassignment analysis on a tree.
1843          */
1844         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
1845             analyzeTree(env, env.tree, make);
1846         }
1847         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
1848             try {
1849                 attrEnv = env;
1850                 Flow.this.make = make;
1851                 pendingExits = new ListBuffer<>();
1852                 preciseRethrowTypes = new HashMap<>();
1853                 this.thrown = this.caught = null;
1854                 this.classDef = null;
1855                 scan(tree);
1856             } finally {
1857                 pendingExits = null;
1858                 Flow.this.make = null;
1859                 this.thrown = this.caught = null;
1860                 this.classDef = null;
1861             }
1862         }
1863     }
1864 
1865     /**
1866      * Specialized pass that performs reachability analysis on a lambda
1867      */
1868     class LambdaAliveAnalyzer extends AliveAnalyzer {
1869 
1870         boolean inLambda;
1871 
1872         @Override
1873         public void visitReturn(JCReturn tree) {
1874             //ignore lambda return expression (which might not even be attributed)
1875             recordExit(new PendingExit(tree));
1876         }
1877 
1878         @Override
1879         public void visitLambda(JCLambda tree) {
1880             if (inLambda || tree.getBodyKind() == BodyKind.EXPRESSION) {
1881                 return;
1882             }
1883             inLambda = true;
1884             try {
1885                 super.visitLambda(tree);
1886             } finally {
1887                 inLambda = false;
1888             }
1889         }
1890 
1891         @Override
1892         public void visitClassDef(JCClassDecl tree) {
1893             //skip
1894         }
1895     }
1896 
1897     /**
1898      * Determine if alive after the given tree.
1899      */
1900     class SnippetAliveAnalyzer extends AliveAnalyzer {
1901         @Override
1902         public void visitClassDef(JCClassDecl tree) {
1903             //skip
1904         }
1905         @Override
1906         public void visitLambda(JCLambda tree) {
1907             //skip
1908         }
1909         public boolean isAlive() {
1910             return super.alive != Liveness.DEAD;
1911         }
1912     }
1913 
1914     class SnippetBreakAnalyzer extends AliveAnalyzer {
1915         private final Set<JCTree> seenTrees = new HashSet<>();
1916         private boolean breaksOut;
1917 
1918         public SnippetBreakAnalyzer() {
1919         }
1920 
1921         @Override
1922         public void visitLabelled(JCTree.JCLabeledStatement tree) {
1923             seenTrees.add(tree);
1924             super.visitLabelled(tree);
1925         }
1926 
1927         @Override
1928         public void visitWhileLoop(JCTree.JCWhileLoop tree) {
1929             seenTrees.add(tree);
1930             super.visitWhileLoop(tree);
1931         }
1932 
1933         @Override
1934         public void visitForLoop(JCTree.JCForLoop tree) {
1935             seenTrees.add(tree);
1936             super.visitForLoop(tree);
1937         }
1938 
1939         @Override
1940         public void visitForeachLoop(JCTree.JCEnhancedForLoop tree) {
1941             seenTrees.add(tree);
1942             super.visitForeachLoop(tree);
1943         }
1944 
1945         @Override
1946         public void visitDoLoop(JCTree.JCDoWhileLoop tree) {
1947             seenTrees.add(tree);
1948             super.visitDoLoop(tree);
1949         }
1950 
1951         @Override
1952         public void visitBreak(JCBreak tree) {
1953             breaksOut |= (super.alive == Liveness.ALIVE &&
1954                           !seenTrees.contains(tree.target));
1955             super.visitBreak(tree);
1956         }
1957 
1958         public boolean breaksOut() {
1959             return breaksOut;
1960         }
1961     }
1962 
1963     /**
1964      * Specialized pass that performs DA/DU on a lambda
1965      */
1966     class LambdaAssignAnalyzer extends AssignAnalyzer {
1967         WriteableScope enclosedSymbols;
1968         boolean inLambda;
1969 
1970         LambdaAssignAnalyzer(Env<AttrContext> env) {
1971             enclosedSymbols = WriteableScope.create(env.enclClass.sym);
1972         }
1973 
1974         @Override
1975         public void visitLambda(JCLambda tree) {
1976             if (inLambda) {
1977                 return;
1978             }
1979             inLambda = true;
1980             try {
1981                 super.visitLambda(tree);
1982             } finally {
1983                 inLambda = false;
1984             }
1985         }
1986 
1987         @Override
1988         public void visitVarDef(JCVariableDecl tree) {
1989             enclosedSymbols.enter(tree.sym);
1990             super.visitVarDef(tree);
1991         }
1992         @Override
1993         protected boolean trackable(VarSymbol sym) {
1994             return enclosedSymbols.includes(sym) &&
1995                    sym.owner.kind == MTH;
1996         }
1997 
1998         @Override
1999         public void visitClassDef(JCClassDecl tree) {
2000             //skip
2001         }
2002     }
2003 
2004     /**
2005      * Specialized pass that performs inference of thrown types for lambdas.
2006      */
2007     class LambdaFlowAnalyzer extends FlowAnalyzer {
2008         List<Type> inferredThrownTypes;
2009         boolean inLambda;
2010         @Override
2011         public void visitLambda(JCLambda tree) {
2012             if ((tree.type != null &&
2013                     tree.type.isErroneous()) || inLambda) {
2014                 return;
2015             }
2016             List<Type> prevCaught = caught;
2017             List<Type> prevThrown = thrown;
2018             ListBuffer<PendingExit> prevPending = pendingExits;
2019             inLambda = true;
2020             try {
2021                 pendingExits = new ListBuffer<>();
2022                 caught = List.of(syms.throwableType);
2023                 thrown = List.nil();
2024                 scan(tree.body);
2025                 inferredThrownTypes = thrown;
2026             } finally {
2027                 pendingExits = prevPending;
2028                 caught = prevCaught;
2029                 thrown = prevThrown;
2030                 inLambda = false;
2031             }
2032         }
2033         @Override
2034         public void visitClassDef(JCClassDecl tree) {
2035             //skip
2036         }
2037     }
2038 
2039     /** Enum to model whether constructors allowed to "leak" this reference before
2040         all instance fields are DA.
2041      */
2042     enum ThisExposability {
2043         ALLOWED,     // identity Object classes - NOP
2044         BANNED,      // primitive/value classes - Error
2045     }
2046 
2047     /**
2048      * This pass implements (i) definite assignment analysis, which ensures that
2049      * each variable is assigned when used and (ii) definite unassignment analysis,
2050      * which ensures that no final variable is assigned more than once. This visitor
2051      * depends on the results of the liveliness analyzer. This pass is also used to mark
2052      * effectively-final local variables/parameters.
2053      */
2054 
2055     public class AssignAnalyzer extends BaseAnalyzer {
2056 
2057         /** The set of definitely assigned variables.
2058          */
2059         final Bits inits;
2060 
2061         /** The set of definitely unassigned variables.
2062          */
2063         final Bits uninits;
2064 
2065         /** The set of variables that are definitely unassigned everywhere
2066          *  in current try block. This variable is maintained lazily; it is
2067          *  updated only when something gets removed from uninits,
2068          *  typically by being assigned in reachable code.  To obtain the
2069          *  correct set of variables which are definitely unassigned
2070          *  anywhere in current try block, intersect uninitsTry and
2071          *  uninits.
2072          */
2073         final Bits uninitsTry;
2074 
2075         /** When analyzing a condition, inits and uninits are null.
2076          *  Instead we have:
2077          */
2078         final Bits initsWhenTrue;
2079         final Bits initsWhenFalse;
2080         final Bits uninitsWhenTrue;
2081         final Bits uninitsWhenFalse;
2082 
2083         /** A mapping from addresses to variable symbols.
2084          */
2085         protected JCVariableDecl[] vardecls;
2086 
2087         /** The current class being defined.
2088          */
2089         JCClassDecl classDef;
2090 
2091         /** The first variable sequence number in this class definition.
2092          */
2093         int firstadr;
2094 
2095         /** The next available variable sequence number.
2096          */
2097         protected int nextadr;
2098 
2099         /** The first variable sequence number in a block that can return.
2100          */
2101         protected int returnadr;
2102 
2103         /** The list of unreferenced automatic resources.
2104          */
2105         WriteableScope unrefdResources;
2106 
2107         /** Modified when processing a loop body the second time for DU analysis. */
2108         FlowKind flowKind = FlowKind.NORMAL;
2109 
2110         /** The starting position of the analyzed tree */
2111         int startPos;
2112 
2113         public class AssignPendingExit extends BaseAnalyzer.PendingExit {
2114 
2115             final Bits inits;
2116             final Bits uninits;
2117             final Bits exit_inits = new Bits(true);
2118             final Bits exit_uninits = new Bits(true);
2119 
2120             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2121                 super(tree);
2122                 this.inits = inits;
2123                 this.uninits = uninits;
2124                 this.exit_inits.assign(inits);
2125                 this.exit_uninits.assign(uninits);
2126             }
2127 
2128             @Override
2129             public void resolveJump() {
2130                 inits.andSet(exit_inits);
2131                 uninits.andSet(exit_uninits);
2132             }
2133         }
2134 
2135         // Are constructors allowed to leak this reference ?
2136         ThisExposability thisExposability = ALLOWED;
2137 
2138         public AssignAnalyzer() {
2139             this.inits = new Bits();
2140             uninits = new Bits();
2141             uninitsTry = new Bits();
2142             initsWhenTrue = new Bits(true);
2143             initsWhenFalse = new Bits(true);
2144             uninitsWhenTrue = new Bits(true);
2145             uninitsWhenFalse = new Bits(true);
2146         }
2147 
2148         private boolean isInitialConstructor = false;
2149 
2150         @Override
2151         protected void markDead() {
2152             if (!isInitialConstructor) {
2153                 inits.inclRange(returnadr, nextadr);
2154             } else {
2155                 for (int address = returnadr; address < nextadr; address++) {
2156                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
2157                         inits.incl(address);
2158                     }
2159                 }
2160             }
2161             uninits.inclRange(returnadr, nextadr);
2162         }
2163 
2164         /*-------------- Processing variables ----------------------*/
2165 
2166         /** Do we need to track init/uninit state of this symbol?
2167          *  I.e. is symbol either a local or a blank final variable?
2168          */
2169         protected boolean trackable(VarSymbol sym) {
2170             return
2171                 sym.pos >= startPos &&
2172                 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2173                 isFinalUninitializedField(sym)));
2174         }
2175 
2176         boolean isFinalUninitializedField(VarSymbol sym) {
2177             return sym.owner.kind == TYP &&
2178                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
2179                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2180         }
2181 
2182         boolean isFinalUninitializedStaticField(VarSymbol sym) {
2183             return isFinalUninitializedField(sym) && sym.isStatic();
2184         }
2185 
2186         /** Initialize new trackable variable by setting its address field
2187          *  to the next available sequence number and entering it under that
2188          *  index into the vars array.
2189          */
2190         void newVar(JCVariableDecl varDecl) {
2191             VarSymbol sym = varDecl.sym;
2192             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2193             if ((sym.flags() & FINAL) == 0) {
2194                 sym.flags_field |= EFFECTIVELY_FINAL;
2195             }
2196             sym.adr = nextadr;
2197             vardecls[nextadr] = varDecl;
2198             inits.excl(nextadr);
2199             uninits.incl(nextadr);
2200             nextadr++;
2201         }
2202 
2203         /** Record an initialization of a trackable variable.
2204          */
2205         void letInit(DiagnosticPosition pos, VarSymbol sym) {
2206             if (sym.adr >= firstadr && trackable(sym)) {
2207                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
2208                     if (!uninits.isMember(sym.adr)) {
2209                         //assignment targeting an effectively final variable
2210                         //makes the variable lose its status of effectively final
2211                         //if the variable is _not_ definitively unassigned
2212                         sym.flags_field &= ~EFFECTIVELY_FINAL;
2213                     } else {
2214                         uninit(sym);
2215                     }
2216                 }
2217                 else if ((sym.flags() & FINAL) != 0) {
2218                     if ((sym.flags() & PARAMETER) != 0) {
2219                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
2220                             log.error(pos, Errors.MulticatchParameterMayNotBeAssigned(sym));
2221                         }
2222                         else {
2223                             log.error(pos,
2224                                       Errors.FinalParameterMayNotBeAssigned(sym));
2225                         }
2226                     } else if (!uninits.isMember(sym.adr)) {
2227                         log.error(pos, diags.errorKey(flowKind.errKey, sym));
2228                     } else {
2229                         uninit(sym);
2230                     }
2231                 }
2232                 inits.incl(sym.adr);
2233             } else if ((sym.flags() & FINAL) != 0) {
2234                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2235             }
2236         }
2237         //where
2238             void uninit(VarSymbol sym) {
2239                 if (!inits.isMember(sym.adr)) {
2240                     // reachable assignment
2241                     uninits.excl(sym.adr);
2242                     uninitsTry.excl(sym.adr);
2243                 } else {
2244                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2245                     uninits.excl(sym.adr);
2246                 }
2247             }
2248 
2249         /** If tree is either a simple name or of the form this.name or
2250          *  C.this.name, and tree represents a trackable variable,
2251          *  record an initialization of the variable.
2252          */
2253         void letInit(JCTree tree) {
2254             tree = TreeInfo.skipParens(tree);
2255             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2256                 Symbol sym = TreeInfo.symbol(tree);
2257                 if (sym.kind == VAR) {
2258                     letInit(tree.pos(), (VarSymbol)sym);
2259                 }
2260             }
2261         }
2262 
2263         void checkEmbryonicThisExposure(JCTree node) {
2264             if (this.thisExposability == ALLOWED || classDef == null)
2265                 return;
2266 
2267             // Note: for non-initial constructors, firstadr is post all instance fields.
2268             for (int i = firstadr; i < nextadr; i++) {
2269                 VarSymbol sym = vardecls[i].sym;
2270                 if (sym.owner != classDef.sym)
2271                     continue;
2272                 if ((sym.flags() & (FINAL | HASINIT | STATIC | PARAMETER)) != FINAL)
2273                     continue;
2274                 if (sym.pos < startPos || sym.adr < firstadr)
2275                     continue;
2276                 if (!inits.isMember(sym.adr)) {
2277                     if (this.thisExposability == BANNED) {
2278                         log.error(node, Errors.ThisExposedPrematurely);
2279                     }
2280                     return; // don't flog a dead horse.
2281                 }
2282             }
2283         }
2284 
2285         /** Check that trackable variable is initialized.
2286          */
2287         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2288             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2289         }
2290 
2291         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2292             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2293                 trackable(sym) &&
2294                 !inits.isMember(sym.adr) &&
2295                 (sym.flags_field & CLASH) == 0) {
2296                     log.error(pos, errkey);
2297                 inits.incl(sym.adr);
2298             }
2299         }
2300 
2301         /** Utility method to reset several Bits instances.
2302          */
2303         private void resetBits(Bits... bits) {
2304             for (Bits b : bits) {
2305                 b.reset();
2306             }
2307         }
2308 
2309         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2310          */
2311         void split(boolean setToNull) {
2312             initsWhenFalse.assign(inits);
2313             uninitsWhenFalse.assign(uninits);
2314             initsWhenTrue.assign(inits);
2315             uninitsWhenTrue.assign(uninits);
2316             if (setToNull) {
2317                 resetBits(inits, uninits);
2318             }
2319         }
2320 
2321         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
2322          */
2323         protected void merge() {
2324             inits.assign(initsWhenFalse.andSet(initsWhenTrue));
2325             uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
2326         }
2327 
2328     /* ************************************************************************
2329      * Visitor methods for statements and definitions
2330      *************************************************************************/
2331 
2332         /** Analyze an expression. Make sure to set (un)inits rather than
2333          *  (un)initsWhenTrue(WhenFalse) on exit.
2334          */
2335         void scanExpr(JCTree tree) {
2336             if (tree != null) {
2337                 scan(tree);
2338                 if (inits.isReset()) {
2339                     merge();
2340                 }
2341             }
2342         }
2343 
2344         /** Analyze a list of expressions.
2345          */
2346         void scanExprs(List<? extends JCExpression> trees) {
2347             if (trees != null)
2348                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
2349                     scanExpr(l.head);
2350         }
2351 
2352         void scanPattern(JCTree tree) {
2353             scan(tree);
2354         }
2355 
2356         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
2357          *  rather than (un)inits on exit.
2358          */
2359         void scanCond(JCTree tree) {
2360             if (tree.type.isFalse()) {
2361                 if (inits.isReset()) merge();
2362                 initsWhenTrue.assign(inits);
2363                 initsWhenTrue.inclRange(firstadr, nextadr);
2364                 uninitsWhenTrue.assign(uninits);
2365                 uninitsWhenTrue.inclRange(firstadr, nextadr);
2366                 initsWhenFalse.assign(inits);
2367                 uninitsWhenFalse.assign(uninits);
2368             } else if (tree.type.isTrue()) {
2369                 if (inits.isReset()) merge();
2370                 initsWhenFalse.assign(inits);
2371                 initsWhenFalse.inclRange(firstadr, nextadr);
2372                 uninitsWhenFalse.assign(uninits);
2373                 uninitsWhenFalse.inclRange(firstadr, nextadr);
2374                 initsWhenTrue.assign(inits);
2375                 uninitsWhenTrue.assign(uninits);
2376             } else {
2377                 scan(tree);
2378                 if (!inits.isReset())
2379                     split(tree.type != syms.unknownType);
2380             }
2381             if (tree.type != syms.unknownType) {
2382                 resetBits(inits, uninits);
2383             }
2384         }
2385 
2386         /* ------------ Visitor methods for various sorts of trees -------------*/
2387 
2388         public void visitClassDef(JCClassDecl tree) {
2389             if (tree.sym == null) {
2390                 return;
2391             }
2392 
2393             Lint lintPrev = lint;
2394             lint = lint.augment(tree.sym);
2395             try {
2396                 JCClassDecl classDefPrev = classDef;
2397                 int firstadrPrev = firstadr;
2398                 int nextadrPrev = nextadr;
2399                 ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
2400 
2401                 pendingExits = new ListBuffer<>();
2402                 if (tree.name != names.empty) {
2403                     firstadr = nextadr;
2404                 }
2405                 classDef = tree;
2406                 try {
2407                     // define all the static fields
2408                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2409                         if (l.head.hasTag(VARDEF)) {
2410                             JCVariableDecl def = (JCVariableDecl)l.head;
2411                             if ((def.mods.flags & STATIC) != 0) {
2412                                 VarSymbol sym = def.sym;
2413                                 if (trackable(sym)) {
2414                                     newVar(def);
2415                                 }
2416                             }
2417                         }
2418                     }
2419 
2420                     // process all the static initializers
2421                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2422                         if (!l.head.hasTag(METHODDEF) &&
2423                             (TreeInfo.flags(l.head) & STATIC) != 0) {
2424                             scan(l.head);
2425                             clearPendingExits(false);
2426                         }
2427                     }
2428 
2429                     // verify all static final fields got initailized
2430                     for (int i = firstadr; i < nextadr; i++) {
2431                         JCVariableDecl vardecl = vardecls[i];
2432                         VarSymbol var = vardecl.sym;
2433                         if (var.owner == classDef.sym && var.isStatic()) {
2434                             checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2435                         }
2436                     }
2437 
2438                     // define all the instance fields
2439                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2440                         if (l.head.hasTag(VARDEF)) {
2441                             JCVariableDecl def = (JCVariableDecl)l.head;
2442                             if ((def.mods.flags & STATIC) == 0) {
2443                                 VarSymbol sym = def.sym;
2444                                 if (trackable(sym)) {
2445                                     newVar(def);
2446                                 }
2447                             }
2448                         }
2449                     }
2450 
2451                     // process all the instance initializers
2452                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2453                         if (!l.head.hasTag(METHODDEF) &&
2454                             (TreeInfo.flags(l.head) & STATIC) == 0) {
2455                             scan(l.head);
2456                             clearPendingExits(false);
2457                         }
2458                     }
2459 
2460                     // process all the methods
2461                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2462                         if (l.head.hasTag(METHODDEF)) {
2463                             scan(l.head);
2464                         }
2465                     }
2466                 } finally {
2467                     pendingExits = pendingExitsPrev;
2468                     nextadr = nextadrPrev;
2469                     firstadr = firstadrPrev;
2470                     classDef = classDefPrev;
2471                 }
2472             } finally {
2473                 lint = lintPrev;
2474             }
2475         }
2476 
2477         public void visitMethodDef(JCMethodDecl tree) {
2478             if (tree.body == null) {
2479                 return;
2480             }
2481 
2482             /*  MemberEnter can generate synthetic methods ignore them
2483              */
2484             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2485                 return;
2486             }
2487 
2488             Lint lintPrev = lint;
2489             lint = lint.augment(tree.sym);
2490             ThisExposability priorThisExposability = this.thisExposability;
2491             try {
2492                 final Bits initsPrev = new Bits(inits);
2493                 final Bits uninitsPrev = new Bits(uninits);
2494                 int nextadrPrev = nextadr;
2495                 int firstadrPrev = firstadr;
2496                 int returnadrPrev = returnadr;
2497 
2498                 Assert.check(pendingExits.isEmpty());
2499                 boolean lastInitialConstructor = isInitialConstructor;
2500                 try {
2501                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2502 
2503                     if (!isInitialConstructor) {
2504                         firstadr = nextadr;
2505                         this.thisExposability = ALLOWED;
2506                     } else {
2507                         if (tree.sym.owner.type.isValueClass())
2508                             this.thisExposability = BANNED;
2509                         else
2510                             this.thisExposability = ALLOWED;
2511                     }
2512                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2513                         JCVariableDecl def = l.head;
2514                         scan(def);
2515                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2516                         /*  If we are executing the code from Gen, then there can be
2517                          *  synthetic or mandated variables, ignore them.
2518                          */
2519                         initParam(def);
2520                     }
2521                     // else we are in an instance initializer block;
2522                     // leave caught unchanged.
2523                     scan(tree.body);
2524 
2525                     boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2526                             (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2527                     if (isInitialConstructor) {
2528                         boolean isSynthesized = (tree.sym.flags() &
2529                                                  GENERATEDCONSTR) != 0;
2530                         for (int i = firstadr; i < nextadr; i++) {
2531                             JCVariableDecl vardecl = vardecls[i];
2532                             VarSymbol var = vardecl.sym;
2533                             if (var.owner == classDef.sym && !var.isStatic()) {
2534                                 // choose the diagnostic position based on whether
2535                                 // the ctor is default(synthesized) or not
2536                                 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2537                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2538                                             var, Errors.VarNotInitializedInDefaultConstructor(var));
2539                                 } else if (isCompactOrGeneratedRecordConstructor) {
2540                                     boolean isInstanceRecordField = var.enclClass().isRecord() &&
2541                                             (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2542                                             var.owner.kind == TYP;
2543                                     if (isInstanceRecordField) {
2544                                         boolean notInitialized = !inits.isMember(var.adr);
2545                                         if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2546                                         /*  this way we indicate Lower that it should generate an initialization for this field
2547                                          *  in the compact constructor
2548                                          */
2549                                             var.flags_field |= UNINITIALIZED_FIELD;
2550                                         } else {
2551                                             checkInit(TreeInfo.diagEndPos(tree.body), var);
2552                                         }
2553                                     } else {
2554                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2555                                     }
2556                                 } else {
2557                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2558                                 }
2559                             }
2560                         }
2561                     }
2562                     clearPendingExits(true);
2563                 } finally {
2564                     inits.assign(initsPrev);
2565                     uninits.assign(uninitsPrev);
2566                     nextadr = nextadrPrev;
2567                     firstadr = firstadrPrev;
2568                     returnadr = returnadrPrev;
2569                     isInitialConstructor = lastInitialConstructor;
2570                 }
2571             } finally {
2572                 lint = lintPrev;
2573                 this.thisExposability = priorThisExposability;
2574             }
2575         }
2576 
2577         private void clearPendingExits(boolean inMethod) {
2578             List<PendingExit> exits = pendingExits.toList();
2579             pendingExits = new ListBuffer<>();
2580             while (exits.nonEmpty()) {
2581                 PendingExit exit = exits.head;
2582                 exits = exits.tail;
2583                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2584                                  log.hasErrorOn(exit.tree.pos()),
2585                              exit.tree);
2586                 if (inMethod && isInitialConstructor) {
2587                     Assert.check(exit instanceof AssignPendingExit);
2588                     inits.assign(((AssignPendingExit) exit).exit_inits);
2589                     for (int i = firstadr; i < nextadr; i++) {
2590                         checkInit(exit.tree.pos(), vardecls[i].sym);
2591                     }
2592                 }
2593             }
2594         }
2595         protected void initParam(JCVariableDecl def) {
2596             inits.incl(def.sym.adr);
2597             uninits.excl(def.sym.adr);
2598         }
2599 
2600         public void visitVarDef(JCVariableDecl tree) {
2601             Lint lintPrev = lint;
2602             lint = lint.augment(tree.sym);
2603             try{
2604                 boolean track = trackable(tree.sym);
2605                 if (track && (tree.sym.owner.kind == MTH || tree.sym.owner.kind == VAR)) {
2606                     newVar(tree);
2607                 }
2608                 if (tree.init != null) {
2609                     scanExpr(tree.init);
2610                     if (track) {
2611                         letInit(tree.pos(), tree.sym);
2612                     }
2613                 }
2614             } finally {
2615                 lint = lintPrev;
2616             }
2617         }
2618 
2619         public void visitBlock(JCBlock tree) {
2620             int nextadrPrev = nextadr;
2621             scan(tree.stats);
2622             nextadr = nextadrPrev;
2623         }
2624 
2625         public void visitDoLoop(JCDoWhileLoop tree) {
2626             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2627             FlowKind prevFlowKind = flowKind;
2628             flowKind = FlowKind.NORMAL;
2629             final Bits initsSkip = new Bits(true);
2630             final Bits uninitsSkip = new Bits(true);
2631             pendingExits = new ListBuffer<>();
2632             int prevErrors = log.nerrors;
2633             do {
2634                 final Bits uninitsEntry = new Bits(uninits);
2635                 uninitsEntry.excludeFrom(nextadr);
2636                 scan(tree.body);
2637                 resolveContinues(tree);
2638                 scanCond(tree.cond);
2639                 if (!flowKind.isFinal()) {
2640                     initsSkip.assign(initsWhenFalse);
2641                     uninitsSkip.assign(uninitsWhenFalse);
2642                 }
2643                 if (log.nerrors !=  prevErrors ||
2644                     flowKind.isFinal() ||
2645                     new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
2646                     break;
2647                 inits.assign(initsWhenTrue);
2648                 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
2649                 flowKind = FlowKind.SPECULATIVE_LOOP;
2650             } while (true);
2651             flowKind = prevFlowKind;
2652             inits.assign(initsSkip);
2653             uninits.assign(uninitsSkip);
2654             resolveBreaks(tree, prevPendingExits);
2655         }
2656 
2657         public void visitWhileLoop(JCWhileLoop tree) {
2658             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2659             FlowKind prevFlowKind = flowKind;
2660             flowKind = FlowKind.NORMAL;
2661             final Bits initsSkip = new Bits(true);
2662             final Bits uninitsSkip = new Bits(true);
2663             pendingExits = new ListBuffer<>();
2664             int prevErrors = log.nerrors;
2665             final Bits uninitsEntry = new Bits(uninits);
2666             uninitsEntry.excludeFrom(nextadr);
2667             do {
2668                 scanCond(tree.cond);
2669                 if (!flowKind.isFinal()) {
2670                     initsSkip.assign(initsWhenFalse) ;
2671                     uninitsSkip.assign(uninitsWhenFalse);
2672                 }
2673                 inits.assign(initsWhenTrue);
2674                 uninits.assign(uninitsWhenTrue);
2675                 scan(tree.body);
2676                 resolveContinues(tree);
2677                 if (log.nerrors != prevErrors ||
2678                     flowKind.isFinal() ||
2679                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
2680                     break;
2681                 }
2682                 uninits.assign(uninitsEntry.andSet(uninits));
2683                 flowKind = FlowKind.SPECULATIVE_LOOP;
2684             } while (true);
2685             flowKind = prevFlowKind;
2686             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
2687             //branch is not taken AND if it's DA/DU before any break statement
2688             inits.assign(initsSkip);
2689             uninits.assign(uninitsSkip);
2690             resolveBreaks(tree, prevPendingExits);
2691         }
2692 
2693         public void visitForLoop(JCForLoop tree) {
2694             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2695             FlowKind prevFlowKind = flowKind;
2696             flowKind = FlowKind.NORMAL;
2697             int nextadrPrev = nextadr;
2698             scan(tree.init);
2699             final Bits initsSkip = new Bits(true);
2700             final Bits uninitsSkip = new Bits(true);
2701             pendingExits = new ListBuffer<>();
2702             int prevErrors = log.nerrors;
2703             do {
2704                 final Bits uninitsEntry = new Bits(uninits);
2705                 uninitsEntry.excludeFrom(nextadr);
2706                 if (tree.cond != null) {
2707                     scanCond(tree.cond);
2708                     if (!flowKind.isFinal()) {
2709                         initsSkip.assign(initsWhenFalse);
2710                         uninitsSkip.assign(uninitsWhenFalse);
2711                     }
2712                     inits.assign(initsWhenTrue);
2713                     uninits.assign(uninitsWhenTrue);
2714                 } else if (!flowKind.isFinal()) {
2715                     initsSkip.assign(inits);
2716                     initsSkip.inclRange(firstadr, nextadr);
2717                     uninitsSkip.assign(uninits);
2718                     uninitsSkip.inclRange(firstadr, nextadr);
2719                 }
2720                 scan(tree.body);
2721                 resolveContinues(tree);
2722                 scan(tree.step);
2723                 if (log.nerrors != prevErrors ||
2724                     flowKind.isFinal() ||
2725                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
2726                     break;
2727                 uninits.assign(uninitsEntry.andSet(uninits));
2728                 flowKind = FlowKind.SPECULATIVE_LOOP;
2729             } while (true);
2730             flowKind = prevFlowKind;
2731             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
2732             //branch is not taken AND if it's DA/DU before any break statement
2733             inits.assign(initsSkip);
2734             uninits.assign(uninitsSkip);
2735             resolveBreaks(tree, prevPendingExits);
2736             nextadr = nextadrPrev;
2737         }
2738 
2739         public void visitForeachLoop(JCEnhancedForLoop tree) {
2740             visitVarDef(tree.var);
2741 
2742             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2743             FlowKind prevFlowKind = flowKind;
2744             flowKind = FlowKind.NORMAL;
2745             int nextadrPrev = nextadr;
2746             scan(tree.expr);
2747             final Bits initsStart = new Bits(inits);
2748             final Bits uninitsStart = new Bits(uninits);
2749 
2750             letInit(tree.pos(), tree.var.sym);
2751             pendingExits = new ListBuffer<>();
2752             int prevErrors = log.nerrors;
2753             do {
2754                 final Bits uninitsEntry = new Bits(uninits);
2755                 uninitsEntry.excludeFrom(nextadr);
2756                 scan(tree.body);
2757                 resolveContinues(tree);
2758                 if (log.nerrors != prevErrors ||
2759                     flowKind.isFinal() ||
2760                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
2761                     break;
2762                 uninits.assign(uninitsEntry.andSet(uninits));
2763                 flowKind = FlowKind.SPECULATIVE_LOOP;
2764             } while (true);
2765             flowKind = prevFlowKind;
2766             inits.assign(initsStart);
2767             uninits.assign(uninitsStart.andSet(uninits));
2768             resolveBreaks(tree, prevPendingExits);
2769             nextadr = nextadrPrev;
2770         }
2771 
2772         public void visitLabelled(JCLabeledStatement tree) {
2773             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2774             pendingExits = new ListBuffer<>();
2775             scan(tree.body);
2776             resolveBreaks(tree, prevPendingExits);
2777         }
2778 
2779         public void visitSwitch(JCSwitch tree) {
2780             handleSwitch(tree, tree.selector, tree.cases, tree.isExhaustive);
2781         }
2782 
2783         public void visitSwitchExpression(JCSwitchExpression tree) {
2784             handleSwitch(tree, tree.selector, tree.cases, tree.isExhaustive);
2785         }
2786 
2787         private void handleSwitch(JCTree tree, JCExpression selector,
2788                                   List<JCCase> cases, boolean isExhaustive) {
2789             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2790             pendingExits = new ListBuffer<>();
2791             int nextadrPrev = nextadr;
2792             scanExpr(selector);
2793             final Bits initsSwitch = new Bits(inits);
2794             final Bits uninitsSwitch = new Bits(uninits);
2795             for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
2796                 inits.assign(initsSwitch);
2797                 uninits.assign(uninits.andSet(uninitsSwitch));
2798                 JCCase c = l.head;
2799                 for (JCCaseLabel pat : c.labels) {
2800                     scanPattern(pat);
2801                 }
2802                 scan(c.guard);
2803                 if (inits.isReset()) {
2804                     inits.assign(initsWhenTrue);
2805                     uninits.assign(uninitsWhenTrue);
2806                 }
2807                 scan(c.stats);
2808                 if (c.completesNormally && c.caseKind == JCCase.RULE) {
2809                     scanSyntheticBreak(make, tree);
2810                 }
2811                 addVars(c.stats, initsSwitch, uninitsSwitch);
2812                 // Warn about fall-through if lint switch fallthrough enabled.
2813             }
2814             if (!isExhaustive) {
2815                 if (tree.hasTag(SWITCH_EXPRESSION)) {
2816                     markDead();
2817                 } else if (tree.hasTag(SWITCH) && !TreeInfo.expectedExhaustive((JCSwitch) tree)) {
2818                     inits.assign(initsSwitch);
2819                     uninits.assign(uninits.andSet(uninitsSwitch));
2820                 }
2821             }
2822             if (tree.hasTag(SWITCH_EXPRESSION)) {
2823                 resolveYields(tree, prevPendingExits);
2824             } else {
2825                 resolveBreaks(tree, prevPendingExits);
2826             }
2827             nextadr = nextadrPrev;
2828         }
2829         // where
2830             /** Add any variables defined in stats to inits and uninits. */
2831             private void addVars(List<JCStatement> stats, final Bits inits,
2832                                         final Bits uninits) {
2833                 for (;stats.nonEmpty(); stats = stats.tail) {
2834                     JCTree stat = stats.head;
2835                     if (stat.hasTag(VARDEF)) {
2836                         int adr = ((JCVariableDecl) stat).sym.adr;
2837                         inits.excl(adr);
2838                         uninits.incl(adr);
2839                     }
2840                 }
2841             }
2842 
2843         public void visitTry(JCTry tree) {
2844             ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
2845             final Bits uninitsTryPrev = new Bits(uninitsTry);
2846             ListBuffer<PendingExit> prevPendingExits = pendingExits;
2847             pendingExits = new ListBuffer<>();
2848             final Bits initsTry = new Bits(inits);
2849             uninitsTry.assign(uninits);
2850             for (JCTree resource : tree.resources) {
2851                 if (resource instanceof JCVariableDecl variableDecl) {
2852                     visitVarDef(variableDecl);
2853                     unrefdResources.enter(variableDecl.sym);
2854                     resourceVarDecls.append(variableDecl);
2855                 } else if (resource instanceof JCExpression expression) {
2856                     scanExpr(expression);
2857                 } else {
2858                     throw new AssertionError(tree);  // parser error
2859                 }
2860             }
2861             scan(tree.body);
2862             uninitsTry.andSet(uninits);
2863             final Bits initsEnd = new Bits(inits);
2864             final Bits uninitsEnd = new Bits(uninits);
2865             int nextadrCatch = nextadr;
2866 
2867             if (!resourceVarDecls.isEmpty() &&
2868                     lint.isEnabled(Lint.LintCategory.TRY)) {
2869                 for (JCVariableDecl resVar : resourceVarDecls) {
2870                     if (unrefdResources.includes(resVar.sym) && !resVar.sym.isUnnamedVariable()) {
2871                         log.warning(Lint.LintCategory.TRY, resVar.pos(),
2872                                     Warnings.TryResourceNotReferenced(resVar.sym));
2873                         unrefdResources.remove(resVar.sym);
2874                     }
2875                 }
2876             }
2877 
2878             /*  The analysis of each catch should be independent.
2879              *  Each one should have the same initial values of inits and
2880              *  uninits.
2881              */
2882             final Bits initsCatchPrev = new Bits(initsTry);
2883             final Bits uninitsCatchPrev = new Bits(uninitsTry);
2884 
2885             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
2886                 JCVariableDecl param = l.head.param;
2887                 inits.assign(initsCatchPrev);
2888                 uninits.assign(uninitsCatchPrev);
2889                 scan(param);
2890                 /* If this is a TWR and we are executing the code from Gen,
2891                  * then there can be synthetic variables, ignore them.
2892                  */
2893                 initParam(param);
2894                 scan(l.head.body);
2895                 initsEnd.andSet(inits);
2896                 uninitsEnd.andSet(uninits);
2897                 nextadr = nextadrCatch;
2898             }
2899             if (tree.finalizer != null) {
2900                 inits.assign(initsTry);
2901                 uninits.assign(uninitsTry);
2902                 ListBuffer<PendingExit> exits = pendingExits;
2903                 pendingExits = prevPendingExits;
2904                 scan(tree.finalizer);
2905                 if (!tree.finallyCanCompleteNormally) {
2906                     // discard exits and exceptions from try and finally
2907                 } else {
2908                     uninits.andSet(uninitsEnd);
2909                     // FIX: this doesn't preserve source order of exits in catch
2910                     // versus finally!
2911                     while (exits.nonEmpty()) {
2912                         PendingExit exit = exits.next();
2913                         if (exit instanceof AssignPendingExit assignPendingExit) {
2914                             assignPendingExit.exit_inits.orSet(inits);
2915                             assignPendingExit.exit_uninits.andSet(uninits);
2916                         }
2917                         pendingExits.append(exit);
2918                     }
2919                     inits.orSet(initsEnd);
2920                 }
2921             } else {
2922                 inits.assign(initsEnd);
2923                 uninits.assign(uninitsEnd);
2924                 ListBuffer<PendingExit> exits = pendingExits;
2925                 pendingExits = prevPendingExits;
2926                 while (exits.nonEmpty()) pendingExits.append(exits.next());
2927             }
2928             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
2929         }
2930 
2931         public void visitConditional(JCConditional tree) {
2932             scanCond(tree.cond);
2933             final Bits initsBeforeElse = new Bits(initsWhenFalse);
2934             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
2935             inits.assign(initsWhenTrue);
2936             uninits.assign(uninitsWhenTrue);
2937             if (tree.truepart.type.hasTag(BOOLEAN) &&
2938                 tree.falsepart.type.hasTag(BOOLEAN)) {
2939                 // if b and c are boolean valued, then
2940                 // v is (un)assigned after a?b:c when true iff
2941                 //    v is (un)assigned after b when true and
2942                 //    v is (un)assigned after c when true
2943                 scanCond(tree.truepart);
2944                 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
2945                 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
2946                 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
2947                 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
2948                 inits.assign(initsBeforeElse);
2949                 uninits.assign(uninitsBeforeElse);
2950                 scanCond(tree.falsepart);
2951                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
2952                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
2953                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
2954                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
2955             } else {
2956                 scanExpr(tree.truepart);
2957                 final Bits initsAfterThen = new Bits(inits);
2958                 final Bits uninitsAfterThen = new Bits(uninits);
2959                 inits.assign(initsBeforeElse);
2960                 uninits.assign(uninitsBeforeElse);
2961                 scanExpr(tree.falsepart);
2962                 inits.andSet(initsAfterThen);
2963                 uninits.andSet(uninitsAfterThen);
2964             }
2965         }
2966 
2967         public void visitIf(JCIf tree) {
2968             scanCond(tree.cond);
2969             final Bits initsBeforeElse = new Bits(initsWhenFalse);
2970             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
2971             inits.assign(initsWhenTrue);
2972             uninits.assign(uninitsWhenTrue);
2973             scan(tree.thenpart);
2974             if (tree.elsepart != null) {
2975                 final Bits initsAfterThen = new Bits(inits);
2976                 final Bits uninitsAfterThen = new Bits(uninits);
2977                 inits.assign(initsBeforeElse);
2978                 uninits.assign(uninitsBeforeElse);
2979                 scan(tree.elsepart);
2980                 inits.andSet(initsAfterThen);
2981                 uninits.andSet(uninitsAfterThen);
2982             } else {
2983                 inits.andSet(initsBeforeElse);
2984                 uninits.andSet(uninitsBeforeElse);
2985             }
2986         }
2987 
2988         @Override
2989         public void visitBreak(JCBreak tree) {
2990             recordExit(new AssignPendingExit(tree, inits, uninits));
2991         }
2992 
2993         @Override
2994         public void visitYield(JCYield tree) {
2995             JCSwitchExpression expr = (JCSwitchExpression) tree.target;
2996             if (expr != null && expr.type.hasTag(BOOLEAN)) {
2997                 scanCond(tree.value);
2998                 Bits initsAfterBreakWhenTrue = new Bits(initsWhenTrue);
2999                 Bits initsAfterBreakWhenFalse = new Bits(initsWhenFalse);
3000                 Bits uninitsAfterBreakWhenTrue = new Bits(uninitsWhenTrue);
3001                 Bits uninitsAfterBreakWhenFalse = new Bits(uninitsWhenFalse);
3002                 PendingExit exit = new PendingExit(tree) {
3003                     @Override
3004                     void resolveJump() {
3005                         if (!inits.isReset()) {
3006                             split(true);
3007                         }
3008                         initsWhenTrue.andSet(initsAfterBreakWhenTrue);
3009                         initsWhenFalse.andSet(initsAfterBreakWhenFalse);
3010                         uninitsWhenTrue.andSet(uninitsAfterBreakWhenTrue);
3011                         uninitsWhenFalse.andSet(uninitsAfterBreakWhenFalse);
3012                     }
3013                 };
3014                 merge();
3015                 recordExit(exit);
3016                 return ;
3017             } else {
3018                 scanExpr(tree.value);
3019                 recordExit(new AssignPendingExit(tree, inits, uninits));
3020             }
3021         }
3022 
3023         @Override
3024         public void visitContinue(JCContinue tree) {
3025             recordExit(new AssignPendingExit(tree, inits, uninits));
3026         }
3027 
3028         @Override
3029         public void visitReturn(JCReturn tree) {
3030             scanExpr(tree.expr);
3031             recordExit(new AssignPendingExit(tree, inits, uninits));
3032         }
3033 
3034         public void visitThrow(JCThrow tree) {
3035             scanExpr(tree.expr);
3036             markDead();
3037         }
3038 
3039         public void visitApply(JCMethodInvocation tree) {
3040             scanExpr(tree.meth);
3041             scanExprs(tree.args);
3042             if (tree.meth.hasTag(IDENT)) {
3043                 JCIdent ident = (JCIdent) tree.meth;
3044                 if (ident.name != names._super && !ident.sym.isStatic())
3045                     checkEmbryonicThisExposure(tree);
3046             }
3047         }
3048 
3049         public void visitNewClass(JCNewClass tree) {
3050             scanExpr(tree.encl);
3051             scanExprs(tree.args);
3052             scan(tree.def);
3053             if (classDef != null && tree.encl == null && tree.clazz.hasTag(IDENT)) {
3054                 JCIdent clazz = (JCIdent) tree.clazz;
3055                 if (!clazz.sym.isStatic() && clazz.type.getEnclosingType().tsym == classDef.sym) {
3056                     checkEmbryonicThisExposure(tree);
3057                 }
3058             }
3059         }
3060 
3061         @Override
3062         public void visitLambda(JCLambda tree) {
3063             final Bits prevUninits = new Bits(uninits);
3064             final Bits prevUninitsTry = new Bits(uninitsTry);
3065             final Bits prevInits = new Bits(inits);
3066             int returnadrPrev = returnadr;
3067             int nextadrPrev = nextadr;
3068             ListBuffer<PendingExit> prevPending = pendingExits;
3069             try {
3070                 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
3071                 // body. This is by design: a variable that was definitely unassigned before the
3072                 // lambda body may end up being assigned to later on, so we cannot conclude that
3073                 // the variable will be unassigned when the body is executed.
3074                 uninits.excludeFrom(firstadr);
3075                 returnadr = nextadr;
3076                 pendingExits = new ListBuffer<>();
3077                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
3078                     JCVariableDecl def = l.head;
3079                     scan(def);
3080                     inits.incl(def.sym.adr);
3081                     uninits.excl(def.sym.adr);
3082                 }
3083                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
3084                     scanExpr(tree.body);
3085                 } else {
3086                     scan(tree.body);
3087                 }
3088             }
3089             finally {
3090                 returnadr = returnadrPrev;
3091                 uninits.assign(prevUninits);
3092                 uninitsTry.assign(prevUninitsTry);
3093                 inits.assign(prevInits);
3094                 pendingExits = prevPending;
3095                 nextadr = nextadrPrev;
3096             }
3097         }
3098 
3099         public void visitNewArray(JCNewArray tree) {
3100             scanExprs(tree.dims);
3101             scanExprs(tree.elems);
3102         }
3103 
3104         public void visitAssert(JCAssert tree) {
3105             final Bits initsExit = new Bits(inits);
3106             final Bits uninitsExit = new Bits(uninits);
3107             scanCond(tree.cond);
3108             uninitsExit.andSet(uninitsWhenTrue);
3109             if (tree.detail != null) {
3110                 inits.assign(initsWhenFalse);
3111                 uninits.assign(uninitsWhenFalse);
3112                 scanExpr(tree.detail);
3113             }
3114             inits.assign(initsExit);
3115             uninits.assign(uninitsExit);
3116         }
3117 
3118         public void visitAssign(JCAssign tree) {
3119             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3120                 scanExpr(tree.lhs);
3121             scanExpr(tree.rhs);
3122             letInit(tree.lhs);
3123         }
3124 
3125         // check fields accessed through this.<field> are definitely
3126         // assigned before reading their value
3127         public void visitSelect(JCFieldAccess tree) {
3128             ThisExposability priorThisExposability = this.thisExposability;
3129             try {
3130                 if (tree.name == names._this && classDef != null && tree.sym.owner == classDef.sym) {
3131                     checkEmbryonicThisExposure(tree);
3132                 } else if (tree.sym.kind == VAR || tree.sym.isStatic()) {
3133                     this.thisExposability = ALLOWED;
3134                 }
3135                 super.visitSelect(tree);
3136             if (TreeInfo.isThisQualifier(tree.selected) &&
3137                 tree.sym.kind == VAR) {
3138                     checkInit(tree.pos(), (VarSymbol)tree.sym);
3139                 }
3140             } finally {
3141                  this.thisExposability = priorThisExposability;
3142             }
3143         }
3144 
3145         public void visitAssignop(JCAssignOp tree) {
3146             scanExpr(tree.lhs);
3147             scanExpr(tree.rhs);
3148             letInit(tree.lhs);
3149         }
3150 
3151         public void visitUnary(JCUnary tree) {
3152             switch (tree.getTag()) {
3153             case NOT:
3154                 scanCond(tree.arg);
3155                 final Bits t = new Bits(initsWhenFalse);
3156                 initsWhenFalse.assign(initsWhenTrue);
3157                 initsWhenTrue.assign(t);
3158                 t.assign(uninitsWhenFalse);
3159                 uninitsWhenFalse.assign(uninitsWhenTrue);
3160                 uninitsWhenTrue.assign(t);
3161                 break;
3162             case PREINC: case POSTINC:
3163             case PREDEC: case POSTDEC:
3164                 scanExpr(tree.arg);
3165                 letInit(tree.arg);
3166                 break;
3167             default:
3168                 scanExpr(tree.arg);
3169             }
3170         }
3171 
3172         public void visitBinary(JCBinary tree) {
3173             switch (tree.getTag()) {
3174             case AND:
3175                 scanCond(tree.lhs);
3176                 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
3177                 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
3178                 inits.assign(initsWhenTrue);
3179                 uninits.assign(uninitsWhenTrue);
3180                 scanCond(tree.rhs);
3181                 initsWhenFalse.andSet(initsWhenFalseLeft);
3182                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
3183                 break;
3184             case OR:
3185                 scanCond(tree.lhs);
3186                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3187                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3188                 inits.assign(initsWhenFalse);
3189                 uninits.assign(uninitsWhenFalse);
3190                 scanCond(tree.rhs);
3191                 initsWhenTrue.andSet(initsWhenTrueLeft);
3192                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3193                 break;
3194             default:
3195                 scanExpr(tree.lhs);
3196                 scanExpr(tree.rhs);
3197             }
3198         }
3199 
3200         public void visitIdent(JCIdent tree) {
3201             if (tree.sym.kind == VAR) {
3202                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3203                 referenced(tree.sym);
3204             }
3205             if (tree.name == names._this) {
3206                 checkEmbryonicThisExposure(tree);
3207             }
3208         }
3209 
3210         @Override
3211         public void visitTypeTest(JCInstanceOf tree) {
3212             scanExpr(tree.expr);
3213             scan(tree.pattern);
3214         }
3215 
3216         @Override
3217         public void visitBindingPattern(JCBindingPattern tree) {
3218             scan(tree.var);
3219             initParam(tree.var);
3220         }
3221 
3222         void referenced(Symbol sym) {
3223             unrefdResources.remove(sym);
3224         }
3225 
3226         public void visitAnnotatedType(JCAnnotatedType tree) {
3227             // annotations don't get scanned
3228             tree.underlyingType.accept(this);
3229         }
3230 
3231         public void visitModuleDef(JCModuleDecl tree) {
3232             // Do nothing for modules
3233         }
3234 
3235     /**************************************************************************
3236      * main method
3237      *************************************************************************/
3238 
3239         /** Perform definite assignment/unassignment analysis on a tree.
3240          */
3241         public void analyzeTree(Env<?> env, TreeMaker make) {
3242             analyzeTree(env, env.tree, make);
3243          }
3244 
3245         public void analyzeTree(Env<?> env, JCTree tree, TreeMaker make) {
3246             try {
3247                 startPos = tree.pos().getStartPosition();
3248 
3249                 if (vardecls == null)
3250                     vardecls = new JCVariableDecl[32];
3251                 else
3252                     for (int i=0; i<vardecls.length; i++)
3253                         vardecls[i] = null;
3254                 firstadr = 0;
3255                 nextadr = 0;
3256                 Flow.this.make = make;
3257                 pendingExits = new ListBuffer<>();
3258                 this.classDef = null;
3259                 unrefdResources = WriteableScope.create(env.enclClass.sym);
3260                 scan(tree);
3261             } finally {
3262                 // note that recursive invocations of this method fail hard
3263                 startPos = -1;
3264                 resetBits(inits, uninits, uninitsTry, initsWhenTrue,
3265                         initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
3266                 if (vardecls != null) {
3267                     for (int i=0; i<vardecls.length; i++)
3268                         vardecls[i] = null;
3269                 }
3270                 firstadr = 0;
3271                 nextadr = 0;
3272                 Flow.this.make = null;
3273                 pendingExits = null;
3274                 this.classDef = null;
3275                 unrefdResources = null;
3276             }
3277         }
3278     }
3279 
3280     /**
3281      * This pass implements the last step of the dataflow analysis, namely
3282      * the effectively-final analysis check. This checks that every local variable
3283      * reference from a lambda body/local inner class is either final or effectively final.
3284      * Additional this also checks that every variable that is used as an operand to
3285      * try-with-resources is final or effectively final.
3286      * As effectively final variables are marked as such during DA/DU, this pass must run after
3287      * AssignAnalyzer.
3288      */
3289     class CaptureAnalyzer extends BaseAnalyzer {
3290 
3291         JCTree currentTree; //local class or lambda
3292         WriteableScope declaredInsideGuard;
3293 
3294         @Override
3295         void markDead() {
3296             //do nothing
3297         }
3298 
3299         @SuppressWarnings("fallthrough")
3300         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
3301             if (currentTree != null &&
3302                     sym.owner.kind == MTH &&
3303                     sym.pos < currentTree.getStartPosition()) {
3304                 switch (currentTree.getTag()) {
3305                     case CLASSDEF:
3306                     case CASE:
3307                     case LAMBDA:
3308                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
3309                            reportEffectivelyFinalError(pos, sym);
3310                         }
3311                 }
3312             }
3313         }
3314 
3315         @SuppressWarnings("fallthrough")
3316         void letInit(JCTree tree) {
3317             tree = TreeInfo.skipParens(tree);
3318             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
3319                 Symbol sym = TreeInfo.symbol(tree);
3320                 if (currentTree != null) {
3321                     switch (currentTree.getTag()) {
3322                         case CLASSDEF, LAMBDA -> {
3323                             if (sym.kind == VAR &&
3324                                 sym.owner.kind == MTH &&
3325                                 ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
3326                                 reportEffectivelyFinalError(tree, sym);
3327                             }
3328                         }
3329                         case CASE -> {
3330                             if (!declaredInsideGuard.includes(sym)) {
3331                                 log.error(tree.pos(), Errors.CannotAssignNotDeclaredGuard(sym));
3332                             }
3333                         }
3334                     }
3335                 }
3336             }
3337         }
3338 
3339         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
3340             Fragment subKey = switch (currentTree.getTag()) {
3341                 case LAMBDA -> Fragments.Lambda;
3342                 case CASE -> Fragments.Guard;
3343                 case CLASSDEF -> Fragments.InnerCls;
3344                 default -> throw new AssertionError("Unexpected tree kind: " + currentTree.getTag());
3345             };
3346             log.error(pos, Errors.CantRefNonEffectivelyFinalVar(sym, diags.fragment(subKey)));
3347         }
3348 
3349     /*************************************************************************
3350      * Visitor methods for statements and definitions
3351      *************************************************************************/
3352 
3353         /* ------------ Visitor methods for various sorts of trees -------------*/
3354 
3355         public void visitClassDef(JCClassDecl tree) {
3356             JCTree prevTree = currentTree;
3357             try {
3358                 currentTree = tree.sym.isDirectlyOrIndirectlyLocal() ? tree : null;
3359                 super.visitClassDef(tree);
3360             } finally {
3361                 currentTree = prevTree;
3362             }
3363         }
3364 
3365         @Override
3366         public void visitLambda(JCLambda tree) {
3367             JCTree prevTree = currentTree;
3368             try {
3369                 currentTree = tree;
3370                 super.visitLambda(tree);
3371             } finally {
3372                 currentTree = prevTree;
3373             }
3374         }
3375 
3376         @Override
3377         public void visitBindingPattern(JCBindingPattern tree) {
3378             scan(tree.var);
3379         }
3380 
3381         @Override
3382         public void visitCase(JCCase tree) {
3383             scan(tree.labels);
3384             if (tree.guard != null) {
3385                 JCTree prevTree = currentTree;
3386                 WriteableScope prevDeclaredInsideGuard = declaredInsideGuard;
3387                 try {
3388                     currentTree = tree;
3389                     declaredInsideGuard = WriteableScope.create(attrEnv.enclClass.sym);
3390                     scan(tree.guard);
3391                 } finally {
3392                     currentTree = prevTree;
3393                     declaredInsideGuard = prevDeclaredInsideGuard;
3394                 }
3395             }
3396             scan(tree.stats);
3397         }
3398 
3399         @Override
3400         public void visitRecordPattern(JCRecordPattern tree) {
3401             scan(tree.deconstructor);
3402             scan(tree.nested);
3403         }
3404 
3405         @Override
3406         public void visitIdent(JCIdent tree) {
3407             if (tree.sym.kind == VAR) {
3408                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
3409             }
3410         }
3411 
3412         public void visitAssign(JCAssign tree) {
3413             JCTree lhs = TreeInfo.skipParens(tree.lhs);
3414             if (!(lhs instanceof JCIdent)) {
3415                 scan(lhs);
3416             }
3417             scan(tree.rhs);
3418             letInit(lhs);
3419         }
3420 
3421         public void visitAssignop(JCAssignOp tree) {
3422             scan(tree.lhs);
3423             scan(tree.rhs);
3424             letInit(tree.lhs);
3425         }
3426 
3427         public void visitUnary(JCUnary tree) {
3428             switch (tree.getTag()) {
3429                 case PREINC: case POSTINC:
3430                 case PREDEC: case POSTDEC:
3431                     scan(tree.arg);
3432                     letInit(tree.arg);
3433                     break;
3434                 default:
3435                     scan(tree.arg);
3436             }
3437         }
3438 
3439         public void visitTry(JCTry tree) {
3440             for (JCTree resource : tree.resources) {
3441                 if (!resource.hasTag(VARDEF)) {
3442                     Symbol var = TreeInfo.symbol(resource);
3443                     if (var != null && (var.flags() & (FINAL | EFFECTIVELY_FINAL)) == 0) {
3444                         log.error(resource.pos(), Errors.TryWithResourcesExprEffectivelyFinalVar(var));
3445                     }
3446                 }
3447             }
3448             super.visitTry(tree);
3449         }
3450 
3451         @Override
3452         public void visitVarDef(JCVariableDecl tree) {
3453             if (declaredInsideGuard != null) {
3454                 declaredInsideGuard.enter(tree.sym);
3455             }
3456             super.visitVarDef(tree);
3457         }
3458 
3459         @Override
3460         public void visitYield(JCYield tree) {
3461             scan(tree.value);
3462         }
3463 
3464         public void visitModuleDef(JCModuleDecl tree) {
3465             // Do nothing for modules
3466         }
3467 
3468     /**************************************************************************
3469      * main method
3470      *************************************************************************/
3471 
3472         /** Perform definite assignment/unassignment analysis on a tree.
3473          */
3474         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
3475             analyzeTree(env, env.tree, make);
3476         }
3477         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
3478             try {
3479                 attrEnv = env;
3480                 Flow.this.make = make;
3481                 pendingExits = new ListBuffer<>();
3482                 scan(tree);
3483             } finally {
3484                 pendingExits = null;
3485                 Flow.this.make = null;
3486             }
3487         }
3488     }
3489 
3490     enum Liveness {
3491         ALIVE {
3492             @Override
3493             public Liveness or(Liveness other) {
3494                 return this;
3495             }
3496             @Override
3497             public Liveness and(Liveness other) {
3498                 return other;
3499             }
3500         },
3501         DEAD {
3502             @Override
3503             public Liveness or(Liveness other) {
3504                 return other;
3505             }
3506             @Override
3507             public Liveness and(Liveness other) {
3508                 return this;
3509             }
3510         },
3511         RECOVERY {
3512             @Override
3513             public Liveness or(Liveness other) {
3514                 if (other == ALIVE) {
3515                     return ALIVE;
3516                 } else {
3517                     return this;
3518                 }
3519             }
3520             @Override
3521             public Liveness and(Liveness other) {
3522                 if (other == DEAD) {
3523                     return DEAD;
3524                 } else {
3525                     return this;
3526                 }
3527             }
3528         };
3529 
3530         public abstract Liveness or(Liveness other);
3531         public abstract Liveness and(Liveness other);
3532         public Liveness or(boolean value) {
3533             return or(from(value));
3534         }
3535         public Liveness and(boolean value) {
3536             return and(from(value));
3537         }
3538         public static Liveness from(boolean value) {
3539             return value ? ALIVE : DEAD;
3540         }
3541     }
3542 
3543     sealed interface PatternDescription { }
3544     public PatternDescription makePatternDescription(Type selectorType, JCPattern pattern) {
3545         if (pattern instanceof JCBindingPattern binding) {
3546             Type type = types.isSubtype(selectorType, binding.type)
3547                     ? selectorType : binding.type;
3548             return new BindingPattern(type);
3549         } else if (pattern instanceof JCRecordPattern record) {
3550             Type[] componentTypes;
3551 
3552             if (!record.type.isErroneous()) {
3553                 componentTypes = ((ClassSymbol) record.type.tsym).getRecordComponents()
3554                         .map(r -> types.memberType(record.type, r))
3555                         .toArray(s -> new Type[s]);
3556             }
3557             else {
3558                 componentTypes = record.nested.map(t -> types.createErrorType(t.type)).toArray(s -> new Type[s]);;
3559             }
3560 
3561             PatternDescription[] nestedDescriptions =
3562                     new PatternDescription[record.nested.size()];
3563             int i = 0;
3564             for (List<JCPattern> it = record.nested;
3565                  it.nonEmpty();
3566                  it = it.tail, i++) {
3567                 nestedDescriptions[i] = makePatternDescription(types.erasure(componentTypes[i]), it.head);
3568             }
3569             return new RecordPattern(record.type, componentTypes, nestedDescriptions);
3570         } else if (pattern instanceof JCAnyPattern) {
3571             Type type = types.isSubtype(selectorType, syms.objectType)
3572                     ? selectorType : syms.objectType;
3573             return new BindingPattern(type);
3574         } else {
3575             throw Assert.error();
3576         }
3577     }
3578     record BindingPattern(Type type) implements PatternDescription {
3579         @Override
3580         public int hashCode() {
3581             return type.tsym.hashCode();
3582         }
3583         @Override
3584         public boolean equals(Object o) {
3585             return o instanceof BindingPattern other &&
3586                     type.tsym == other.type.tsym;
3587         }
3588         @Override
3589         public String toString() {
3590             return type.tsym + " _";
3591         }
3592     }
3593     record RecordPattern(Type recordType, int _hashCode, Type[] fullComponentTypes, PatternDescription... nested) implements PatternDescription {
3594 
3595         public RecordPattern(Type recordType, Type[] fullComponentTypes, PatternDescription[] nested) {
3596             this(recordType, hashCode(-1, recordType, nested), fullComponentTypes, nested);
3597         }
3598 
3599         @Override
3600         public int hashCode() {
3601             return _hashCode;
3602         }
3603 
3604         @Override
3605         public boolean equals(Object o) {
3606             return o instanceof RecordPattern other &&
3607                     recordType.tsym == other.recordType.tsym &&
3608                     Arrays.equals(nested, other.nested);
3609         }
3610 
3611         public int hashCode(int excludeComponent) {
3612             return hashCode(excludeComponent, recordType, nested);
3613         }
3614 
3615         public static int hashCode(int excludeComponent, Type recordType, PatternDescription... nested) {
3616             int hash = 5;
3617             hash =  41 * hash + recordType.tsym.hashCode();
3618             for (int  i = 0; i < nested.length; i++) {
3619                 if (i != excludeComponent) {
3620                     hash = 41 * hash + nested[i].hashCode();
3621                 }
3622             }
3623             return hash;
3624         }
3625         @Override
3626         public String toString() {
3627             return recordType.tsym + "(" + Arrays.stream(nested)
3628                     .map(pd -> pd.toString())
3629                     .collect(Collectors.joining(", ")) + ")";
3630         }
3631     }
3632 }