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