src/share/classes/com/sun/tools/javac/comp/Flow.java

Mon, 16 Oct 2017 16:07:48 +0800

author
aoqi
date
Mon, 16 Oct 2017 16:07:48 +0800
changeset 2893
ca5783d9a597
parent 2820
7f6d6b80a58b
parent 2702
9ca8d8713094
permissions
-rw-r--r--

merge

     1 /*
     2  * Copyright (c) 1999, 2015, 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  */
    26 //todo: one might eliminate uninits.andSets when monotonic
    28 package com.sun.tools.javac.comp;
    30 import java.util.HashMap;
    32 import com.sun.tools.javac.code.*;
    33 import com.sun.tools.javac.tree.*;
    34 import com.sun.tools.javac.util.*;
    35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    37 import com.sun.tools.javac.code.Symbol.*;
    38 import com.sun.tools.javac.tree.JCTree.*;
    40 import static com.sun.tools.javac.code.Flags.*;
    41 import static com.sun.tools.javac.code.Flags.BLOCK;
    42 import static com.sun.tools.javac.code.Kinds.*;
    43 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
    44 import static com.sun.tools.javac.code.TypeTag.VOID;
    45 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    47 /** This pass implements dataflow analysis for Java programs though
    48  *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
    49  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
    50  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
    51  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
    52  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
    53  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
    54  *  determines that local variables accessed within the scope of an inner class/lambda
    55  *  are either final or effectively-final.
    56  *
    57  *  <p>The JLS has a number of problems in the
    58  *  specification of these flow analysis problems. This implementation
    59  *  attempts to address those issues.
    60  *
    61  *  <p>First, there is no accommodation for a finally clause that cannot
    62  *  complete normally. For liveness analysis, an intervening finally
    63  *  clause can cause a break, continue, or return not to reach its
    64  *  target.  For exception analysis, an intervening finally clause can
    65  *  cause any exception to be "caught".  For DA/DU analysis, the finally
    66  *  clause can prevent a transfer of control from propagating DA/DU
    67  *  state to the target.  In addition, code in the finally clause can
    68  *  affect the DA/DU status of variables.
    69  *
    70  *  <p>For try statements, we introduce the idea of a variable being
    71  *  definitely unassigned "everywhere" in a block.  A variable V is
    72  *  "unassigned everywhere" in a block iff it is unassigned at the
    73  *  beginning of the block and there is no reachable assignment to V
    74  *  in the block.  An assignment V=e is reachable iff V is not DA
    75  *  after e.  Then we can say that V is DU at the beginning of the
    76  *  catch block iff V is DU everywhere in the try block.  Similarly, V
    77  *  is DU at the beginning of the finally block iff V is DU everywhere
    78  *  in the try block and in every catch block.  Specifically, the
    79  *  following bullet is added to 16.2.2
    80  *  <pre>
    81  *      V is <em>unassigned everywhere</em> in a block if it is
    82  *      unassigned before the block and there is no reachable
    83  *      assignment to V within the block.
    84  *  </pre>
    85  *  <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all
    86  *  try blocks is changed to
    87  *  <pre>
    88  *      V is definitely unassigned before a catch block iff V is
    89  *      definitely unassigned everywhere in the try block.
    90  *  </pre>
    91  *  <p>The last bullet (and all of its sub-bullets) for try blocks that
    92  *  have a finally block is changed to
    93  *  <pre>
    94  *      V is definitely unassigned before the finally block iff
    95  *      V is definitely unassigned everywhere in the try block
    96  *      and everywhere in each catch block of the try statement.
    97  *  </pre>
    98  *  <p>In addition,
    99  *  <pre>
   100  *      V is definitely assigned at the end of a constructor iff
   101  *      V is definitely assigned after the block that is the body
   102  *      of the constructor and V is definitely assigned at every
   103  *      return that can return from the constructor.
   104  *  </pre>
   105  *  <p>In addition, each continue statement with the loop as its target
   106  *  is treated as a jump to the end of the loop body, and "intervening"
   107  *  finally clauses are treated as follows: V is DA "due to the
   108  *  continue" iff V is DA before the continue statement or V is DA at
   109  *  the end of any intervening finally block.  V is DU "due to the
   110  *  continue" iff any intervening finally cannot complete normally or V
   111  *  is DU at the end of every intervening finally block.  This "due to
   112  *  the continue" concept is then used in the spec for the loops.
   113  *
   114  *  <p>Similarly, break statements must consider intervening finally
   115  *  blocks.  For liveness analysis, a break statement for which any
   116  *  intervening finally cannot complete normally is not considered to
   117  *  cause the target statement to be able to complete normally. Then
   118  *  we say V is DA "due to the break" iff V is DA before the break or
   119  *  V is DA at the end of any intervening finally block.  V is DU "due
   120  *  to the break" iff any intervening finally cannot complete normally
   121  *  or V is DU at the break and at the end of every intervening
   122  *  finally block.  (I suspect this latter condition can be
   123  *  simplified.)  This "due to the break" is then used in the spec for
   124  *  all statements that can be "broken".
   125  *
   126  *  <p>The return statement is treated similarly.  V is DA "due to a
   127  *  return statement" iff V is DA before the return statement or V is
   128  *  DA at the end of any intervening finally block.  Note that we
   129  *  don't have to worry about the return expression because this
   130  *  concept is only used for construcrors.
   131  *
   132  *  <p>There is no spec in the JLS for when a variable is definitely
   133  *  assigned at the end of a constructor, which is needed for final
   134  *  fields (8.3.1.2).  We implement the rule that V is DA at the end
   135  *  of the constructor iff it is DA and the end of the body of the
   136  *  constructor and V is DA "due to" every return of the constructor.
   137  *
   138  *  <p>Intervening finally blocks similarly affect exception analysis.  An
   139  *  intervening finally that cannot complete normally allows us to ignore
   140  *  an otherwise uncaught exception.
   141  *
   142  *  <p>To implement the semantics of intervening finally clauses, all
   143  *  nonlocal transfers (break, continue, return, throw, method call that
   144  *  can throw a checked exception, and a constructor invocation that can
   145  *  thrown a checked exception) are recorded in a queue, and removed
   146  *  from the queue when we complete processing the target of the
   147  *  nonlocal transfer.  This allows us to modify the queue in accordance
   148  *  with the above rules when we encounter a finally clause.  The only
   149  *  exception to this [no pun intended] is that checked exceptions that
   150  *  are known to be caught or declared to be caught in the enclosing
   151  *  method are not recorded in the queue, but instead are recorded in a
   152  *  global variable "{@code Set<Type> thrown}" that records the type of all
   153  *  exceptions that can be thrown.
   154  *
   155  *  <p>Other minor issues the treatment of members of other classes
   156  *  (always considered DA except that within an anonymous class
   157  *  constructor, where DA status from the enclosing scope is
   158  *  preserved), treatment of the case expression (V is DA before the
   159  *  case expression iff V is DA after the switch expression),
   160  *  treatment of variables declared in a switch block (the implied
   161  *  DA/DU status after the switch expression is DU and not DA for
   162  *  variables defined in a switch block), the treatment of boolean ?:
   163  *  expressions (The JLS rules only handle b and c non-boolean; the
   164  *  new rule is that if b and c are boolean valued, then V is
   165  *  (un)assigned after a?b:c when true/false iff V is (un)assigned
   166  *  after b when true/false and V is (un)assigned after c when
   167  *  true/false).
   168  *
   169  *  <p>There is the remaining question of what syntactic forms constitute a
   170  *  reference to a variable.  It is conventional to allow this.x on the
   171  *  left-hand-side to initialize a final instance field named x, yet
   172  *  this.x isn't considered a "use" when appearing on a right-hand-side
   173  *  in most implementations.  Should parentheses affect what is
   174  *  considered a variable reference?  The simplest rule would be to
   175  *  allow unqualified forms only, parentheses optional, and phase out
   176  *  support for assigning to a final field via this.x.
   177  *
   178  *  <p><b>This is NOT part of any supported API.
   179  *  If you write code that depends on this, you do so at your own risk.
   180  *  This code and its internal interfaces are subject to change or
   181  *  deletion without notice.</b>
   182  */
   183 public class Flow {
   184     protected static final Context.Key<Flow> flowKey =
   185         new Context.Key<Flow>();
   187     private final Names names;
   188     private final Log log;
   189     private final Symtab syms;
   190     private final Types types;
   191     private final Check chk;
   192     private       TreeMaker make;
   193     private final Resolve rs;
   194     private final JCDiagnostic.Factory diags;
   195     private Env<AttrContext> attrEnv;
   196     private       Lint lint;
   197     private final boolean allowImprovedRethrowAnalysis;
   198     private final boolean allowImprovedCatchAnalysis;
   199     private final boolean allowEffectivelyFinalInInnerClasses;
   200     private final boolean enforceThisDotInit;
   202     public static Flow instance(Context context) {
   203         Flow instance = context.get(flowKey);
   204         if (instance == null)
   205             instance = new Flow(context);
   206         return instance;
   207     }
   209     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   210         new AliveAnalyzer().analyzeTree(env, make);
   211         new AssignAnalyzer().analyzeTree(env);
   212         new FlowAnalyzer().analyzeTree(env, make);
   213         new CaptureAnalyzer().analyzeTree(env, make);
   214     }
   216     public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
   217         Log.DiagnosticHandler diagHandler = null;
   218         //we need to disable diagnostics temporarily; the problem is that if
   219         //a lambda expression contains e.g. an unreachable statement, an error
   220         //message will be reported and will cause compilation to skip the flow analyis
   221         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
   222         //related errors, which will allow for more errors to be detected
   223         if (!speculative) {
   224             diagHandler = new Log.DiscardDiagnosticHandler(log);
   225         }
   226         try {
   227             new AliveAnalyzer().analyzeTree(env, that, make);
   228         } finally {
   229             if (!speculative) {
   230                 log.popDiagnosticHandler(diagHandler);
   231             }
   232         }
   233     }
   235     public List<Type> analyzeLambdaThrownTypes(final Env<AttrContext> env,
   236             JCLambda that, TreeMaker make) {
   237         //we need to disable diagnostics temporarily; the problem is that if
   238         //a lambda expression contains e.g. an unreachable statement, an error
   239         //message will be reported and will cause compilation to skip the flow analyis
   240         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
   241         //related errors, which will allow for more errors to be detected
   242         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
   243         try {
   244             new AssignAnalyzer() {
   245                 Scope enclosedSymbols = new Scope(env.enclClass.sym);
   246                 @Override
   247                 public void visitVarDef(JCVariableDecl tree) {
   248                     enclosedSymbols.enter(tree.sym);
   249                     super.visitVarDef(tree);
   250                 }
   251                 @Override
   252                 protected boolean trackable(VarSymbol sym) {
   253                     return enclosedSymbols.includes(sym) &&
   254                            sym.owner.kind == MTH;
   255                 }
   256             }.analyzeTree(env, that);
   257             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
   258             flowAnalyzer.analyzeTree(env, that, make);
   259             return flowAnalyzer.inferredThrownTypes;
   260         } finally {
   261             log.popDiagnosticHandler(diagHandler);
   262         }
   263     }
   265     /**
   266      * Definite assignment scan mode
   267      */
   268     enum FlowKind {
   269         /**
   270          * This is the normal DA/DU analysis mode
   271          */
   272         NORMAL("var.might.already.be.assigned", false),
   273         /**
   274          * This is the speculative DA/DU analysis mode used to speculatively
   275          * derive assertions within loop bodies
   276          */
   277         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
   279         final String errKey;
   280         final boolean isFinal;
   282         FlowKind(String errKey, boolean isFinal) {
   283             this.errKey = errKey;
   284             this.isFinal = isFinal;
   285         }
   287         boolean isFinal() {
   288             return isFinal;
   289         }
   290     }
   292     protected Flow(Context context) {
   293         context.put(flowKey, this);
   294         names = Names.instance(context);
   295         log = Log.instance(context);
   296         syms = Symtab.instance(context);
   297         types = Types.instance(context);
   298         chk = Check.instance(context);
   299         lint = Lint.instance(context);
   300         rs = Resolve.instance(context);
   301         diags = JCDiagnostic.Factory.instance(context);
   302         Source source = Source.instance(context);
   303         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   304         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   305         allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
   306         enforceThisDotInit = source.enforceThisDotInit();
   307     }
   309     /**
   310      * Base visitor class for all visitors implementing dataflow analysis logic.
   311      * This class define the shared logic for handling jumps (break/continue statements).
   312      */
   313     static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
   315         enum JumpKind {
   316             BREAK(JCTree.Tag.BREAK) {
   317                 @Override
   318                 JCTree getTarget(JCTree tree) {
   319                     return ((JCBreak)tree).target;
   320                 }
   321             },
   322             CONTINUE(JCTree.Tag.CONTINUE) {
   323                 @Override
   324                 JCTree getTarget(JCTree tree) {
   325                     return ((JCContinue)tree).target;
   326                 }
   327             };
   329             final JCTree.Tag treeTag;
   331             private JumpKind(Tag treeTag) {
   332                 this.treeTag = treeTag;
   333             }
   335             abstract JCTree getTarget(JCTree tree);
   336         }
   338         /** The currently pending exits that go from current inner blocks
   339          *  to an enclosing block, in source order.
   340          */
   341         ListBuffer<P> pendingExits;
   343         /** A pending exit.  These are the statements return, break, and
   344          *  continue.  In addition, exception-throwing expressions or
   345          *  statements are put here when not known to be caught.  This
   346          *  will typically result in an error unless it is within a
   347          *  try-finally whose finally block cannot complete normally.
   348          */
   349         static class PendingExit {
   350             JCTree tree;
   352             PendingExit(JCTree tree) {
   353                 this.tree = tree;
   354             }
   356             void resolveJump() {
   357                 //do nothing
   358             }
   359         }
   361         abstract void markDead();
   363         /** Record an outward transfer of control. */
   364         void recordExit(P pe) {
   365             pendingExits.append(pe);
   366             markDead();
   367         }
   369         /** Resolve all jumps of this statement. */
   370         private boolean resolveJump(JCTree tree,
   371                         ListBuffer<P> oldPendingExits,
   372                         JumpKind jk) {
   373             boolean resolved = false;
   374             List<P> exits = pendingExits.toList();
   375             pendingExits = oldPendingExits;
   376             for (; exits.nonEmpty(); exits = exits.tail) {
   377                 P exit = exits.head;
   378                 if (exit.tree.hasTag(jk.treeTag) &&
   379                         jk.getTarget(exit.tree) == tree) {
   380                     exit.resolveJump();
   381                     resolved = true;
   382                 } else {
   383                     pendingExits.append(exit);
   384                 }
   385             }
   386             return resolved;
   387         }
   389         /** Resolve all continues of this statement. */
   390         boolean resolveContinues(JCTree tree) {
   391             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
   392         }
   394         /** Resolve all breaks of this statement. */
   395         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
   396             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   397         }
   399         @Override
   400         public void scan(JCTree tree) {
   401             if (tree != null && (
   402                     tree.type == null ||
   403                     tree.type != Type.stuckType)) {
   404                 super.scan(tree);
   405             }
   406         }
   407     }
   409     /**
   410      * This pass implements the first step of the dataflow analysis, namely
   411      * the liveness analysis check. This checks that every statement is reachable.
   412      * The output of this analysis pass are used by other analyzers. This analyzer
   413      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   414      */
   415     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
   417         /** A flag that indicates whether the last statement could
   418          *  complete normally.
   419          */
   420         private boolean alive;
   422         @Override
   423         void markDead() {
   424             alive = false;
   425         }
   427     /*************************************************************************
   428      * Visitor methods for statements and definitions
   429      *************************************************************************/
   431         /** Analyze a definition.
   432          */
   433         void scanDef(JCTree tree) {
   434             scanStat(tree);
   435             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
   436                 log.error(tree.pos(),
   437                           "initializer.must.be.able.to.complete.normally");
   438             }
   439         }
   441         /** Analyze a statement. Check that statement is reachable.
   442          */
   443         void scanStat(JCTree tree) {
   444             if (!alive && tree != null) {
   445                 log.error(tree.pos(), "unreachable.stmt");
   446                 if (!tree.hasTag(SKIP)) alive = true;
   447             }
   448             scan(tree);
   449         }
   451         /** Analyze list of statements.
   452          */
   453         void scanStats(List<? extends JCStatement> trees) {
   454             if (trees != null)
   455                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
   456                     scanStat(l.head);
   457         }
   459         /* ------------ Visitor methods for various sorts of trees -------------*/
   461         public void visitClassDef(JCClassDecl tree) {
   462             if (tree.sym == null) return;
   463             boolean alivePrev = alive;
   464             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   465             Lint lintPrev = lint;
   467             pendingExits = new ListBuffer<>();
   468             lint = lint.augment(tree.sym);
   470             try {
   471                 // process all the static initializers
   472                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   473                     if (!l.head.hasTag(METHODDEF) &&
   474                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   475                         scanDef(l.head);
   476                     }
   477                 }
   479                 // process all the instance initializers
   480                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   481                     if (!l.head.hasTag(METHODDEF) &&
   482                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   483                         scanDef(l.head);
   484                     }
   485                 }
   487                 // process all the methods
   488                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   489                     if (l.head.hasTag(METHODDEF)) {
   490                         scan(l.head);
   491                     }
   492                 }
   493             } finally {
   494                 pendingExits = pendingExitsPrev;
   495                 alive = alivePrev;
   496                 lint = lintPrev;
   497             }
   498         }
   500         public void visitMethodDef(JCMethodDecl tree) {
   501             if (tree.body == null) return;
   502             Lint lintPrev = lint;
   504             lint = lint.augment(tree.sym);
   506             Assert.check(pendingExits.isEmpty());
   508             try {
   509                 alive = true;
   510                 scanStat(tree.body);
   512                 if (alive && !tree.sym.type.getReturnType().hasTag(VOID))
   513                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   515                 List<PendingExit> exits = pendingExits.toList();
   516                 pendingExits = new ListBuffer<>();
   517                 while (exits.nonEmpty()) {
   518                     PendingExit exit = exits.head;
   519                     exits = exits.tail;
   520                     Assert.check(exit.tree.hasTag(RETURN));
   521                 }
   522             } finally {
   523                 lint = lintPrev;
   524             }
   525         }
   527         public void visitVarDef(JCVariableDecl tree) {
   528             if (tree.init != null) {
   529                 Lint lintPrev = lint;
   530                 lint = lint.augment(tree.sym);
   531                 try{
   532                     scan(tree.init);
   533                 } finally {
   534                     lint = lintPrev;
   535                 }
   536             }
   537         }
   539         public void visitBlock(JCBlock tree) {
   540             scanStats(tree.stats);
   541         }
   543         public void visitDoLoop(JCDoWhileLoop tree) {
   544             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   545             pendingExits = new ListBuffer<>();
   546             scanStat(tree.body);
   547             alive |= resolveContinues(tree);
   548             scan(tree.cond);
   549             alive = alive && !tree.cond.type.isTrue();
   550             alive |= resolveBreaks(tree, prevPendingExits);
   551         }
   553         public void visitWhileLoop(JCWhileLoop tree) {
   554             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   555             pendingExits = new ListBuffer<>();
   556             scan(tree.cond);
   557             alive = !tree.cond.type.isFalse();
   558             scanStat(tree.body);
   559             alive |= resolveContinues(tree);
   560             alive = resolveBreaks(tree, prevPendingExits) ||
   561                 !tree.cond.type.isTrue();
   562         }
   564         public void visitForLoop(JCForLoop tree) {
   565             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   566             scanStats(tree.init);
   567             pendingExits = new ListBuffer<>();
   568             if (tree.cond != null) {
   569                 scan(tree.cond);
   570                 alive = !tree.cond.type.isFalse();
   571             } else {
   572                 alive = true;
   573             }
   574             scanStat(tree.body);
   575             alive |= resolveContinues(tree);
   576             scan(tree.step);
   577             alive = resolveBreaks(tree, prevPendingExits) ||
   578                 tree.cond != null && !tree.cond.type.isTrue();
   579         }
   581         public void visitForeachLoop(JCEnhancedForLoop tree) {
   582             visitVarDef(tree.var);
   583             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   584             scan(tree.expr);
   585             pendingExits = new ListBuffer<>();
   586             scanStat(tree.body);
   587             alive |= resolveContinues(tree);
   588             resolveBreaks(tree, prevPendingExits);
   589             alive = true;
   590         }
   592         public void visitLabelled(JCLabeledStatement tree) {
   593             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   594             pendingExits = new ListBuffer<>();
   595             scanStat(tree.body);
   596             alive |= resolveBreaks(tree, prevPendingExits);
   597         }
   599         public void visitSwitch(JCSwitch tree) {
   600             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   601             pendingExits = new ListBuffer<>();
   602             scan(tree.selector);
   603             boolean hasDefault = false;
   604             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   605                 alive = true;
   606                 JCCase c = l.head;
   607                 if (c.pat == null)
   608                     hasDefault = true;
   609                 else
   610                     scan(c.pat);
   611                 scanStats(c.stats);
   612                 // Warn about fall-through if lint switch fallthrough enabled.
   613                 if (alive &&
   614                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   615                     c.stats.nonEmpty() && l.tail.nonEmpty())
   616                     log.warning(Lint.LintCategory.FALLTHROUGH,
   617                                 l.tail.head.pos(),
   618                                 "possible.fall-through.into.case");
   619             }
   620             if (!hasDefault) {
   621                 alive = true;
   622             }
   623             alive |= resolveBreaks(tree, prevPendingExits);
   624         }
   626         public void visitTry(JCTry tree) {
   627             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   628             pendingExits = new ListBuffer<>();
   629             for (JCTree resource : tree.resources) {
   630                 if (resource instanceof JCVariableDecl) {
   631                     JCVariableDecl vdecl = (JCVariableDecl) resource;
   632                     visitVarDef(vdecl);
   633                 } else if (resource instanceof JCExpression) {
   634                     scan((JCExpression) resource);
   635                 } else {
   636                     throw new AssertionError(tree);  // parser error
   637                 }
   638             }
   640             scanStat(tree.body);
   641             boolean aliveEnd = alive;
   643             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   644                 alive = true;
   645                 JCVariableDecl param = l.head.param;
   646                 scan(param);
   647                 scanStat(l.head.body);
   648                 aliveEnd |= alive;
   649             }
   650             if (tree.finalizer != null) {
   651                 ListBuffer<PendingExit> exits = pendingExits;
   652                 pendingExits = prevPendingExits;
   653                 alive = true;
   654                 scanStat(tree.finalizer);
   655                 tree.finallyCanCompleteNormally = alive;
   656                 if (!alive) {
   657                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
   658                         log.warning(Lint.LintCategory.FINALLY,
   659                                 TreeInfo.diagEndPos(tree.finalizer),
   660                                 "finally.cannot.complete");
   661                     }
   662                 } else {
   663                     while (exits.nonEmpty()) {
   664                         pendingExits.append(exits.next());
   665                     }
   666                     alive = aliveEnd;
   667                 }
   668             } else {
   669                 alive = aliveEnd;
   670                 ListBuffer<PendingExit> exits = pendingExits;
   671                 pendingExits = prevPendingExits;
   672                 while (exits.nonEmpty()) pendingExits.append(exits.next());
   673             }
   674         }
   676         @Override
   677         public void visitIf(JCIf tree) {
   678             scan(tree.cond);
   679             scanStat(tree.thenpart);
   680             if (tree.elsepart != null) {
   681                 boolean aliveAfterThen = alive;
   682                 alive = true;
   683                 scanStat(tree.elsepart);
   684                 alive = alive | aliveAfterThen;
   685             } else {
   686                 alive = true;
   687             }
   688         }
   690         public void visitBreak(JCBreak tree) {
   691             recordExit(new PendingExit(tree));
   692         }
   694         public void visitContinue(JCContinue tree) {
   695             recordExit(new PendingExit(tree));
   696         }
   698         public void visitReturn(JCReturn tree) {
   699             scan(tree.expr);
   700             recordExit(new PendingExit(tree));
   701         }
   703         public void visitThrow(JCThrow tree) {
   704             scan(tree.expr);
   705             markDead();
   706         }
   708         public void visitApply(JCMethodInvocation tree) {
   709             scan(tree.meth);
   710             scan(tree.args);
   711         }
   713         public void visitNewClass(JCNewClass tree) {
   714             scan(tree.encl);
   715             scan(tree.args);
   716             if (tree.def != null) {
   717                 scan(tree.def);
   718             }
   719         }
   721         @Override
   722         public void visitLambda(JCLambda tree) {
   723             if (tree.type != null &&
   724                     tree.type.isErroneous()) {
   725                 return;
   726             }
   728             ListBuffer<PendingExit> prevPending = pendingExits;
   729             boolean prevAlive = alive;
   730             try {
   731                 pendingExits = new ListBuffer<>();
   732                 alive = true;
   733                 scanStat(tree.body);
   734                 tree.canCompleteNormally = alive;
   735             }
   736             finally {
   737                 pendingExits = prevPending;
   738                 alive = prevAlive;
   739             }
   740         }
   742         public void visitTopLevel(JCCompilationUnit tree) {
   743             // Do nothing for TopLevel since each class is visited individually
   744         }
   746     /**************************************************************************
   747      * main method
   748      *************************************************************************/
   750         /** Perform definite assignment/unassignment analysis on a tree.
   751          */
   752         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   753             analyzeTree(env, env.tree, make);
   754         }
   755         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
   756             try {
   757                 attrEnv = env;
   758                 Flow.this.make = make;
   759                 pendingExits = new ListBuffer<>();
   760                 alive = true;
   761                 scan(tree);
   762             } finally {
   763                 pendingExits = null;
   764                 Flow.this.make = null;
   765             }
   766         }
   767     }
   769     /**
   770      * This pass implements the second step of the dataflow analysis, namely
   771      * the exception analysis. This is to ensure that every checked exception that is
   772      * thrown is declared or caught. The analyzer uses some info that has been set by
   773      * the liveliness analyzer.
   774      */
   775     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   777         /** A flag that indicates whether the last statement could
   778          *  complete normally.
   779          */
   780         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   782         /** The current class being defined.
   783          */
   784         JCClassDecl classDef;
   786         /** The list of possibly thrown declarable exceptions.
   787          */
   788         List<Type> thrown;
   790         /** The list of exceptions that are either caught or declared to be
   791          *  thrown.
   792          */
   793         List<Type> caught;
   795         class FlowPendingExit extends BaseAnalyzer.PendingExit {
   797             Type thrown;
   799             FlowPendingExit(JCTree tree, Type thrown) {
   800                 super(tree);
   801                 this.thrown = thrown;
   802             }
   803         }
   805         @Override
   806         void markDead() {
   807             //do nothing
   808         }
   810         /*-------------------- Exceptions ----------------------*/
   812         /** Complain that pending exceptions are not caught.
   813          */
   814         void errorUncaught() {
   815             for (FlowPendingExit exit = pendingExits.next();
   816                  exit != null;
   817                  exit = pendingExits.next()) {
   818                 if (classDef != null &&
   819                     classDef.pos == exit.tree.pos) {
   820                     log.error(exit.tree.pos(),
   821                             "unreported.exception.default.constructor",
   822                             exit.thrown);
   823                 } else if (exit.tree.hasTag(VARDEF) &&
   824                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   825                     log.error(exit.tree.pos(),
   826                             "unreported.exception.implicit.close",
   827                             exit.thrown,
   828                             ((JCVariableDecl)exit.tree).sym.name);
   829                 } else {
   830                     log.error(exit.tree.pos(),
   831                             "unreported.exception.need.to.catch.or.throw",
   832                             exit.thrown);
   833                 }
   834             }
   835         }
   837         /** Record that exception is potentially thrown and check that it
   838          *  is caught.
   839          */
   840         void markThrown(JCTree tree, Type exc) {
   841             if (!chk.isUnchecked(tree.pos(), exc)) {
   842                 if (!chk.isHandled(exc, caught)) {
   843                     pendingExits.append(new FlowPendingExit(tree, exc));
   844                 }
   845                 thrown = chk.incl(exc, thrown);
   846             }
   847         }
   849     /*************************************************************************
   850      * Visitor methods for statements and definitions
   851      *************************************************************************/
   853         /* ------------ Visitor methods for various sorts of trees -------------*/
   855         public void visitClassDef(JCClassDecl tree) {
   856             if (tree.sym == null) return;
   858             JCClassDecl classDefPrev = classDef;
   859             List<Type> thrownPrev = thrown;
   860             List<Type> caughtPrev = caught;
   861             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   862             Lint lintPrev = lint;
   864             pendingExits = new ListBuffer<FlowPendingExit>();
   865             if (tree.name != names.empty) {
   866                 caught = List.nil();
   867             }
   868             classDef = tree;
   869             thrown = List.nil();
   870             lint = lint.augment(tree.sym);
   872             try {
   873                 // process all the static initializers
   874                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   875                     if (!l.head.hasTag(METHODDEF) &&
   876                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   877                         scan(l.head);
   878                         errorUncaught();
   879                     }
   880                 }
   882                 // add intersection of all thrown clauses of initial constructors
   883                 // to set of caught exceptions, unless class is anonymous.
   884                 if (tree.name != names.empty) {
   885                     boolean firstConstructor = true;
   886                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   887                         if (TreeInfo.isInitialConstructor(l.head)) {
   888                             List<Type> mthrown =
   889                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
   890                             if (firstConstructor) {
   891                                 caught = mthrown;
   892                                 firstConstructor = false;
   893                             } else {
   894                                 caught = chk.intersect(mthrown, caught);
   895                             }
   896                         }
   897                     }
   898                 }
   900                 // process all the instance initializers
   901                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   902                     if (!l.head.hasTag(METHODDEF) &&
   903                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   904                         scan(l.head);
   905                         errorUncaught();
   906                     }
   907                 }
   909                 // in an anonymous class, add the set of thrown exceptions to
   910                 // the throws clause of the synthetic constructor and propagate
   911                 // outwards.
   912                 // Changing the throws clause on the fly is okay here because
   913                 // the anonymous constructor can't be invoked anywhere else,
   914                 // and its type hasn't been cached.
   915                 if (tree.name == names.empty) {
   916                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   917                         if (TreeInfo.isInitialConstructor(l.head)) {
   918                             JCMethodDecl mdef = (JCMethodDecl)l.head;
   919                             mdef.thrown = make.Types(thrown);
   920                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
   921                         }
   922                     }
   923                     thrownPrev = chk.union(thrown, thrownPrev);
   924                 }
   926                 // process all the methods
   927                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   928                     if (l.head.hasTag(METHODDEF)) {
   929                         scan(l.head);
   930                         errorUncaught();
   931                     }
   932                 }
   934                 thrown = thrownPrev;
   935             } finally {
   936                 pendingExits = pendingExitsPrev;
   937                 caught = caughtPrev;
   938                 classDef = classDefPrev;
   939                 lint = lintPrev;
   940             }
   941         }
   943         public void visitMethodDef(JCMethodDecl tree) {
   944             if (tree.body == null) return;
   946             List<Type> caughtPrev = caught;
   947             List<Type> mthrown = tree.sym.type.getThrownTypes();
   948             Lint lintPrev = lint;
   950             lint = lint.augment(tree.sym);
   952             Assert.check(pendingExits.isEmpty());
   954             try {
   955                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   956                     JCVariableDecl def = l.head;
   957                     scan(def);
   958                 }
   959                 if (TreeInfo.isInitialConstructor(tree))
   960                     caught = chk.union(caught, mthrown);
   961                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   962                     caught = mthrown;
   963                 // else we are in an instance initializer block;
   964                 // leave caught unchanged.
   966                 scan(tree.body);
   968                 List<FlowPendingExit> exits = pendingExits.toList();
   969                 pendingExits = new ListBuffer<FlowPendingExit>();
   970                 while (exits.nonEmpty()) {
   971                     FlowPendingExit exit = exits.head;
   972                     exits = exits.tail;
   973                     if (exit.thrown == null) {
   974                         Assert.check(exit.tree.hasTag(RETURN));
   975                     } else {
   976                         // uncaught throws will be reported later
   977                         pendingExits.append(exit);
   978                     }
   979                 }
   980             } finally {
   981                 caught = caughtPrev;
   982                 lint = lintPrev;
   983             }
   984         }
   986         public void visitVarDef(JCVariableDecl tree) {
   987             if (tree.init != null) {
   988                 Lint lintPrev = lint;
   989                 lint = lint.augment(tree.sym);
   990                 try{
   991                     scan(tree.init);
   992                 } finally {
   993                     lint = lintPrev;
   994                 }
   995             }
   996         }
   998         public void visitBlock(JCBlock tree) {
   999             scan(tree.stats);
  1002         public void visitDoLoop(JCDoWhileLoop tree) {
  1003             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1004             pendingExits = new ListBuffer<FlowPendingExit>();
  1005             scan(tree.body);
  1006             resolveContinues(tree);
  1007             scan(tree.cond);
  1008             resolveBreaks(tree, prevPendingExits);
  1011         public void visitWhileLoop(JCWhileLoop tree) {
  1012             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1013             pendingExits = new ListBuffer<FlowPendingExit>();
  1014             scan(tree.cond);
  1015             scan(tree.body);
  1016             resolveContinues(tree);
  1017             resolveBreaks(tree, prevPendingExits);
  1020         public void visitForLoop(JCForLoop tree) {
  1021             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1022             scan(tree.init);
  1023             pendingExits = new ListBuffer<FlowPendingExit>();
  1024             if (tree.cond != null) {
  1025                 scan(tree.cond);
  1027             scan(tree.body);
  1028             resolveContinues(tree);
  1029             scan(tree.step);
  1030             resolveBreaks(tree, prevPendingExits);
  1033         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1034             visitVarDef(tree.var);
  1035             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1036             scan(tree.expr);
  1037             pendingExits = new ListBuffer<FlowPendingExit>();
  1038             scan(tree.body);
  1039             resolveContinues(tree);
  1040             resolveBreaks(tree, prevPendingExits);
  1043         public void visitLabelled(JCLabeledStatement tree) {
  1044             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1045             pendingExits = new ListBuffer<FlowPendingExit>();
  1046             scan(tree.body);
  1047             resolveBreaks(tree, prevPendingExits);
  1050         public void visitSwitch(JCSwitch tree) {
  1051             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1052             pendingExits = new ListBuffer<FlowPendingExit>();
  1053             scan(tree.selector);
  1054             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1055                 JCCase c = l.head;
  1056                 if (c.pat != null) {
  1057                     scan(c.pat);
  1059                 scan(c.stats);
  1061             resolveBreaks(tree, prevPendingExits);
  1064         public void visitTry(JCTry tree) {
  1065             List<Type> caughtPrev = caught;
  1066             List<Type> thrownPrev = thrown;
  1067             thrown = List.nil();
  1068             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1069                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1070                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1071                         List.of(l.head.param.vartype);
  1072                 for (JCExpression ct : subClauses) {
  1073                     caught = chk.incl(ct.type, caught);
  1077             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1078             pendingExits = new ListBuffer<FlowPendingExit>();
  1079             for (JCTree resource : tree.resources) {
  1080                 if (resource instanceof JCVariableDecl) {
  1081                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1082                     visitVarDef(vdecl);
  1083                 } else if (resource instanceof JCExpression) {
  1084                     scan((JCExpression) resource);
  1085                 } else {
  1086                     throw new AssertionError(tree);  // parser error
  1089             for (JCTree resource : tree.resources) {
  1090                 List<Type> closeableSupertypes = resource.type.isCompound() ?
  1091                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
  1092                     List.of(resource.type);
  1093                 for (Type sup : closeableSupertypes) {
  1094                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
  1095                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
  1096                                 attrEnv,
  1097                                 sup,
  1098                                 names.close,
  1099                                 List.<Type>nil(),
  1100                                 List.<Type>nil());
  1101                         Type mt = types.memberType(resource.type, closeMethod);
  1102                         if (closeMethod.kind == MTH) {
  1103                             for (Type t : mt.getThrownTypes()) {
  1104                                 markThrown(resource, t);
  1110             scan(tree.body);
  1111             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1112                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1113                 thrown;
  1114             thrown = thrownPrev;
  1115             caught = caughtPrev;
  1117             List<Type> caughtInTry = List.nil();
  1118             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1119                 JCVariableDecl param = l.head.param;
  1120                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1121                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1122                         List.of(l.head.param.vartype);
  1123                 List<Type> ctypes = List.nil();
  1124                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
  1125                 for (JCExpression ct : subClauses) {
  1126                     Type exc = ct.type;
  1127                     if (exc != syms.unknownType) {
  1128                         ctypes = ctypes.append(exc);
  1129                         if (types.isSameType(exc, syms.objectType))
  1130                             continue;
  1131                         checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
  1132                         caughtInTry = chk.incl(exc, caughtInTry);
  1135                 scan(param);
  1136                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1137                 scan(l.head.body);
  1138                 preciseRethrowTypes.remove(param.sym);
  1140             if (tree.finalizer != null) {
  1141                 List<Type> savedThrown = thrown;
  1142                 thrown = List.nil();
  1143                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1144                 pendingExits = prevPendingExits;
  1145                 scan(tree.finalizer);
  1146                 if (!tree.finallyCanCompleteNormally) {
  1147                     // discard exits and exceptions from try and finally
  1148                     thrown = chk.union(thrown, thrownPrev);
  1149                 } else {
  1150                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1151                     thrown = chk.union(thrown, savedThrown);
  1152                     // FIX: this doesn't preserve source order of exits in catch
  1153                     // versus finally!
  1154                     while (exits.nonEmpty()) {
  1155                         pendingExits.append(exits.next());
  1158             } else {
  1159                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1160                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1161                 pendingExits = prevPendingExits;
  1162                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1166         @Override
  1167         public void visitIf(JCIf tree) {
  1168             scan(tree.cond);
  1169             scan(tree.thenpart);
  1170             if (tree.elsepart != null) {
  1171                 scan(tree.elsepart);
  1175         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1176             if (chk.subset(exc, caughtInTry)) {
  1177                 log.error(pos, "except.already.caught", exc);
  1178             } else if (!chk.isUnchecked(pos, exc) &&
  1179                     !isExceptionOrThrowable(exc) &&
  1180                     !chk.intersects(exc, thrownInTry)) {
  1181                 log.error(pos, "except.never.thrown.in.try", exc);
  1182             } else if (allowImprovedCatchAnalysis) {
  1183                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
  1184                 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
  1185                 // unchecked exception, the result list would not be empty, as the augmented
  1186                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
  1187                 // exception, that would have been covered in the branch above
  1188                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
  1189                         !isExceptionOrThrowable(exc)) {
  1190                     String key = catchableThrownTypes.length() == 1 ?
  1191                             "unreachable.catch" :
  1192                             "unreachable.catch.1";
  1193                     log.warning(pos, key, catchableThrownTypes);
  1197         //where
  1198             private boolean isExceptionOrThrowable(Type exc) {
  1199                 return exc.tsym == syms.throwableType.tsym ||
  1200                     exc.tsym == syms.exceptionType.tsym;
  1203         public void visitBreak(JCBreak tree) {
  1204             recordExit(new FlowPendingExit(tree, null));
  1207         public void visitContinue(JCContinue tree) {
  1208             recordExit(new FlowPendingExit(tree, null));
  1211         public void visitReturn(JCReturn tree) {
  1212             scan(tree.expr);
  1213             recordExit(new FlowPendingExit(tree, null));
  1216         public void visitThrow(JCThrow tree) {
  1217             scan(tree.expr);
  1218             Symbol sym = TreeInfo.symbol(tree.expr);
  1219             if (sym != null &&
  1220                 sym.kind == VAR &&
  1221                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
  1222                 preciseRethrowTypes.get(sym) != null &&
  1223                 allowImprovedRethrowAnalysis) {
  1224                 for (Type t : preciseRethrowTypes.get(sym)) {
  1225                     markThrown(tree, t);
  1228             else {
  1229                 markThrown(tree, tree.expr.type);
  1231             markDead();
  1234         public void visitApply(JCMethodInvocation tree) {
  1235             scan(tree.meth);
  1236             scan(tree.args);
  1237             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
  1238                 markThrown(tree, l.head);
  1241         public void visitNewClass(JCNewClass tree) {
  1242             scan(tree.encl);
  1243             scan(tree.args);
  1244            // scan(tree.def);
  1245             for (List<Type> l = tree.constructorType.getThrownTypes();
  1246                  l.nonEmpty();
  1247                  l = l.tail) {
  1248                 markThrown(tree, l.head);
  1250             List<Type> caughtPrev = caught;
  1251             try {
  1252                 // If the new class expression defines an anonymous class,
  1253                 // analysis of the anonymous constructor may encounter thrown
  1254                 // types which are unsubstituted type variables.
  1255                 // However, since the constructor's actual thrown types have
  1256                 // already been marked as thrown, it is safe to simply include
  1257                 // each of the constructor's formal thrown types in the set of
  1258                 // 'caught/declared to be thrown' types, for the duration of
  1259                 // the class def analysis.
  1260                 if (tree.def != null)
  1261                     for (List<Type> l = tree.constructor.type.getThrownTypes();
  1262                          l.nonEmpty();
  1263                          l = l.tail) {
  1264                         caught = chk.incl(l.head, caught);
  1266                 scan(tree.def);
  1268             finally {
  1269                 caught = caughtPrev;
  1273         @Override
  1274         public void visitLambda(JCLambda tree) {
  1275             if (tree.type != null &&
  1276                     tree.type.isErroneous()) {
  1277                 return;
  1279             List<Type> prevCaught = caught;
  1280             List<Type> prevThrown = thrown;
  1281             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1282             try {
  1283                 pendingExits = new ListBuffer<>();
  1284                 caught = tree.getDescriptorType(types).getThrownTypes();
  1285                 thrown = List.nil();
  1286                 scan(tree.body);
  1287                 List<FlowPendingExit> exits = pendingExits.toList();
  1288                 pendingExits = new ListBuffer<FlowPendingExit>();
  1289                 while (exits.nonEmpty()) {
  1290                     FlowPendingExit exit = exits.head;
  1291                     exits = exits.tail;
  1292                     if (exit.thrown == null) {
  1293                         Assert.check(exit.tree.hasTag(RETURN));
  1294                     } else {
  1295                         // uncaught throws will be reported later
  1296                         pendingExits.append(exit);
  1300                 errorUncaught();
  1301             } finally {
  1302                 pendingExits = prevPending;
  1303                 caught = prevCaught;
  1304                 thrown = prevThrown;
  1308         public void visitTopLevel(JCCompilationUnit tree) {
  1309             // Do nothing for TopLevel since each class is visited individually
  1312     /**************************************************************************
  1313      * main method
  1314      *************************************************************************/
  1316         /** Perform definite assignment/unassignment analysis on a tree.
  1317          */
  1318         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1319             analyzeTree(env, env.tree, make);
  1321         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  1322             try {
  1323                 attrEnv = env;
  1324                 Flow.this.make = make;
  1325                 pendingExits = new ListBuffer<FlowPendingExit>();
  1326                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1327                 this.thrown = this.caught = null;
  1328                 this.classDef = null;
  1329                 scan(tree);
  1330             } finally {
  1331                 pendingExits = null;
  1332                 Flow.this.make = null;
  1333                 this.thrown = this.caught = null;
  1334                 this.classDef = null;
  1339     /**
  1340      * Specialized pass that performs inference of thrown types for lambdas.
  1341      */
  1342     class LambdaFlowAnalyzer extends FlowAnalyzer {
  1343         List<Type> inferredThrownTypes;
  1344         boolean inLambda;
  1345         @Override
  1346         public void visitLambda(JCLambda tree) {
  1347             if ((tree.type != null &&
  1348                     tree.type.isErroneous()) || inLambda) {
  1349                 return;
  1351             List<Type> prevCaught = caught;
  1352             List<Type> prevThrown = thrown;
  1353             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1354             inLambda = true;
  1355             try {
  1356                 pendingExits = new ListBuffer<>();
  1357                 caught = List.of(syms.throwableType);
  1358                 thrown = List.nil();
  1359                 scan(tree.body);
  1360                 inferredThrownTypes = thrown;
  1361             } finally {
  1362                 pendingExits = prevPending;
  1363                 caught = prevCaught;
  1364                 thrown = prevThrown;
  1365                 inLambda = false;
  1368         @Override
  1369         public void visitClassDef(JCClassDecl tree) {
  1370             //skip
  1374     /**
  1375      * This pass implements (i) definite assignment analysis, which ensures that
  1376      * each variable is assigned when used and (ii) definite unassignment analysis,
  1377      * which ensures that no final variable is assigned more than once. This visitor
  1378      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1379      * effectively-final local variables/parameters.
  1380      */
  1382     public class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
  1383         /** The set of definitely assigned variables.
  1384          */
  1385         final Bits inits;
  1387         /** The set of definitely unassigned variables.
  1388          */
  1389         final Bits uninits;
  1391         /** The set of variables that are definitely unassigned everywhere
  1392          *  in current try block. This variable is maintained lazily; it is
  1393          *  updated only when something gets removed from uninits,
  1394          *  typically by being assigned in reachable code.  To obtain the
  1395          *  correct set of variables which are definitely unassigned
  1396          *  anywhere in current try block, intersect uninitsTry and
  1397          *  uninits.
  1398          */
  1399         final Bits uninitsTry;
  1401         /** When analyzing a condition, inits and uninits are null.
  1402          *  Instead we have:
  1403          */
  1404         final Bits initsWhenTrue;
  1405         final Bits initsWhenFalse;
  1406         final Bits uninitsWhenTrue;
  1407         final Bits uninitsWhenFalse;
  1409         /** A mapping from addresses to variable symbols.
  1410          */
  1411         protected JCVariableDecl[] vardecls;
  1413         /** The current class being defined.
  1414          */
  1415         JCClassDecl classDef;
  1417         /** The first variable sequence number in this class definition.
  1418          */
  1419         int firstadr;
  1421         /** The next available variable sequence number.
  1422          */
  1423         protected int nextadr;
  1425         /** The first variable sequence number in a block that can return.
  1426          */
  1427         protected int returnadr;
  1429         /** The list of unreferenced automatic resources.
  1430          */
  1431         Scope unrefdResources;
  1433         /** Modified when processing a loop body the second time for DU analysis. */
  1434         FlowKind flowKind = FlowKind.NORMAL;
  1436         /** The starting position of the analyzed tree */
  1437         int startPos;
  1439         public class AssignPendingExit extends BaseAnalyzer.PendingExit {
  1441             final Bits inits;
  1442             final Bits uninits;
  1443             final Bits exit_inits = new Bits(true);
  1444             final Bits exit_uninits = new Bits(true);
  1446             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
  1447                 super(tree);
  1448                 this.inits = inits;
  1449                 this.uninits = uninits;
  1450                 this.exit_inits.assign(inits);
  1451                 this.exit_uninits.assign(uninits);
  1454             @Override
  1455             void resolveJump() {
  1456                 inits.andSet(exit_inits);
  1457                 uninits.andSet(exit_uninits);
  1461         public AssignAnalyzer() {
  1462             this.inits = new Bits();
  1463             uninits = new Bits();
  1464             uninitsTry = new Bits();
  1465             initsWhenTrue = new Bits(true);
  1466             initsWhenFalse = new Bits(true);
  1467             uninitsWhenTrue = new Bits(true);
  1468             uninitsWhenFalse = new Bits(true);
  1471         private boolean isInitialConstructor = false;
  1473         @Override
  1474          void markDead() {
  1475             if (!isInitialConstructor) {
  1476                 inits.inclRange(returnadr, nextadr);
  1477             } else {
  1478                 for (int address = returnadr; address < nextadr; address++) {
  1479                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
  1480                         inits.incl(address);
  1484             uninits.inclRange(returnadr, nextadr);
  1487         /*-------------- Processing variables ----------------------*/
  1489         /** Do we need to track init/uninit state of this symbol?
  1490          *  I.e. is symbol either a local or a blank final variable?
  1491          */
  1492         protected boolean trackable(VarSymbol sym) {
  1493             return
  1494                 sym.pos >= startPos &&
  1495                 ((sym.owner.kind == MTH ||
  1496                 isFinalUninitializedField(sym)));
  1499         boolean isFinalUninitializedField(VarSymbol sym) {
  1500             return sym.owner.kind == TYP &&
  1501                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1502                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
  1505         boolean isFinalUninitializedStaticField(VarSymbol sym) {
  1506             return isFinalUninitializedField(sym) && sym.isStatic();
  1509         /** Initialize new trackable variable by setting its address field
  1510          *  to the next available sequence number and entering it under that
  1511          *  index into the vars array.
  1512          */
  1513         void newVar(JCVariableDecl varDecl) {
  1514             VarSymbol sym = varDecl.sym;
  1515             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
  1516             if ((sym.flags() & FINAL) == 0) {
  1517                 sym.flags_field |= EFFECTIVELY_FINAL;
  1519             sym.adr = nextadr;
  1520             vardecls[nextadr] = varDecl;
  1521             inits.excl(nextadr);
  1522             uninits.incl(nextadr);
  1523             nextadr++;
  1526         /** Record an initialization of a trackable variable.
  1527          */
  1528         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1529             if (sym.adr >= firstadr && trackable(sym)) {
  1530                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
  1531                     if (!uninits.isMember(sym.adr)) {
  1532                         //assignment targeting an effectively final variable
  1533                         //makes the variable lose its status of effectively final
  1534                         //if the variable is _not_ definitively unassigned
  1535                         sym.flags_field &= ~EFFECTIVELY_FINAL;
  1536                     } else {
  1537                         uninit(sym);
  1539                 } else if ((sym.flags() & FINAL) != 0) {
  1540                     if ((sym.flags() & PARAMETER) != 0) {
  1541                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  1542                             log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
  1543                         } else {
  1544                             log.error(pos, "final.parameter.may.not.be.assigned",
  1545                                   sym);
  1547                     } else if (!uninits.isMember(sym.adr)) {
  1548                         log.error(pos, flowKind.errKey, sym);
  1549                     } else {
  1550                         uninit(sym);
  1553                 inits.incl(sym.adr);
  1554             } else if ((sym.flags() & FINAL) != 0) {
  1555                 log.error(pos, "var.might.already.be.assigned", sym);
  1558         //where
  1559             void uninit(VarSymbol sym) {
  1560                 if (!inits.isMember(sym.adr)) {
  1561                     // reachable assignment
  1562                     uninits.excl(sym.adr);
  1563                     uninitsTry.excl(sym.adr);
  1564                 } else {
  1565                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
  1566                     uninits.excl(sym.adr);
  1570         /** If tree is either a simple name or of the form this.name or
  1571          *  C.this.name, and tree represents a trackable variable,
  1572          *  record an initialization of the variable.
  1573          */
  1574         void letInit(JCTree tree) {
  1575             tree = TreeInfo.skipParens(tree);
  1576             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  1577                 Symbol sym = TreeInfo.symbol(tree);
  1578                 if (sym.kind == VAR) {
  1579                     letInit(tree.pos(), (VarSymbol)sym);
  1584         /** Check that trackable variable is initialized.
  1585          */
  1586         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
  1587             checkInit(pos, sym, "var.might.not.have.been.initialized");
  1590         void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
  1591             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  1592                 trackable(sym) &&
  1593                 !inits.isMember(sym.adr)) {
  1594                 log.error(pos, errkey, sym);
  1595                 inits.incl(sym.adr);
  1599         /** Utility method to reset several Bits instances.
  1600          */
  1601         private void resetBits(Bits... bits) {
  1602             for (Bits b : bits) {
  1603                 b.reset();
  1607         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
  1608          */
  1609         void split(boolean setToNull) {
  1610             initsWhenFalse.assign(inits);
  1611             uninitsWhenFalse.assign(uninits);
  1612             initsWhenTrue.assign(inits);
  1613             uninitsWhenTrue.assign(uninits);
  1614             if (setToNull) {
  1615                 resetBits(inits, uninits);
  1619         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
  1620          */
  1621         protected void merge() {
  1622             inits.assign(initsWhenFalse.andSet(initsWhenTrue));
  1623             uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
  1626     /* ************************************************************************
  1627      * Visitor methods for statements and definitions
  1628      *************************************************************************/
  1630         /** Analyze an expression. Make sure to set (un)inits rather than
  1631          *  (un)initsWhenTrue(WhenFalse) on exit.
  1632          */
  1633         void scanExpr(JCTree tree) {
  1634             if (tree != null) {
  1635                 scan(tree);
  1636                 if (inits.isReset()) {
  1637                     merge();
  1642         /** Analyze a list of expressions.
  1643          */
  1644         void scanExprs(List<? extends JCExpression> trees) {
  1645             if (trees != null)
  1646                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
  1647                     scanExpr(l.head);
  1650         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
  1651          *  rather than (un)inits on exit.
  1652          */
  1653         void scanCond(JCTree tree) {
  1654             if (tree.type.isFalse()) {
  1655                 if (inits.isReset()) merge();
  1656                 initsWhenTrue.assign(inits);
  1657                 initsWhenTrue.inclRange(firstadr, nextadr);
  1658                 uninitsWhenTrue.assign(uninits);
  1659                 uninitsWhenTrue.inclRange(firstadr, nextadr);
  1660                 initsWhenFalse.assign(inits);
  1661                 uninitsWhenFalse.assign(uninits);
  1662             } else if (tree.type.isTrue()) {
  1663                 if (inits.isReset()) merge();
  1664                 initsWhenFalse.assign(inits);
  1665                 initsWhenFalse.inclRange(firstadr, nextadr);
  1666                 uninitsWhenFalse.assign(uninits);
  1667                 uninitsWhenFalse.inclRange(firstadr, nextadr);
  1668                 initsWhenTrue.assign(inits);
  1669                 uninitsWhenTrue.assign(uninits);
  1670             } else {
  1671                 scan(tree);
  1672                 if (!inits.isReset())
  1673                     split(tree.type != syms.unknownType);
  1675             if (tree.type != syms.unknownType) {
  1676                 resetBits(inits, uninits);
  1680         /* ------------ Visitor methods for various sorts of trees -------------*/
  1682         public void visitClassDef(JCClassDecl tree) {
  1683             if (tree.sym == null) {
  1684                 return;
  1687             Lint lintPrev = lint;
  1688             lint = lint.augment(tree.sym);
  1689             try {
  1690                 if (tree.sym == null) {
  1691                     return;
  1694                 JCClassDecl classDefPrev = classDef;
  1695                 int firstadrPrev = firstadr;
  1696                 int nextadrPrev = nextadr;
  1697                 ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
  1699                 pendingExits = new ListBuffer<>();
  1700                 if (tree.name != names.empty) {
  1701                     firstadr = nextadr;
  1703                 classDef = tree;
  1704                 try {
  1705                     // define all the static fields
  1706                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1707                         if (l.head.hasTag(VARDEF)) {
  1708                             JCVariableDecl def = (JCVariableDecl)l.head;
  1709                             if ((def.mods.flags & STATIC) != 0) {
  1710                                 VarSymbol sym = def.sym;
  1711                                 if (trackable(sym)) {
  1712                                     newVar(def);
  1718                     // process all the static initializers
  1719                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1720                         if (!l.head.hasTag(METHODDEF) &&
  1721                             (TreeInfo.flags(l.head) & STATIC) != 0) {
  1722                             scan(l.head);
  1726                     // define all the instance fields
  1727                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1728                         if (l.head.hasTag(VARDEF)) {
  1729                             JCVariableDecl def = (JCVariableDecl)l.head;
  1730                             if ((def.mods.flags & STATIC) == 0) {
  1731                                 VarSymbol sym = def.sym;
  1732                                 if (trackable(sym)) {
  1733                                     newVar(def);
  1738                     // process all the instance initializers
  1739                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1740                         if (!l.head.hasTag(METHODDEF) &&
  1741                             (TreeInfo.flags(l.head) & STATIC) == 0) {
  1742                             scan(l.head);
  1746                     // process all the methods
  1747                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1748                         if (l.head.hasTag(METHODDEF)) {
  1749                             scan(l.head);
  1752                 } finally {
  1753                     pendingExits = pendingExitsPrev;
  1754                     nextadr = nextadrPrev;
  1755                     firstadr = firstadrPrev;
  1756                     classDef = classDefPrev;
  1758             } finally {
  1759                 lint = lintPrev;
  1763         public void visitMethodDef(JCMethodDecl tree) {
  1764             if (tree.body == null) {
  1765                 return;
  1768             /*  MemberEnter can generate synthetic methods ignore them
  1769              */
  1770             if ((tree.sym.flags() & SYNTHETIC) != 0) {
  1771                 return;
  1774             Lint lintPrev = lint;
  1775             lint = lint.augment(tree.sym);
  1776             try {
  1777                 if (tree.body == null) {
  1778                     return;
  1780                 /*  Ignore synthetic methods, except for translated lambda methods.
  1781                  */
  1782                 if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
  1783                     return;
  1786                 final Bits initsPrev = new Bits(inits);
  1787                 final Bits uninitsPrev = new Bits(uninits);
  1788                 int nextadrPrev = nextadr;
  1789                 int firstadrPrev = firstadr;
  1790                 int returnadrPrev = returnadr;
  1792                 Assert.check(pendingExits.isEmpty());
  1793                 boolean lastInitialConstructor = isInitialConstructor;
  1794                 try {
  1795                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
  1797                     if (!isInitialConstructor) {
  1798                         firstadr = nextadr;
  1800                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  1801                         JCVariableDecl def = l.head;
  1802                         scan(def);
  1803                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
  1804                         /*  If we are executing the code from Gen, then there can be
  1805                          *  synthetic or mandated variables, ignore them.
  1806                          */
  1807                         initParam(def);
  1809                     // else we are in an instance initializer block;
  1810                     // leave caught unchanged.
  1811                     scan(tree.body);
  1813                     if (isInitialConstructor) {
  1814                         boolean isSynthesized = (tree.sym.flags() &
  1815                                                  GENERATEDCONSTR) != 0;
  1816                         for (int i = firstadr; i < nextadr; i++) {
  1817                             JCVariableDecl vardecl = vardecls[i];
  1818                             VarSymbol var = vardecl.sym;
  1819                             if (var.owner == classDef.sym) {
  1820                                 // choose the diagnostic position based on whether
  1821                                 // the ctor is default(synthesized) or not
  1822                                 if (isSynthesized) {
  1823                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
  1824                                         var, "var.not.initialized.in.default.constructor");
  1825                                 } else {
  1826                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
  1831                     List<AssignPendingExit> exits = pendingExits.toList();
  1832                     pendingExits = new ListBuffer<>();
  1833                     while (exits.nonEmpty()) {
  1834                         AssignPendingExit exit = exits.head;
  1835                         exits = exits.tail;
  1836                         Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1837                         if (isInitialConstructor) {
  1838                             inits.assign(exit.exit_inits);
  1839                             for (int i = firstadr; i < nextadr; i++) {
  1840                                 checkInit(exit.tree.pos(), vardecls[i].sym);
  1844                 } finally {
  1845                     inits.assign(initsPrev);
  1846                     uninits.assign(uninitsPrev);
  1847                     nextadr = nextadrPrev;
  1848                     firstadr = firstadrPrev;
  1849                     returnadr = returnadrPrev;
  1850                     isInitialConstructor = lastInitialConstructor;
  1852             } finally {
  1853                 lint = lintPrev;
  1857         protected void initParam(JCVariableDecl def) {
  1858             inits.incl(def.sym.adr);
  1859             uninits.excl(def.sym.adr);
  1862         public void visitVarDef(JCVariableDecl tree) {
  1863             Lint lintPrev = lint;
  1864             lint = lint.augment(tree.sym);
  1865             try{
  1866                 boolean track = trackable(tree.sym);
  1867                 if (track && tree.sym.owner.kind == MTH) {
  1868                     newVar(tree);
  1870                 if (tree.init != null) {
  1871                     scanExpr(tree.init);
  1872                     if (track) {
  1873                         letInit(tree.pos(), tree.sym);
  1876             } finally {
  1877                 lint = lintPrev;
  1881         public void visitBlock(JCBlock tree) {
  1882             int nextadrPrev = nextadr;
  1883             scan(tree.stats);
  1884             nextadr = nextadrPrev;
  1887         public void visitDoLoop(JCDoWhileLoop tree) {
  1888             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1889             FlowKind prevFlowKind = flowKind;
  1890             flowKind = FlowKind.NORMAL;
  1891             final Bits initsSkip = new Bits(true);
  1892             final Bits uninitsSkip = new Bits(true);
  1893             pendingExits = new ListBuffer<>();
  1894             int prevErrors = log.nerrors;
  1895             do {
  1896                 final Bits uninitsEntry = new Bits(uninits);
  1897                 uninitsEntry.excludeFrom(nextadr);
  1898                 scan(tree.body);
  1899                 resolveContinues(tree);
  1900                 scanCond(tree.cond);
  1901                 if (!flowKind.isFinal()) {
  1902                     initsSkip.assign(initsWhenFalse);
  1903                     uninitsSkip.assign(uninitsWhenFalse);
  1905                 if (log.nerrors !=  prevErrors ||
  1906                     flowKind.isFinal() ||
  1907                     new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1908                     break;
  1909                 inits.assign(initsWhenTrue);
  1910                 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
  1911                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1912             } while (true);
  1913             flowKind = prevFlowKind;
  1914             inits.assign(initsSkip);
  1915             uninits.assign(uninitsSkip);
  1916             resolveBreaks(tree, prevPendingExits);
  1919         public void visitWhileLoop(JCWhileLoop tree) {
  1920             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1921             FlowKind prevFlowKind = flowKind;
  1922             flowKind = FlowKind.NORMAL;
  1923             final Bits initsSkip = new Bits(true);
  1924             final Bits uninitsSkip = new Bits(true);
  1925             pendingExits = new ListBuffer<>();
  1926             int prevErrors = log.nerrors;
  1927             final Bits uninitsEntry = new Bits(uninits);
  1928             uninitsEntry.excludeFrom(nextadr);
  1929             do {
  1930                 scanCond(tree.cond);
  1931                 if (!flowKind.isFinal()) {
  1932                     initsSkip.assign(initsWhenFalse) ;
  1933                     uninitsSkip.assign(uninitsWhenFalse);
  1935                 inits.assign(initsWhenTrue);
  1936                 uninits.assign(uninitsWhenTrue);
  1937                 scan(tree.body);
  1938                 resolveContinues(tree);
  1939                 if (log.nerrors != prevErrors ||
  1940                     flowKind.isFinal() ||
  1941                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
  1942                     break;
  1944                 uninits.assign(uninitsEntry.andSet(uninits));
  1945                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1946             } while (true);
  1947             flowKind = prevFlowKind;
  1948             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
  1949             //branch is not taken AND if it's DA/DU before any break statement
  1950             inits.assign(initsSkip);
  1951             uninits.assign(uninitsSkip);
  1952             resolveBreaks(tree, prevPendingExits);
  1955         public void visitForLoop(JCForLoop tree) {
  1956             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1957             FlowKind prevFlowKind = flowKind;
  1958             flowKind = FlowKind.NORMAL;
  1959             int nextadrPrev = nextadr;
  1960             scan(tree.init);
  1961             final Bits initsSkip = new Bits(true);
  1962             final Bits uninitsSkip = new Bits(true);
  1963             pendingExits = new ListBuffer<>();
  1964             int prevErrors = log.nerrors;
  1965             do {
  1966                 final Bits uninitsEntry = new Bits(uninits);
  1967                 uninitsEntry.excludeFrom(nextadr);
  1968                 if (tree.cond != null) {
  1969                     scanCond(tree.cond);
  1970                     if (!flowKind.isFinal()) {
  1971                         initsSkip.assign(initsWhenFalse);
  1972                         uninitsSkip.assign(uninitsWhenFalse);
  1974                     inits.assign(initsWhenTrue);
  1975                     uninits.assign(uninitsWhenTrue);
  1976                 } else if (!flowKind.isFinal()) {
  1977                     initsSkip.assign(inits);
  1978                     initsSkip.inclRange(firstadr, nextadr);
  1979                     uninitsSkip.assign(uninits);
  1980                     uninitsSkip.inclRange(firstadr, nextadr);
  1982                 scan(tree.body);
  1983                 resolveContinues(tree);
  1984                 scan(tree.step);
  1985                 if (log.nerrors != prevErrors ||
  1986                     flowKind.isFinal() ||
  1987                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  1988                     break;
  1989                 uninits.assign(uninitsEntry.andSet(uninits));
  1990                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1991             } while (true);
  1992             flowKind = prevFlowKind;
  1993             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
  1994             //branch is not taken AND if it's DA/DU before any break statement
  1995             inits.assign(initsSkip);
  1996             uninits.assign(uninitsSkip);
  1997             resolveBreaks(tree, prevPendingExits);
  1998             nextadr = nextadrPrev;
  2001         public void visitForeachLoop(JCEnhancedForLoop tree) {
  2002             visitVarDef(tree.var);
  2004             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2005             FlowKind prevFlowKind = flowKind;
  2006             flowKind = FlowKind.NORMAL;
  2007             int nextadrPrev = nextadr;
  2008             scan(tree.expr);
  2009             final Bits initsStart = new Bits(inits);
  2010             final Bits uninitsStart = new Bits(uninits);
  2012             letInit(tree.pos(), tree.var.sym);
  2013             pendingExits = new ListBuffer<>();
  2014             int prevErrors = log.nerrors;
  2015             do {
  2016                 final Bits uninitsEntry = new Bits(uninits);
  2017                 uninitsEntry.excludeFrom(nextadr);
  2018                 scan(tree.body);
  2019                 resolveContinues(tree);
  2020                 if (log.nerrors != prevErrors ||
  2021                     flowKind.isFinal() ||
  2022                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  2023                     break;
  2024                 uninits.assign(uninitsEntry.andSet(uninits));
  2025                 flowKind = FlowKind.SPECULATIVE_LOOP;
  2026             } while (true);
  2027             flowKind = prevFlowKind;
  2028             inits.assign(initsStart);
  2029             uninits.assign(uninitsStart.andSet(uninits));
  2030             resolveBreaks(tree, prevPendingExits);
  2031             nextadr = nextadrPrev;
  2034         public void visitLabelled(JCLabeledStatement tree) {
  2035             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2036             pendingExits = new ListBuffer<>();
  2037             scan(tree.body);
  2038             resolveBreaks(tree, prevPendingExits);
  2041         public void visitSwitch(JCSwitch tree) {
  2042             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2043             pendingExits = new ListBuffer<>();
  2044             int nextadrPrev = nextadr;
  2045             scanExpr(tree.selector);
  2046             final Bits initsSwitch = new Bits(inits);
  2047             final Bits uninitsSwitch = new Bits(uninits);
  2048             boolean hasDefault = false;
  2049             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  2050                 inits.assign(initsSwitch);
  2051                 uninits.assign(uninits.andSet(uninitsSwitch));
  2052                 JCCase c = l.head;
  2053                 if (c.pat == null) {
  2054                     hasDefault = true;
  2055                 } else {
  2056                     scanExpr(c.pat);
  2058                 if (hasDefault) {
  2059                     inits.assign(initsSwitch);
  2060                     uninits.assign(uninits.andSet(uninitsSwitch));
  2062                 scan(c.stats);
  2063                 addVars(c.stats, initsSwitch, uninitsSwitch);
  2064                 if (!hasDefault) {
  2065                     inits.assign(initsSwitch);
  2066                     uninits.assign(uninits.andSet(uninitsSwitch));
  2068                 // Warn about fall-through if lint switch fallthrough enabled.
  2070             if (!hasDefault) {
  2071                 inits.andSet(initsSwitch);
  2073             resolveBreaks(tree, prevPendingExits);
  2074             nextadr = nextadrPrev;
  2076         // where
  2077             /** Add any variables defined in stats to inits and uninits. */
  2078             private void addVars(List<JCStatement> stats, final Bits inits,
  2079                                         final Bits uninits) {
  2080                 for (;stats.nonEmpty(); stats = stats.tail) {
  2081                     JCTree stat = stats.head;
  2082                     if (stat.hasTag(VARDEF)) {
  2083                         int adr = ((JCVariableDecl) stat).sym.adr;
  2084                         inits.excl(adr);
  2085                         uninits.incl(adr);
  2090         public void visitTry(JCTry tree) {
  2091             ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
  2092             final Bits uninitsTryPrev = new Bits(uninitsTry);
  2093             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  2094             pendingExits = new ListBuffer<>();
  2095             final Bits initsTry = new Bits(inits);
  2096             uninitsTry.assign(uninits);
  2097             for (JCTree resource : tree.resources) {
  2098                 if (resource instanceof JCVariableDecl) {
  2099                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  2100                     visitVarDef(vdecl);
  2101                     unrefdResources.enter(vdecl.sym);
  2102                     resourceVarDecls.append(vdecl);
  2103                 } else if (resource instanceof JCExpression) {
  2104                     scanExpr((JCExpression) resource);
  2105                 } else {
  2106                     throw new AssertionError(tree);  // parser error
  2109             scan(tree.body);
  2110             uninitsTry.andSet(uninits);
  2111             final Bits initsEnd = new Bits(inits);
  2112             final Bits uninitsEnd = new Bits(uninits);
  2113             int nextadrCatch = nextadr;
  2115             if (!resourceVarDecls.isEmpty() &&
  2116                     lint.isEnabled(Lint.LintCategory.TRY)) {
  2117                 for (JCVariableDecl resVar : resourceVarDecls) {
  2118                     if (unrefdResources.includes(resVar.sym)) {
  2119                         log.warning(Lint.LintCategory.TRY, resVar.pos(),
  2120                                     "try.resource.not.referenced", resVar.sym);
  2121                         unrefdResources.remove(resVar.sym);
  2126             /*  The analysis of each catch should be independent.
  2127              *  Each one should have the same initial values of inits and
  2128              *  uninits.
  2129              */
  2130             final Bits initsCatchPrev = new Bits(initsTry);
  2131             final Bits uninitsCatchPrev = new Bits(uninitsTry);
  2133             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  2134                 JCVariableDecl param = l.head.param;
  2135                 inits.assign(initsCatchPrev);
  2136                 uninits.assign(uninitsCatchPrev);
  2137                 scan(param);
  2138                 /* If this is a TWR and we are executing the code from Gen,
  2139                  * then there can be synthetic variables, ignore them.
  2140                  */
  2141                 initParam(param);
  2142                 scan(l.head.body);
  2143                 initsEnd.andSet(inits);
  2144                 uninitsEnd.andSet(uninits);
  2145                 nextadr = nextadrCatch;
  2147             if (tree.finalizer != null) {
  2148                 inits.assign(initsTry);
  2149                 uninits.assign(uninitsTry);
  2150                 ListBuffer<AssignPendingExit> exits = pendingExits;
  2151                 pendingExits = prevPendingExits;
  2152                 scan(tree.finalizer);
  2153                 if (!tree.finallyCanCompleteNormally) {
  2154                     // discard exits and exceptions from try and finally
  2155                 } else {
  2156                     uninits.andSet(uninitsEnd);
  2157                     // FIX: this doesn't preserve source order of exits in catch
  2158                     // versus finally!
  2159                     while (exits.nonEmpty()) {
  2160                         AssignPendingExit exit = exits.next();
  2161                         if (exit.exit_inits != null) {
  2162                             exit.exit_inits.orSet(inits);
  2163                             exit.exit_uninits.andSet(uninits);
  2165                         pendingExits.append(exit);
  2167                     inits.orSet(initsEnd);
  2169             } else {
  2170                 inits.assign(initsEnd);
  2171                 uninits.assign(uninitsEnd);
  2172                 ListBuffer<AssignPendingExit> exits = pendingExits;
  2173                 pendingExits = prevPendingExits;
  2174                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  2176             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  2179         public void visitConditional(JCConditional tree) {
  2180             scanCond(tree.cond);
  2181             final Bits initsBeforeElse = new Bits(initsWhenFalse);
  2182             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
  2183             inits.assign(initsWhenTrue);
  2184             uninits.assign(uninitsWhenTrue);
  2185             if (tree.truepart.type.hasTag(BOOLEAN) &&
  2186                 tree.falsepart.type.hasTag(BOOLEAN)) {
  2187                 // if b and c are boolean valued, then
  2188                 // v is (un)assigned after a?b:c when true iff
  2189                 //    v is (un)assigned after b when true and
  2190                 //    v is (un)assigned after c when true
  2191                 scanCond(tree.truepart);
  2192                 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
  2193                 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
  2194                 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
  2195                 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
  2196                 inits.assign(initsBeforeElse);
  2197                 uninits.assign(uninitsBeforeElse);
  2198                 scanCond(tree.falsepart);
  2199                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
  2200                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
  2201                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
  2202                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
  2203             } else {
  2204                 scanExpr(tree.truepart);
  2205                 final Bits initsAfterThen = new Bits(inits);
  2206                 final Bits uninitsAfterThen = new Bits(uninits);
  2207                 inits.assign(initsBeforeElse);
  2208                 uninits.assign(uninitsBeforeElse);
  2209                 scanExpr(tree.falsepart);
  2210                 inits.andSet(initsAfterThen);
  2211                 uninits.andSet(uninitsAfterThen);
  2215         public void visitIf(JCIf tree) {
  2216             scanCond(tree.cond);
  2217             final Bits initsBeforeElse = new Bits(initsWhenFalse);
  2218             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
  2219             inits.assign(initsWhenTrue);
  2220             uninits.assign(uninitsWhenTrue);
  2221             scan(tree.thenpart);
  2222             if (tree.elsepart != null) {
  2223                 final Bits initsAfterThen = new Bits(inits);
  2224                 final Bits uninitsAfterThen = new Bits(uninits);
  2225                 inits.assign(initsBeforeElse);
  2226                 uninits.assign(uninitsBeforeElse);
  2227                 scan(tree.elsepart);
  2228                 inits.andSet(initsAfterThen);
  2229                 uninits.andSet(uninitsAfterThen);
  2230             } else {
  2231                 inits.andSet(initsBeforeElse);
  2232                 uninits.andSet(uninitsBeforeElse);
  2236         @Override
  2237         public void visitBreak(JCBreak tree) {
  2238             recordExit(new AssignPendingExit(tree, inits, uninits));
  2241         @Override
  2242         public void visitContinue(JCContinue tree) {
  2243             recordExit(new AssignPendingExit(tree, inits, uninits));
  2246         @Override
  2247         public void visitReturn(JCReturn tree) {
  2248             scanExpr(tree.expr);
  2249             recordExit(new AssignPendingExit(tree, inits, uninits));
  2252         public void visitThrow(JCThrow tree) {
  2253             scanExpr(tree.expr);
  2254             markDead();
  2257         public void visitApply(JCMethodInvocation tree) {
  2258             scanExpr(tree.meth);
  2259             scanExprs(tree.args);
  2262         public void visitNewClass(JCNewClass tree) {
  2263             scanExpr(tree.encl);
  2264             scanExprs(tree.args);
  2265             scan(tree.def);
  2268         @Override
  2269         public void visitLambda(JCLambda tree) {
  2270             final Bits prevUninits = new Bits(uninits);
  2271             final Bits prevInits = new Bits(inits);
  2272             int returnadrPrev = returnadr;
  2273             ListBuffer<AssignPendingExit> prevPending = pendingExits;
  2274             try {
  2275                 returnadr = nextadr;
  2276                 pendingExits = new ListBuffer<>();
  2277                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  2278                     JCVariableDecl def = l.head;
  2279                     scan(def);
  2280                     inits.incl(def.sym.adr);
  2281                     uninits.excl(def.sym.adr);
  2283                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
  2284                     scanExpr(tree.body);
  2285                 } else {
  2286                     scan(tree.body);
  2289             finally {
  2290                 returnadr = returnadrPrev;
  2291                 uninits.assign(prevUninits);
  2292                 inits.assign(prevInits);
  2293                 pendingExits = prevPending;
  2297         public void visitNewArray(JCNewArray tree) {
  2298             scanExprs(tree.dims);
  2299             scanExprs(tree.elems);
  2302         public void visitAssert(JCAssert tree) {
  2303             final Bits initsExit = new Bits(inits);
  2304             final Bits uninitsExit = new Bits(uninits);
  2305             scanCond(tree.cond);
  2306             uninitsExit.andSet(uninitsWhenTrue);
  2307             if (tree.detail != null) {
  2308                 inits.assign(initsWhenFalse);
  2309                 uninits.assign(uninitsWhenFalse);
  2310                 scanExpr(tree.detail);
  2312             inits.assign(initsExit);
  2313             uninits.assign(uninitsExit);
  2316         public void visitAssign(JCAssign tree) {
  2317             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2318             if (!isIdentOrThisDotIdent(lhs))
  2319                 scanExpr(lhs);
  2320             scanExpr(tree.rhs);
  2321             letInit(lhs);
  2323         private boolean isIdentOrThisDotIdent(JCTree lhs) {
  2324             if (lhs.hasTag(IDENT))
  2325                 return true;
  2326             if (!lhs.hasTag(SELECT))
  2327                 return false;
  2329             JCFieldAccess fa = (JCFieldAccess)lhs;
  2330             return fa.selected.hasTag(IDENT) &&
  2331                    ((JCIdent)fa.selected).name == names._this;
  2334         // check fields accessed through this.<field> are definitely
  2335         // assigned before reading their value
  2336         public void visitSelect(JCFieldAccess tree) {
  2337             super.visitSelect(tree);
  2338             if (enforceThisDotInit &&
  2339                 tree.selected.hasTag(IDENT) &&
  2340                 ((JCIdent)tree.selected).name == names._this &&
  2341                 tree.sym.kind == VAR)
  2343                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2347         public void visitAssignop(JCAssignOp tree) {
  2348             scanExpr(tree.lhs);
  2349             scanExpr(tree.rhs);
  2350             letInit(tree.lhs);
  2353         public void visitUnary(JCUnary tree) {
  2354             switch (tree.getTag()) {
  2355             case NOT:
  2356                 scanCond(tree.arg);
  2357                 final Bits t = new Bits(initsWhenFalse);
  2358                 initsWhenFalse.assign(initsWhenTrue);
  2359                 initsWhenTrue.assign(t);
  2360                 t.assign(uninitsWhenFalse);
  2361                 uninitsWhenFalse.assign(uninitsWhenTrue);
  2362                 uninitsWhenTrue.assign(t);
  2363                 break;
  2364             case PREINC: case POSTINC:
  2365             case PREDEC: case POSTDEC:
  2366                 scanExpr(tree.arg);
  2367                 letInit(tree.arg);
  2368                 break;
  2369             default:
  2370                 scanExpr(tree.arg);
  2374         public void visitBinary(JCBinary tree) {
  2375             switch (tree.getTag()) {
  2376             case AND:
  2377                 scanCond(tree.lhs);
  2378                 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
  2379                 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
  2380                 inits.assign(initsWhenTrue);
  2381                 uninits.assign(uninitsWhenTrue);
  2382                 scanCond(tree.rhs);
  2383                 initsWhenFalse.andSet(initsWhenFalseLeft);
  2384                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
  2385                 break;
  2386             case OR:
  2387                 scanCond(tree.lhs);
  2388                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
  2389                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
  2390                 inits.assign(initsWhenFalse);
  2391                 uninits.assign(uninitsWhenFalse);
  2392                 scanCond(tree.rhs);
  2393                 initsWhenTrue.andSet(initsWhenTrueLeft);
  2394                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
  2395                 break;
  2396             default:
  2397                 scanExpr(tree.lhs);
  2398                 scanExpr(tree.rhs);
  2402         public void visitIdent(JCIdent tree) {
  2403             if (tree.sym.kind == VAR) {
  2404                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2405                 referenced(tree.sym);
  2409         void referenced(Symbol sym) {
  2410             unrefdResources.remove(sym);
  2413         public void visitAnnotatedType(JCAnnotatedType tree) {
  2414             // annotations don't get scanned
  2415             tree.underlyingType.accept(this);
  2418         public void visitTopLevel(JCCompilationUnit tree) {
  2419             // Do nothing for TopLevel since each class is visited individually
  2422     /**************************************************************************
  2423      * main method
  2424      *************************************************************************/
  2426         /** Perform definite assignment/unassignment analysis on a tree.
  2427          */
  2428         public void analyzeTree(Env<?> env) {
  2429             analyzeTree(env, env.tree);
  2432         public void analyzeTree(Env<?> env, JCTree tree) {
  2433             try {
  2434                 startPos = tree.pos().getStartPosition();
  2436                 if (vardecls == null)
  2437                     vardecls = new JCVariableDecl[32];
  2438                 else
  2439                     for (int i=0; i<vardecls.length; i++)
  2440                         vardecls[i] = null;
  2441                 firstadr = 0;
  2442                 nextadr = 0;
  2443                 pendingExits = new ListBuffer<>();
  2444                 this.classDef = null;
  2445                 unrefdResources = new Scope(env.enclClass.sym);
  2446                 scan(tree);
  2447             } finally {
  2448                 // note that recursive invocations of this method fail hard
  2449                 startPos = -1;
  2450                 resetBits(inits, uninits, uninitsTry, initsWhenTrue,
  2451                         initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
  2452                 if (vardecls != null) {
  2453                     for (int i=0; i<vardecls.length; i++)
  2454                         vardecls[i] = null;
  2456                 firstadr = 0;
  2457                 nextadr = 0;
  2458                 pendingExits = null;
  2459                 this.classDef = null;
  2460                 unrefdResources = null;
  2465     /**
  2466      * This pass implements the last step of the dataflow analysis, namely
  2467      * the effectively-final analysis check. This checks that every local variable
  2468      * reference from a lambda body/local inner class is either final or effectively final.
  2469      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2470      * AssignAnalyzer.
  2471      */
  2472     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
  2474         JCTree currentTree; //local class or lambda
  2476         @Override
  2477         void markDead() {
  2478             //do nothing
  2481         @SuppressWarnings("fallthrough")
  2482         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
  2483             if (currentTree != null &&
  2484                     sym.owner.kind == MTH &&
  2485                     sym.pos < currentTree.getStartPosition()) {
  2486                 switch (currentTree.getTag()) {
  2487                     case CLASSDEF:
  2488                         if (!allowEffectivelyFinalInInnerClasses) {
  2489                             if ((sym.flags() & FINAL) == 0) {
  2490                                 reportInnerClsNeedsFinalError(pos, sym);
  2492                             break;
  2494                     case LAMBDA:
  2495                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
  2496                            reportEffectivelyFinalError(pos, sym);
  2502         @SuppressWarnings("fallthrough")
  2503         void letInit(JCTree tree) {
  2504             tree = TreeInfo.skipParens(tree);
  2505             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  2506                 Symbol sym = TreeInfo.symbol(tree);
  2507                 if (currentTree != null &&
  2508                         sym.kind == VAR &&
  2509                         sym.owner.kind == MTH &&
  2510                         ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
  2511                     switch (currentTree.getTag()) {
  2512                         case CLASSDEF:
  2513                             if (!allowEffectivelyFinalInInnerClasses) {
  2514                                 reportInnerClsNeedsFinalError(tree, sym);
  2515                                 break;
  2517                         case LAMBDA:
  2518                             reportEffectivelyFinalError(tree, sym);
  2524         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
  2525             String subKey = currentTree.hasTag(LAMBDA) ?
  2526                   "lambda"  : "inner.cls";
  2527             log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
  2530         void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
  2531             log.error(pos,
  2532                     "local.var.accessed.from.icls.needs.final",
  2533                     sym);
  2536     /*************************************************************************
  2537      * Visitor methods for statements and definitions
  2538      *************************************************************************/
  2540         /* ------------ Visitor methods for various sorts of trees -------------*/
  2542         public void visitClassDef(JCClassDecl tree) {
  2543             JCTree prevTree = currentTree;
  2544             try {
  2545                 currentTree = tree.sym.isLocal() ? tree : null;
  2546                 super.visitClassDef(tree);
  2547             } finally {
  2548                 currentTree = prevTree;
  2552         @Override
  2553         public void visitLambda(JCLambda tree) {
  2554             JCTree prevTree = currentTree;
  2555             try {
  2556                 currentTree = tree;
  2557                 super.visitLambda(tree);
  2558             } finally {
  2559                 currentTree = prevTree;
  2563         @Override
  2564         public void visitIdent(JCIdent tree) {
  2565             if (tree.sym.kind == VAR) {
  2566                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
  2570         public void visitAssign(JCAssign tree) {
  2571             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2572             if (!(lhs instanceof JCIdent)) {
  2573                 scan(lhs);
  2575             scan(tree.rhs);
  2576             letInit(lhs);
  2579         public void visitAssignop(JCAssignOp tree) {
  2580             scan(tree.lhs);
  2581             scan(tree.rhs);
  2582             letInit(tree.lhs);
  2585         public void visitUnary(JCUnary tree) {
  2586             switch (tree.getTag()) {
  2587                 case PREINC: case POSTINC:
  2588                 case PREDEC: case POSTDEC:
  2589                     scan(tree.arg);
  2590                     letInit(tree.arg);
  2591                     break;
  2592                 default:
  2593                     scan(tree.arg);
  2597         public void visitTopLevel(JCCompilationUnit tree) {
  2598             // Do nothing for TopLevel since each class is visited individually
  2601     /**************************************************************************
  2602      * main method
  2603      *************************************************************************/
  2605         /** Perform definite assignment/unassignment analysis on a tree.
  2606          */
  2607         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2608             analyzeTree(env, env.tree, make);
  2610         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2611             try {
  2612                 attrEnv = env;
  2613                 Flow.this.make = make;
  2614                 pendingExits = new ListBuffer<>();
  2615                 scan(tree);
  2616             } finally {
  2617                 pendingExits = null;
  2618                 Flow.this.make = null;

mercurial