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