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

Fri, 09 May 2014 20:33:21 -0700

author
mfang
date
Fri, 09 May 2014 20:33:21 -0700
changeset 2388
0add97444be9
parent 2252
fa004631cf00
child 2370
acd64168cf8b
permissions
-rw-r--r--

8041424: 8u20 l10n resource file translation update 1
Reviewed-by: naoto, yhuang

     1 /*
     2  * Copyright (c) 1999, 2014, 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 AliveAlanyzer) 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;
   201     public static Flow instance(Context context) {
   202         Flow instance = context.get(flowKey);
   203         if (instance == null)
   204             instance = new Flow(context);
   205         return instance;
   206     }
   208     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   209         new AliveAnalyzer().analyzeTree(env, make);
   210         new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
   211         new FlowAnalyzer().analyzeTree(env, make);
   212         new CaptureAnalyzer().analyzeTree(env, make);
   213     }
   215     public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
   216         Log.DiagnosticHandler diagHandler = null;
   217         //we need to disable diagnostics temporarily; the problem is that if
   218         //a lambda expression contains e.g. an unreachable statement, an error
   219         //message will be reported and will cause compilation to skip the flow analyis
   220         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
   221         //related errors, which will allow for more errors to be detected
   222         if (!speculative) {
   223             diagHandler = new Log.DiscardDiagnosticHandler(log);
   224         }
   225         try {
   226             new AliveAnalyzer().analyzeTree(env, that, make);
   227         } finally {
   228             if (!speculative) {
   229                 log.popDiagnosticHandler(diagHandler);
   230             }
   231         }
   232     }
   234     public List<Type> analyzeLambdaThrownTypes(Env<AttrContext> env, JCLambda that, TreeMaker make) {
   235         //we need to disable diagnostics temporarily; the problem is that if
   236         //a lambda expression contains e.g. an unreachable statement, an error
   237         //message will be reported and will cause compilation to skip the flow analyis
   238         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
   239         //related errors, which will allow for more errors to be detected
   240         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
   241         try {
   242             new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
   243             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
   244             flowAnalyzer.analyzeTree(env, that, make);
   245             return flowAnalyzer.inferredThrownTypes;
   246         } finally {
   247             log.popDiagnosticHandler(diagHandler);
   248         }
   249     }
   251     /**
   252      * Definite assignment scan mode
   253      */
   254     enum FlowKind {
   255         /**
   256          * This is the normal DA/DU analysis mode
   257          */
   258         NORMAL("var.might.already.be.assigned", false),
   259         /**
   260          * This is the speculative DA/DU analysis mode used to speculatively
   261          * derive assertions within loop bodies
   262          */
   263         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
   265         final String errKey;
   266         final boolean isFinal;
   268         FlowKind(String errKey, boolean isFinal) {
   269             this.errKey = errKey;
   270             this.isFinal = isFinal;
   271         }
   273         boolean isFinal() {
   274             return isFinal;
   275         }
   276     }
   278     protected Flow(Context context) {
   279         context.put(flowKey, this);
   280         names = Names.instance(context);
   281         log = Log.instance(context);
   282         syms = Symtab.instance(context);
   283         types = Types.instance(context);
   284         chk = Check.instance(context);
   285         lint = Lint.instance(context);
   286         rs = Resolve.instance(context);
   287         diags = JCDiagnostic.Factory.instance(context);
   288         Source source = Source.instance(context);
   289         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   290         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   291         allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
   292     }
   294     /**
   295      * Base visitor class for all visitors implementing dataflow analysis logic.
   296      * This class define the shared logic for handling jumps (break/continue statements).
   297      */
   298     static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
   300         enum JumpKind {
   301             BREAK(JCTree.Tag.BREAK) {
   302                 @Override
   303                 JCTree getTarget(JCTree tree) {
   304                     return ((JCBreak)tree).target;
   305                 }
   306             },
   307             CONTINUE(JCTree.Tag.CONTINUE) {
   308                 @Override
   309                 JCTree getTarget(JCTree tree) {
   310                     return ((JCContinue)tree).target;
   311                 }
   312             };
   314             final JCTree.Tag treeTag;
   316             private JumpKind(Tag treeTag) {
   317                 this.treeTag = treeTag;
   318             }
   320             abstract JCTree getTarget(JCTree tree);
   321         }
   323         /** The currently pending exits that go from current inner blocks
   324          *  to an enclosing block, in source order.
   325          */
   326         ListBuffer<P> pendingExits;
   328         /** A pending exit.  These are the statements return, break, and
   329          *  continue.  In addition, exception-throwing expressions or
   330          *  statements are put here when not known to be caught.  This
   331          *  will typically result in an error unless it is within a
   332          *  try-finally whose finally block cannot complete normally.
   333          */
   334         static class PendingExit {
   335             JCTree tree;
   337             PendingExit(JCTree tree) {
   338                 this.tree = tree;
   339             }
   341             void resolveJump(JCTree tree) {
   342                 //do nothing
   343             }
   344         }
   346         abstract void markDead(JCTree tree);
   348         /** Record an outward transfer of control. */
   349         void recordExit(JCTree tree, P pe) {
   350             pendingExits.append(pe);
   351             markDead(tree);
   352         }
   354         /** Resolve all jumps of this statement. */
   355         private boolean resolveJump(JCTree tree,
   356                         ListBuffer<P> oldPendingExits,
   357                         JumpKind jk) {
   358             boolean resolved = false;
   359             List<P> exits = pendingExits.toList();
   360             pendingExits = oldPendingExits;
   361             for (; exits.nonEmpty(); exits = exits.tail) {
   362                 P exit = exits.head;
   363                 if (exit.tree.hasTag(jk.treeTag) &&
   364                         jk.getTarget(exit.tree) == tree) {
   365                     exit.resolveJump(tree);
   366                     resolved = true;
   367                 } else {
   368                     pendingExits.append(exit);
   369                 }
   370             }
   371             return resolved;
   372         }
   374         /** Resolve all continues of this statement. */
   375         boolean resolveContinues(JCTree tree) {
   376             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
   377         }
   379         /** Resolve all breaks of this statement. */
   380         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
   381             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   382         }
   384         @Override
   385         public void scan(JCTree tree) {
   386             if (tree != null && (
   387                     tree.type == null ||
   388                     tree.type != Type.stuckType)) {
   389                 super.scan(tree);
   390             }
   391         }
   392     }
   394     /**
   395      * This pass implements the first step of the dataflow analysis, namely
   396      * the liveness analysis check. This checks that every statement is reachable.
   397      * The output of this analysis pass are used by other analyzers. This analyzer
   398      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   399      */
   400     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
   402         /** A flag that indicates whether the last statement could
   403          *  complete normally.
   404          */
   405         private boolean alive;
   407         @Override
   408         void markDead(JCTree tree) {
   409             alive = false;
   410         }
   412     /*************************************************************************
   413      * Visitor methods for statements and definitions
   414      *************************************************************************/
   416         /** Analyze a definition.
   417          */
   418         void scanDef(JCTree tree) {
   419             scanStat(tree);
   420             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
   421                 log.error(tree.pos(),
   422                           "initializer.must.be.able.to.complete.normally");
   423             }
   424         }
   426         /** Analyze a statement. Check that statement is reachable.
   427          */
   428         void scanStat(JCTree tree) {
   429             if (!alive && tree != null) {
   430                 log.error(tree.pos(), "unreachable.stmt");
   431                 if (!tree.hasTag(SKIP)) alive = true;
   432             }
   433             scan(tree);
   434         }
   436         /** Analyze list of statements.
   437          */
   438         void scanStats(List<? extends JCStatement> trees) {
   439             if (trees != null)
   440                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
   441                     scanStat(l.head);
   442         }
   444         /* ------------ Visitor methods for various sorts of trees -------------*/
   446         public void visitClassDef(JCClassDecl tree) {
   447             if (tree.sym == null) return;
   448             boolean alivePrev = alive;
   449             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   450             Lint lintPrev = lint;
   452             pendingExits = new ListBuffer<PendingExit>();
   453             lint = lint.augment(tree.sym);
   455             try {
   456                 // process all the static initializers
   457                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   458                     if (!l.head.hasTag(METHODDEF) &&
   459                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   460                         scanDef(l.head);
   461                     }
   462                 }
   464                 // process all the instance initializers
   465                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   466                     if (!l.head.hasTag(METHODDEF) &&
   467                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   468                         scanDef(l.head);
   469                     }
   470                 }
   472                 // process all the methods
   473                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   474                     if (l.head.hasTag(METHODDEF)) {
   475                         scan(l.head);
   476                     }
   477                 }
   478             } finally {
   479                 pendingExits = pendingExitsPrev;
   480                 alive = alivePrev;
   481                 lint = lintPrev;
   482             }
   483         }
   485         public void visitMethodDef(JCMethodDecl tree) {
   486             if (tree.body == null) return;
   487             Lint lintPrev = lint;
   489             lint = lint.augment(tree.sym);
   491             Assert.check(pendingExits.isEmpty());
   493             try {
   494                 alive = true;
   495                 scanStat(tree.body);
   497                 if (alive && !tree.sym.type.getReturnType().hasTag(VOID))
   498                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   500                 List<PendingExit> exits = pendingExits.toList();
   501                 pendingExits = new ListBuffer<PendingExit>();
   502                 while (exits.nonEmpty()) {
   503                     PendingExit exit = exits.head;
   504                     exits = exits.tail;
   505                     Assert.check(exit.tree.hasTag(RETURN));
   506                 }
   507             } finally {
   508                 lint = lintPrev;
   509             }
   510         }
   512         public void visitVarDef(JCVariableDecl tree) {
   513             if (tree.init != null) {
   514                 Lint lintPrev = lint;
   515                 lint = lint.augment(tree.sym);
   516                 try{
   517                     scan(tree.init);
   518                 } finally {
   519                     lint = lintPrev;
   520                 }
   521             }
   522         }
   524         public void visitBlock(JCBlock tree) {
   525             scanStats(tree.stats);
   526         }
   528         public void visitDoLoop(JCDoWhileLoop tree) {
   529             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   530             pendingExits = new ListBuffer<PendingExit>();
   531             scanStat(tree.body);
   532             alive |= resolveContinues(tree);
   533             scan(tree.cond);
   534             alive = alive && !tree.cond.type.isTrue();
   535             alive |= resolveBreaks(tree, prevPendingExits);
   536         }
   538         public void visitWhileLoop(JCWhileLoop tree) {
   539             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   540             pendingExits = new ListBuffer<PendingExit>();
   541             scan(tree.cond);
   542             alive = !tree.cond.type.isFalse();
   543             scanStat(tree.body);
   544             alive |= resolveContinues(tree);
   545             alive = resolveBreaks(tree, prevPendingExits) ||
   546                 !tree.cond.type.isTrue();
   547         }
   549         public void visitForLoop(JCForLoop tree) {
   550             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   551             scanStats(tree.init);
   552             pendingExits = new ListBuffer<PendingExit>();
   553             if (tree.cond != null) {
   554                 scan(tree.cond);
   555                 alive = !tree.cond.type.isFalse();
   556             } else {
   557                 alive = true;
   558             }
   559             scanStat(tree.body);
   560             alive |= resolveContinues(tree);
   561             scan(tree.step);
   562             alive = resolveBreaks(tree, prevPendingExits) ||
   563                 tree.cond != null && !tree.cond.type.isTrue();
   564         }
   566         public void visitForeachLoop(JCEnhancedForLoop tree) {
   567             visitVarDef(tree.var);
   568             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   569             scan(tree.expr);
   570             pendingExits = new ListBuffer<PendingExit>();
   571             scanStat(tree.body);
   572             alive |= resolveContinues(tree);
   573             resolveBreaks(tree, prevPendingExits);
   574             alive = true;
   575         }
   577         public void visitLabelled(JCLabeledStatement tree) {
   578             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   579             pendingExits = new ListBuffer<PendingExit>();
   580             scanStat(tree.body);
   581             alive |= resolveBreaks(tree, prevPendingExits);
   582         }
   584         public void visitSwitch(JCSwitch tree) {
   585             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   586             pendingExits = new ListBuffer<PendingExit>();
   587             scan(tree.selector);
   588             boolean hasDefault = false;
   589             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   590                 alive = true;
   591                 JCCase c = l.head;
   592                 if (c.pat == null)
   593                     hasDefault = true;
   594                 else
   595                     scan(c.pat);
   596                 scanStats(c.stats);
   597                 // Warn about fall-through if lint switch fallthrough enabled.
   598                 if (alive &&
   599                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   600                     c.stats.nonEmpty() && l.tail.nonEmpty())
   601                     log.warning(Lint.LintCategory.FALLTHROUGH,
   602                                 l.tail.head.pos(),
   603                                 "possible.fall-through.into.case");
   604             }
   605             if (!hasDefault) {
   606                 alive = true;
   607             }
   608             alive |= resolveBreaks(tree, prevPendingExits);
   609         }
   611         public void visitTry(JCTry tree) {
   612             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   613             pendingExits = new ListBuffer<PendingExit>();
   614             for (JCTree resource : tree.resources) {
   615                 if (resource instanceof JCVariableDecl) {
   616                     JCVariableDecl vdecl = (JCVariableDecl) resource;
   617                     visitVarDef(vdecl);
   618                 } else if (resource instanceof JCExpression) {
   619                     scan((JCExpression) resource);
   620                 } else {
   621                     throw new AssertionError(tree);  // parser error
   622                 }
   623             }
   625             scanStat(tree.body);
   626             boolean aliveEnd = alive;
   628             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   629                 alive = true;
   630                 JCVariableDecl param = l.head.param;
   631                 scan(param);
   632                 scanStat(l.head.body);
   633                 aliveEnd |= alive;
   634             }
   635             if (tree.finalizer != null) {
   636                 ListBuffer<PendingExit> exits = pendingExits;
   637                 pendingExits = prevPendingExits;
   638                 alive = true;
   639                 scanStat(tree.finalizer);
   640                 tree.finallyCanCompleteNormally = alive;
   641                 if (!alive) {
   642                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
   643                         log.warning(Lint.LintCategory.FINALLY,
   644                                 TreeInfo.diagEndPos(tree.finalizer),
   645                                 "finally.cannot.complete");
   646                     }
   647                 } else {
   648                     while (exits.nonEmpty()) {
   649                         pendingExits.append(exits.next());
   650                     }
   651                     alive = aliveEnd;
   652                 }
   653             } else {
   654                 alive = aliveEnd;
   655                 ListBuffer<PendingExit> exits = pendingExits;
   656                 pendingExits = prevPendingExits;
   657                 while (exits.nonEmpty()) pendingExits.append(exits.next());
   658             }
   659         }
   661         @Override
   662         public void visitIf(JCIf tree) {
   663             scan(tree.cond);
   664             scanStat(tree.thenpart);
   665             if (tree.elsepart != null) {
   666                 boolean aliveAfterThen = alive;
   667                 alive = true;
   668                 scanStat(tree.elsepart);
   669                 alive = alive | aliveAfterThen;
   670             } else {
   671                 alive = true;
   672             }
   673         }
   675         public void visitBreak(JCBreak tree) {
   676             recordExit(tree, new PendingExit(tree));
   677         }
   679         public void visitContinue(JCContinue tree) {
   680             recordExit(tree, new PendingExit(tree));
   681         }
   683         public void visitReturn(JCReturn tree) {
   684             scan(tree.expr);
   685             recordExit(tree, new PendingExit(tree));
   686         }
   688         public void visitThrow(JCThrow tree) {
   689             scan(tree.expr);
   690             markDead(tree);
   691         }
   693         public void visitApply(JCMethodInvocation tree) {
   694             scan(tree.meth);
   695             scan(tree.args);
   696         }
   698         public void visitNewClass(JCNewClass tree) {
   699             scan(tree.encl);
   700             scan(tree.args);
   701             if (tree.def != null) {
   702                 scan(tree.def);
   703             }
   704         }
   706         @Override
   707         public void visitLambda(JCLambda tree) {
   708             if (tree.type != null &&
   709                     tree.type.isErroneous()) {
   710                 return;
   711             }
   713             ListBuffer<PendingExit> prevPending = pendingExits;
   714             boolean prevAlive = alive;
   715             try {
   716                 pendingExits = new ListBuffer<>();
   717                 alive = true;
   718                 scanStat(tree.body);
   719                 tree.canCompleteNormally = alive;
   720             }
   721             finally {
   722                 pendingExits = prevPending;
   723                 alive = prevAlive;
   724             }
   725         }
   727         public void visitTopLevel(JCCompilationUnit tree) {
   728             // Do nothing for TopLevel since each class is visited individually
   729         }
   731     /**************************************************************************
   732      * main method
   733      *************************************************************************/
   735         /** Perform definite assignment/unassignment analysis on a tree.
   736          */
   737         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   738             analyzeTree(env, env.tree, make);
   739         }
   740         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
   741             try {
   742                 attrEnv = env;
   743                 Flow.this.make = make;
   744                 pendingExits = new ListBuffer<PendingExit>();
   745                 alive = true;
   746                 scan(tree);
   747             } finally {
   748                 pendingExits = null;
   749                 Flow.this.make = null;
   750             }
   751         }
   752     }
   754     /**
   755      * This pass implements the second step of the dataflow analysis, namely
   756      * the exception analysis. This is to ensure that every checked exception that is
   757      * thrown is declared or caught. The analyzer uses some info that has been set by
   758      * the liveliness analyzer.
   759      */
   760     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   762         /** A flag that indicates whether the last statement could
   763          *  complete normally.
   764          */
   765         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   767         /** The current class being defined.
   768          */
   769         JCClassDecl classDef;
   771         /** The list of possibly thrown declarable exceptions.
   772          */
   773         List<Type> thrown;
   775         /** The list of exceptions that are either caught or declared to be
   776          *  thrown.
   777          */
   778         List<Type> caught;
   780         class FlowPendingExit extends BaseAnalyzer.PendingExit {
   782             Type thrown;
   784             FlowPendingExit(JCTree tree, Type thrown) {
   785                 super(tree);
   786                 this.thrown = thrown;
   787             }
   788         }
   790         @Override
   791         void markDead(JCTree tree) {
   792             //do nothing
   793         }
   795         /*-------------------- Exceptions ----------------------*/
   797         /** Complain that pending exceptions are not caught.
   798          */
   799         void errorUncaught() {
   800             for (FlowPendingExit exit = pendingExits.next();
   801                  exit != null;
   802                  exit = pendingExits.next()) {
   803                 if (classDef != null &&
   804                     classDef.pos == exit.tree.pos) {
   805                     log.error(exit.tree.pos(),
   806                             "unreported.exception.default.constructor",
   807                             exit.thrown);
   808                 } else if (exit.tree.hasTag(VARDEF) &&
   809                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   810                     log.error(exit.tree.pos(),
   811                             "unreported.exception.implicit.close",
   812                             exit.thrown,
   813                             ((JCVariableDecl)exit.tree).sym.name);
   814                 } else {
   815                     log.error(exit.tree.pos(),
   816                             "unreported.exception.need.to.catch.or.throw",
   817                             exit.thrown);
   818                 }
   819             }
   820         }
   822         /** Record that exception is potentially thrown and check that it
   823          *  is caught.
   824          */
   825         void markThrown(JCTree tree, Type exc) {
   826             if (!chk.isUnchecked(tree.pos(), exc)) {
   827                 if (!chk.isHandled(exc, caught)) {
   828                     pendingExits.append(new FlowPendingExit(tree, exc));
   829                 }
   830                 thrown = chk.incl(exc, thrown);
   831             }
   832         }
   834     /*************************************************************************
   835      * Visitor methods for statements and definitions
   836      *************************************************************************/
   838         /* ------------ Visitor methods for various sorts of trees -------------*/
   840         public void visitClassDef(JCClassDecl tree) {
   841             if (tree.sym == null) return;
   843             JCClassDecl classDefPrev = classDef;
   844             List<Type> thrownPrev = thrown;
   845             List<Type> caughtPrev = caught;
   846             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   847             Lint lintPrev = lint;
   849             pendingExits = new ListBuffer<FlowPendingExit>();
   850             if (tree.name != names.empty) {
   851                 caught = List.nil();
   852             }
   853             classDef = tree;
   854             thrown = List.nil();
   855             lint = lint.augment(tree.sym);
   857             try {
   858                 // process all the static initializers
   859                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   860                     if (!l.head.hasTag(METHODDEF) &&
   861                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   862                         scan(l.head);
   863                         errorUncaught();
   864                     }
   865                 }
   867                 // add intersection of all thrown clauses of initial constructors
   868                 // to set of caught exceptions, unless class is anonymous.
   869                 if (tree.name != names.empty) {
   870                     boolean firstConstructor = true;
   871                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   872                         if (TreeInfo.isInitialConstructor(l.head)) {
   873                             List<Type> mthrown =
   874                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
   875                             if (firstConstructor) {
   876                                 caught = mthrown;
   877                                 firstConstructor = false;
   878                             } else {
   879                                 caught = chk.intersect(mthrown, caught);
   880                             }
   881                         }
   882                     }
   883                 }
   885                 // process all the instance initializers
   886                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   887                     if (!l.head.hasTag(METHODDEF) &&
   888                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   889                         scan(l.head);
   890                         errorUncaught();
   891                     }
   892                 }
   894                 // in an anonymous class, add the set of thrown exceptions to
   895                 // the throws clause of the synthetic constructor and propagate
   896                 // outwards.
   897                 // Changing the throws clause on the fly is okay here because
   898                 // the anonymous constructor can't be invoked anywhere else,
   899                 // and its type hasn't been cached.
   900                 if (tree.name == names.empty) {
   901                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   902                         if (TreeInfo.isInitialConstructor(l.head)) {
   903                             JCMethodDecl mdef = (JCMethodDecl)l.head;
   904                             mdef.thrown = make.Types(thrown);
   905                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
   906                         }
   907                     }
   908                     thrownPrev = chk.union(thrown, thrownPrev);
   909                 }
   911                 // process all the methods
   912                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   913                     if (l.head.hasTag(METHODDEF)) {
   914                         scan(l.head);
   915                         errorUncaught();
   916                     }
   917                 }
   919                 thrown = thrownPrev;
   920             } finally {
   921                 pendingExits = pendingExitsPrev;
   922                 caught = caughtPrev;
   923                 classDef = classDefPrev;
   924                 lint = lintPrev;
   925             }
   926         }
   928         public void visitMethodDef(JCMethodDecl tree) {
   929             if (tree.body == null) return;
   931             List<Type> caughtPrev = caught;
   932             List<Type> mthrown = tree.sym.type.getThrownTypes();
   933             Lint lintPrev = lint;
   935             lint = lint.augment(tree.sym);
   937             Assert.check(pendingExits.isEmpty());
   939             try {
   940                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   941                     JCVariableDecl def = l.head;
   942                     scan(def);
   943                 }
   944                 if (TreeInfo.isInitialConstructor(tree))
   945                     caught = chk.union(caught, mthrown);
   946                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   947                     caught = mthrown;
   948                 // else we are in an instance initializer block;
   949                 // leave caught unchanged.
   951                 scan(tree.body);
   953                 List<FlowPendingExit> exits = pendingExits.toList();
   954                 pendingExits = new ListBuffer<FlowPendingExit>();
   955                 while (exits.nonEmpty()) {
   956                     FlowPendingExit exit = exits.head;
   957                     exits = exits.tail;
   958                     if (exit.thrown == null) {
   959                         Assert.check(exit.tree.hasTag(RETURN));
   960                     } else {
   961                         // uncaught throws will be reported later
   962                         pendingExits.append(exit);
   963                     }
   964                 }
   965             } finally {
   966                 caught = caughtPrev;
   967                 lint = lintPrev;
   968             }
   969         }
   971         public void visitVarDef(JCVariableDecl tree) {
   972             if (tree.init != null) {
   973                 Lint lintPrev = lint;
   974                 lint = lint.augment(tree.sym);
   975                 try{
   976                     scan(tree.init);
   977                 } finally {
   978                     lint = lintPrev;
   979                 }
   980             }
   981         }
   983         public void visitBlock(JCBlock tree) {
   984             scan(tree.stats);
   985         }
   987         public void visitDoLoop(JCDoWhileLoop tree) {
   988             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   989             pendingExits = new ListBuffer<FlowPendingExit>();
   990             scan(tree.body);
   991             resolveContinues(tree);
   992             scan(tree.cond);
   993             resolveBreaks(tree, prevPendingExits);
   994         }
   996         public void visitWhileLoop(JCWhileLoop tree) {
   997             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   998             pendingExits = new ListBuffer<FlowPendingExit>();
   999             scan(tree.cond);
  1000             scan(tree.body);
  1001             resolveContinues(tree);
  1002             resolveBreaks(tree, prevPendingExits);
  1005         public void visitForLoop(JCForLoop tree) {
  1006             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1007             scan(tree.init);
  1008             pendingExits = new ListBuffer<FlowPendingExit>();
  1009             if (tree.cond != null) {
  1010                 scan(tree.cond);
  1012             scan(tree.body);
  1013             resolveContinues(tree);
  1014             scan(tree.step);
  1015             resolveBreaks(tree, prevPendingExits);
  1018         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1019             visitVarDef(tree.var);
  1020             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1021             scan(tree.expr);
  1022             pendingExits = new ListBuffer<FlowPendingExit>();
  1023             scan(tree.body);
  1024             resolveContinues(tree);
  1025             resolveBreaks(tree, prevPendingExits);
  1028         public void visitLabelled(JCLabeledStatement tree) {
  1029             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1030             pendingExits = new ListBuffer<FlowPendingExit>();
  1031             scan(tree.body);
  1032             resolveBreaks(tree, prevPendingExits);
  1035         public void visitSwitch(JCSwitch tree) {
  1036             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1037             pendingExits = new ListBuffer<FlowPendingExit>();
  1038             scan(tree.selector);
  1039             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1040                 JCCase c = l.head;
  1041                 if (c.pat != null) {
  1042                     scan(c.pat);
  1044                 scan(c.stats);
  1046             resolveBreaks(tree, prevPendingExits);
  1049         public void visitTry(JCTry tree) {
  1050             List<Type> caughtPrev = caught;
  1051             List<Type> thrownPrev = thrown;
  1052             thrown = List.nil();
  1053             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1054                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1055                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1056                         List.of(l.head.param.vartype);
  1057                 for (JCExpression ct : subClauses) {
  1058                     caught = chk.incl(ct.type, caught);
  1062             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1063             pendingExits = new ListBuffer<FlowPendingExit>();
  1064             for (JCTree resource : tree.resources) {
  1065                 if (resource instanceof JCVariableDecl) {
  1066                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1067                     visitVarDef(vdecl);
  1068                 } else if (resource instanceof JCExpression) {
  1069                     scan((JCExpression) resource);
  1070                 } else {
  1071                     throw new AssertionError(tree);  // parser error
  1074             for (JCTree resource : tree.resources) {
  1075                 List<Type> closeableSupertypes = resource.type.isCompound() ?
  1076                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
  1077                     List.of(resource.type);
  1078                 for (Type sup : closeableSupertypes) {
  1079                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
  1080                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
  1081                                 attrEnv,
  1082                                 sup,
  1083                                 names.close,
  1084                                 List.<Type>nil(),
  1085                                 List.<Type>nil());
  1086                         Type mt = types.memberType(resource.type, closeMethod);
  1087                         if (closeMethod.kind == MTH) {
  1088                             for (Type t : mt.getThrownTypes()) {
  1089                                 markThrown(resource, t);
  1095             scan(tree.body);
  1096             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1097                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1098                 thrown;
  1099             thrown = thrownPrev;
  1100             caught = caughtPrev;
  1102             List<Type> caughtInTry = List.nil();
  1103             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1104                 JCVariableDecl param = l.head.param;
  1105                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1106                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1107                         List.of(l.head.param.vartype);
  1108                 List<Type> ctypes = List.nil();
  1109                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
  1110                 for (JCExpression ct : subClauses) {
  1111                     Type exc = ct.type;
  1112                     if (exc != syms.unknownType) {
  1113                         ctypes = ctypes.append(exc);
  1114                         if (types.isSameType(exc, syms.objectType))
  1115                             continue;
  1116                         checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
  1117                         caughtInTry = chk.incl(exc, caughtInTry);
  1120                 scan(param);
  1121                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1122                 scan(l.head.body);
  1123                 preciseRethrowTypes.remove(param.sym);
  1125             if (tree.finalizer != null) {
  1126                 List<Type> savedThrown = thrown;
  1127                 thrown = List.nil();
  1128                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1129                 pendingExits = prevPendingExits;
  1130                 scan(tree.finalizer);
  1131                 if (!tree.finallyCanCompleteNormally) {
  1132                     // discard exits and exceptions from try and finally
  1133                     thrown = chk.union(thrown, thrownPrev);
  1134                 } else {
  1135                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1136                     thrown = chk.union(thrown, savedThrown);
  1137                     // FIX: this doesn't preserve source order of exits in catch
  1138                     // versus finally!
  1139                     while (exits.nonEmpty()) {
  1140                         pendingExits.append(exits.next());
  1143             } else {
  1144                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1145                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1146                 pendingExits = prevPendingExits;
  1147                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1151         @Override
  1152         public void visitIf(JCIf tree) {
  1153             scan(tree.cond);
  1154             scan(tree.thenpart);
  1155             if (tree.elsepart != null) {
  1156                 scan(tree.elsepart);
  1160         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1161             if (chk.subset(exc, caughtInTry)) {
  1162                 log.error(pos, "except.already.caught", exc);
  1163             } else if (!chk.isUnchecked(pos, exc) &&
  1164                     !isExceptionOrThrowable(exc) &&
  1165                     !chk.intersects(exc, thrownInTry)) {
  1166                 log.error(pos, "except.never.thrown.in.try", exc);
  1167             } else if (allowImprovedCatchAnalysis) {
  1168                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
  1169                 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
  1170                 // unchecked exception, the result list would not be empty, as the augmented
  1171                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
  1172                 // exception, that would have been covered in the branch above
  1173                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
  1174                         !isExceptionOrThrowable(exc)) {
  1175                     String key = catchableThrownTypes.length() == 1 ?
  1176                             "unreachable.catch" :
  1177                             "unreachable.catch.1";
  1178                     log.warning(pos, key, catchableThrownTypes);
  1182         //where
  1183             private boolean isExceptionOrThrowable(Type exc) {
  1184                 return exc.tsym == syms.throwableType.tsym ||
  1185                     exc.tsym == syms.exceptionType.tsym;
  1188         public void visitBreak(JCBreak tree) {
  1189             recordExit(tree, new FlowPendingExit(tree, null));
  1192         public void visitContinue(JCContinue tree) {
  1193             recordExit(tree, new FlowPendingExit(tree, null));
  1196         public void visitReturn(JCReturn tree) {
  1197             scan(tree.expr);
  1198             recordExit(tree, new FlowPendingExit(tree, null));
  1201         public void visitThrow(JCThrow tree) {
  1202             scan(tree.expr);
  1203             Symbol sym = TreeInfo.symbol(tree.expr);
  1204             if (sym != null &&
  1205                 sym.kind == VAR &&
  1206                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
  1207                 preciseRethrowTypes.get(sym) != null &&
  1208                 allowImprovedRethrowAnalysis) {
  1209                 for (Type t : preciseRethrowTypes.get(sym)) {
  1210                     markThrown(tree, t);
  1213             else {
  1214                 markThrown(tree, tree.expr.type);
  1216             markDead(tree);
  1219         public void visitApply(JCMethodInvocation tree) {
  1220             scan(tree.meth);
  1221             scan(tree.args);
  1222             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
  1223                 markThrown(tree, l.head);
  1226         public void visitNewClass(JCNewClass tree) {
  1227             scan(tree.encl);
  1228             scan(tree.args);
  1229            // scan(tree.def);
  1230             for (List<Type> l = tree.constructorType.getThrownTypes();
  1231                  l.nonEmpty();
  1232                  l = l.tail) {
  1233                 markThrown(tree, l.head);
  1235             List<Type> caughtPrev = caught;
  1236             try {
  1237                 // If the new class expression defines an anonymous class,
  1238                 // analysis of the anonymous constructor may encounter thrown
  1239                 // types which are unsubstituted type variables.
  1240                 // However, since the constructor's actual thrown types have
  1241                 // already been marked as thrown, it is safe to simply include
  1242                 // each of the constructor's formal thrown types in the set of
  1243                 // 'caught/declared to be thrown' types, for the duration of
  1244                 // the class def analysis.
  1245                 if (tree.def != null)
  1246                     for (List<Type> l = tree.constructor.type.getThrownTypes();
  1247                          l.nonEmpty();
  1248                          l = l.tail) {
  1249                         caught = chk.incl(l.head, caught);
  1251                 scan(tree.def);
  1253             finally {
  1254                 caught = caughtPrev;
  1258         @Override
  1259         public void visitLambda(JCLambda tree) {
  1260             if (tree.type != null &&
  1261                     tree.type.isErroneous()) {
  1262                 return;
  1264             List<Type> prevCaught = caught;
  1265             List<Type> prevThrown = thrown;
  1266             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1267             try {
  1268                 pendingExits = new ListBuffer<>();
  1269                 caught = tree.getDescriptorType(types).getThrownTypes();
  1270                 thrown = List.nil();
  1271                 scan(tree.body);
  1272                 List<FlowPendingExit> exits = pendingExits.toList();
  1273                 pendingExits = new ListBuffer<FlowPendingExit>();
  1274                 while (exits.nonEmpty()) {
  1275                     FlowPendingExit exit = exits.head;
  1276                     exits = exits.tail;
  1277                     if (exit.thrown == null) {
  1278                         Assert.check(exit.tree.hasTag(RETURN));
  1279                     } else {
  1280                         // uncaught throws will be reported later
  1281                         pendingExits.append(exit);
  1285                 errorUncaught();
  1286             } finally {
  1287                 pendingExits = prevPending;
  1288                 caught = prevCaught;
  1289                 thrown = prevThrown;
  1293         public void visitTopLevel(JCCompilationUnit tree) {
  1294             // Do nothing for TopLevel since each class is visited individually
  1297     /**************************************************************************
  1298      * main method
  1299      *************************************************************************/
  1301         /** Perform definite assignment/unassignment analysis on a tree.
  1302          */
  1303         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1304             analyzeTree(env, env.tree, make);
  1306         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  1307             try {
  1308                 attrEnv = env;
  1309                 Flow.this.make = make;
  1310                 pendingExits = new ListBuffer<FlowPendingExit>();
  1311                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1312                 this.thrown = this.caught = null;
  1313                 this.classDef = null;
  1314                 scan(tree);
  1315             } finally {
  1316                 pendingExits = null;
  1317                 Flow.this.make = null;
  1318                 this.thrown = this.caught = null;
  1319                 this.classDef = null;
  1324     /**
  1325      * Specialized pass that performs inference of thrown types for lambdas.
  1326      */
  1327     class LambdaFlowAnalyzer extends FlowAnalyzer {
  1328         List<Type> inferredThrownTypes;
  1329         boolean inLambda;
  1330         @Override
  1331         public void visitLambda(JCLambda tree) {
  1332             if ((tree.type != null &&
  1333                     tree.type.isErroneous()) || inLambda) {
  1334                 return;
  1336             List<Type> prevCaught = caught;
  1337             List<Type> prevThrown = thrown;
  1338             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1339             inLambda = true;
  1340             try {
  1341                 pendingExits = new ListBuffer<>();
  1342                 caught = List.of(syms.throwableType);
  1343                 thrown = List.nil();
  1344                 scan(tree.body);
  1345                 inferredThrownTypes = thrown;
  1346             } finally {
  1347                 pendingExits = prevPending;
  1348                 caught = prevCaught;
  1349                 thrown = prevThrown;
  1350                 inLambda = false;
  1353         @Override
  1354         public void visitClassDef(JCClassDecl tree) {
  1355             //skip
  1359     /**
  1360      * This pass implements (i) definite assignment analysis, which ensures that
  1361      * each variable is assigned when used and (ii) definite unassignment analysis,
  1362      * which ensures that no final variable is assigned more than once. This visitor
  1363      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1364      * effectively-final local variables/parameters.
  1365      */
  1367     public abstract static class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer.AbstractAssignPendingExit>
  1368         extends BaseAnalyzer<P> {
  1370         /** The set of definitely assigned variables.
  1371          */
  1372         protected final Bits inits;
  1374         /** The set of definitely unassigned variables.
  1375          */
  1376         final Bits uninits;
  1378         /** The set of variables that are definitely unassigned everywhere
  1379          *  in current try block. This variable is maintained lazily; it is
  1380          *  updated only when something gets removed from uninits,
  1381          *  typically by being assigned in reachable code.  To obtain the
  1382          *  correct set of variables which are definitely unassigned
  1383          *  anywhere in current try block, intersect uninitsTry and
  1384          *  uninits.
  1385          */
  1386         final Bits uninitsTry;
  1388         /** When analyzing a condition, inits and uninits are null.
  1389          *  Instead we have:
  1390          */
  1391         final Bits initsWhenTrue;
  1392         final Bits initsWhenFalse;
  1393         final Bits uninitsWhenTrue;
  1394         final Bits uninitsWhenFalse;
  1396         /** A mapping from addresses to variable symbols.
  1397          */
  1398         protected JCVariableDecl[] vardecls;
  1400         /** The current class being defined.
  1401          */
  1402         JCClassDecl classDef;
  1404         /** The first variable sequence number in this class definition.
  1405          */
  1406         int firstadr;
  1408         /** The next available variable sequence number.
  1409          */
  1410         protected int nextadr;
  1412         /** The first variable sequence number in a block that can return.
  1413          */
  1414         protected int returnadr;
  1416         /** The list of unreferenced automatic resources.
  1417          */
  1418         Scope unrefdResources;
  1420         /** Set when processing a loop body the second time for DU analysis. */
  1421         FlowKind flowKind = FlowKind.NORMAL;
  1423         /** The starting position of the analysed tree */
  1424         int startPos;
  1426         final Symtab syms;
  1428         protected Names names;
  1430         public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
  1432             final Bits inits;
  1433             final Bits uninits;
  1434             final Bits exit_inits = new Bits(true);
  1435             final Bits exit_uninits = new Bits(true);
  1437             public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
  1438                 super(tree);
  1439                 this.inits = inits;
  1440                 this.uninits = uninits;
  1441                 this.exit_inits.assign(inits);
  1442                 this.exit_uninits.assign(uninits);
  1445             @Override
  1446             public void resolveJump(JCTree tree) {
  1447                 inits.andSet(exit_inits);
  1448                 uninits.andSet(exit_uninits);
  1452         public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) {
  1453             this.inits = inits;
  1454             uninits = new Bits();
  1455             uninitsTry = new Bits();
  1456             initsWhenTrue = new Bits(true);
  1457             initsWhenFalse = new Bits(true);
  1458             uninitsWhenTrue = new Bits(true);
  1459             uninitsWhenFalse = new Bits(true);
  1460             this.syms = syms;
  1461             this.names = names;
  1464         private boolean isInitialConstructor = false;
  1466         @Override
  1467         protected void markDead(JCTree tree) {
  1468             if (!isInitialConstructor) {
  1469                 inits.inclRange(returnadr, nextadr);
  1470             } else {
  1471                 for (int address = returnadr; address < nextadr; address++) {
  1472                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
  1473                         inits.incl(address);
  1477             uninits.inclRange(returnadr, nextadr);
  1480         /*-------------- Processing variables ----------------------*/
  1482         /** Do we need to track init/uninit state of this symbol?
  1483          *  I.e. is symbol either a local or a blank final variable?
  1484          */
  1485         protected boolean trackable(VarSymbol sym) {
  1486             return
  1487                 sym.pos >= startPos &&
  1488                 ((sym.owner.kind == MTH ||
  1489                 isFinalUninitializedField(sym)));
  1492         boolean isFinalUninitializedField(VarSymbol sym) {
  1493             return sym.owner.kind == TYP &&
  1494                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1495                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
  1498         boolean isFinalUninitializedStaticField(VarSymbol sym) {
  1499             return isFinalUninitializedField(sym) && sym.isStatic();
  1502         /** Initialize new trackable variable by setting its address field
  1503          *  to the next available sequence number and entering it under that
  1504          *  index into the vars array.
  1505          */
  1506         void newVar(JCVariableDecl varDecl) {
  1507             VarSymbol sym = varDecl.sym;
  1508             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
  1509             if ((sym.flags() & FINAL) == 0) {
  1510                 sym.flags_field |= EFFECTIVELY_FINAL;
  1512             sym.adr = nextadr;
  1513             vardecls[nextadr] = varDecl;
  1514             exclVarFromInits(varDecl, nextadr);
  1515             uninits.incl(nextadr);
  1516             nextadr++;
  1519         protected void exclVarFromInits(JCTree tree, int adr) {
  1520             inits.excl(adr);
  1523         protected void assignToInits(JCTree tree, Bits bits) {
  1524             inits.assign(bits);
  1527         protected void andSetInits(JCTree tree, Bits bits) {
  1528             inits.andSet(bits);
  1531         protected void orSetInits(JCTree tree, Bits bits) {
  1532             inits.orSet(bits);
  1535         /** Record an initialization of a trackable variable.
  1536          */
  1537         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1538             if (sym.adr >= firstadr && trackable(sym)) {
  1539                 if (uninits.isMember(sym.adr)) {
  1540                     uninit(sym);
  1542                 inits.incl(sym.adr);
  1545         //where
  1546             void uninit(VarSymbol sym) {
  1547                 if (!inits.isMember(sym.adr)) {
  1548                     // reachable assignment
  1549                     uninits.excl(sym.adr);
  1550                     uninitsTry.excl(sym.adr);
  1551                 } else {
  1552                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
  1553                     uninits.excl(sym.adr);
  1557         /** If tree is either a simple name or of the form this.name or
  1558          *  C.this.name, and tree represents a trackable variable,
  1559          *  record an initialization of the variable.
  1560          */
  1561         void letInit(JCTree tree) {
  1562             tree = TreeInfo.skipParens(tree);
  1563             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  1564                 Symbol sym = TreeInfo.symbol(tree);
  1565                 if (sym.kind == VAR) {
  1566                     letInit(tree.pos(), (VarSymbol)sym);
  1571         /** Check that trackable variable is initialized.
  1572          */
  1573         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
  1574             checkInit(pos, sym, "var.might.not.have.been.initialized");
  1577         void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}
  1579         /** Utility method to reset several Bits instances.
  1580          */
  1581         private void resetBits(Bits... bits) {
  1582             for (Bits b : bits) {
  1583                 b.reset();
  1587         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
  1588          */
  1589         void split(boolean setToNull) {
  1590             initsWhenFalse.assign(inits);
  1591             uninitsWhenFalse.assign(uninits);
  1592             initsWhenTrue.assign(inits);
  1593             uninitsWhenTrue.assign(uninits);
  1594             if (setToNull) {
  1595                 resetBits(inits, uninits);
  1599         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
  1600          */
  1601         protected void merge(JCTree tree) {
  1602             inits.assign(initsWhenFalse.andSet(initsWhenTrue));
  1603             uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
  1606     /* ************************************************************************
  1607      * Visitor methods for statements and definitions
  1608      *************************************************************************/
  1610         /** Analyze an expression. Make sure to set (un)inits rather than
  1611          *  (un)initsWhenTrue(WhenFalse) on exit.
  1612          */
  1613         void scanExpr(JCTree tree) {
  1614             if (tree != null) {
  1615                 scan(tree);
  1616                 if (inits.isReset()) {
  1617                     merge(tree);
  1622         /** Analyze a list of expressions.
  1623          */
  1624         void scanExprs(List<? extends JCExpression> trees) {
  1625             if (trees != null)
  1626                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
  1627                     scanExpr(l.head);
  1630         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
  1631          *  rather than (un)inits on exit.
  1632          */
  1633         void scanCond(JCTree tree) {
  1634             if (tree.type.isFalse()) {
  1635                 if (inits.isReset()) merge(tree);
  1636                 initsWhenTrue.assign(inits);
  1637                 initsWhenTrue.inclRange(firstadr, nextadr);
  1638                 uninitsWhenTrue.assign(uninits);
  1639                 uninitsWhenTrue.inclRange(firstadr, nextadr);
  1640                 initsWhenFalse.assign(inits);
  1641                 uninitsWhenFalse.assign(uninits);
  1642             } else if (tree.type.isTrue()) {
  1643                 if (inits.isReset()) merge(tree);
  1644                 initsWhenFalse.assign(inits);
  1645                 initsWhenFalse.inclRange(firstadr, nextadr);
  1646                 uninitsWhenFalse.assign(uninits);
  1647                 uninitsWhenFalse.inclRange(firstadr, nextadr);
  1648                 initsWhenTrue.assign(inits);
  1649                 uninitsWhenTrue.assign(uninits);
  1650             } else {
  1651                 scan(tree);
  1652                 if (!inits.isReset())
  1653                     split(tree.type != syms.unknownType);
  1655             if (tree.type != syms.unknownType) {
  1656                 resetBits(inits, uninits);
  1660         /* ------------ Visitor methods for various sorts of trees -------------*/
  1662         @Override
  1663         public void visitClassDef(JCClassDecl tree) {
  1664             if (tree.sym == null) {
  1665                 return;
  1668             JCClassDecl classDefPrev = classDef;
  1669             int firstadrPrev = firstadr;
  1670             int nextadrPrev = nextadr;
  1671             ListBuffer<P> pendingExitsPrev = pendingExits;
  1673             pendingExits = new ListBuffer<P>();
  1674             if (tree.name != names.empty) {
  1675                 firstadr = nextadr;
  1677             classDef = tree;
  1678             try {
  1679                 // define all the static fields
  1680                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1681                     if (l.head.hasTag(VARDEF)) {
  1682                         JCVariableDecl def = (JCVariableDecl)l.head;
  1683                         if ((def.mods.flags & STATIC) != 0) {
  1684                             VarSymbol sym = def.sym;
  1685                             if (trackable(sym)) {
  1686                                 newVar(def);
  1692                 // process all the static initializers
  1693                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1694                     if (!l.head.hasTag(METHODDEF) &&
  1695                         (TreeInfo.flags(l.head) & STATIC) != 0) {
  1696                         scan(l.head);
  1700                 // define all the instance fields
  1701                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1702                     if (l.head.hasTag(VARDEF)) {
  1703                         JCVariableDecl def = (JCVariableDecl)l.head;
  1704                         if ((def.mods.flags & STATIC) == 0) {
  1705                             VarSymbol sym = def.sym;
  1706                             if (trackable(sym)) {
  1707                                 newVar(def);
  1713                 // process all the instance initializers
  1714                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1715                     if (!l.head.hasTag(METHODDEF) &&
  1716                         (TreeInfo.flags(l.head) & STATIC) == 0) {
  1717                         scan(l.head);
  1721                 // process all the methods
  1722                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1723                     if (l.head.hasTag(METHODDEF)) {
  1724                         scan(l.head);
  1727             } finally {
  1728                 pendingExits = pendingExitsPrev;
  1729                 nextadr = nextadrPrev;
  1730                 firstadr = firstadrPrev;
  1731                 classDef = classDefPrev;
  1735         @Override
  1736         public void visitMethodDef(JCMethodDecl tree) {
  1737             if (tree.body == null) {
  1738                 return;
  1740             /*  Ignore synthetic methods, except for translated lambda methods.
  1741              */
  1742             if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
  1743                 return;
  1746             final Bits initsPrev = new Bits(inits);
  1747             final Bits uninitsPrev = new Bits(uninits);
  1748             int nextadrPrev = nextadr;
  1749             int firstadrPrev = firstadr;
  1750             int returnadrPrev = returnadr;
  1752             Assert.check(pendingExits.isEmpty());
  1753             boolean lastInitialConstructor = isInitialConstructor;
  1754             try {
  1755                 isInitialConstructor = TreeInfo.isInitialConstructor(tree);
  1757                 if (!isInitialConstructor) {
  1758                     firstadr = nextadr;
  1760                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  1761                     JCVariableDecl def = l.head;
  1762                     scan(def);
  1763                     Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
  1764                     /*  If we are executing the code from Gen, then there can be
  1765                      *  synthetic or mandated variables, ignore them.
  1766                      */
  1767                     initParam(def);
  1769                 // else we are in an instance initializer block;
  1770                 // leave caught unchanged.
  1771                 scan(tree.body);
  1773                 if (isInitialConstructor) {
  1774                     boolean isSynthesized = (tree.sym.flags() &
  1775                                              GENERATEDCONSTR) != 0;
  1776                     for (int i = firstadr; i < nextadr; i++) {
  1777                         JCVariableDecl vardecl = vardecls[i];
  1778                         VarSymbol var = vardecl.sym;
  1779                         if (var.owner == classDef.sym) {
  1780                             // choose the diagnostic position based on whether
  1781                             // the ctor is default(synthesized) or not
  1782                             if (isSynthesized) {
  1783                                 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
  1784                                     var, "var.not.initialized.in.default.constructor");
  1785                             } else {
  1786                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
  1791                 List<P> exits = pendingExits.toList();
  1792                 pendingExits = new ListBuffer<>();
  1793                 while (exits.nonEmpty()) {
  1794                     P exit = exits.head;
  1795                     exits = exits.tail;
  1796                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1797                     if (isInitialConstructor) {
  1798                         assignToInits(exit.tree, exit.exit_inits);
  1799                         for (int i = firstadr; i < nextadr; i++) {
  1800                             checkInit(exit.tree.pos(), vardecls[i].sym);
  1804             } finally {
  1805                 assignToInits(tree, initsPrev);
  1806                 uninits.assign(uninitsPrev);
  1807                 nextadr = nextadrPrev;
  1808                 firstadr = firstadrPrev;
  1809                 returnadr = returnadrPrev;
  1810                 isInitialConstructor = lastInitialConstructor;
  1814         protected void initParam(JCVariableDecl def) {
  1815             inits.incl(def.sym.adr);
  1816             uninits.excl(def.sym.adr);
  1819         public void visitVarDef(JCVariableDecl tree) {
  1820             boolean track = trackable(tree.sym);
  1821             if (track && tree.sym.owner.kind == MTH) {
  1822                 newVar(tree);
  1824             if (tree.init != null) {
  1825                 scanExpr(tree.init);
  1826                 if (track) {
  1827                     letInit(tree.pos(), tree.sym);
  1832         public void visitBlock(JCBlock tree) {
  1833             int nextadrPrev = nextadr;
  1834             scan(tree.stats);
  1835             nextadr = nextadrPrev;
  1838         int getLogNumberOfErrors() {
  1839             return 0;
  1842         public void visitDoLoop(JCDoWhileLoop tree) {
  1843             ListBuffer<P> prevPendingExits = pendingExits;
  1844             FlowKind prevFlowKind = flowKind;
  1845             flowKind = FlowKind.NORMAL;
  1846             final Bits initsSkip = new Bits(true);
  1847             final Bits uninitsSkip = new Bits(true);
  1848             pendingExits = new ListBuffer<P>();
  1849             int prevErrors = getLogNumberOfErrors();
  1850             do {
  1851                 final Bits uninitsEntry = new Bits(uninits);
  1852                 uninitsEntry.excludeFrom(nextadr);
  1853                 scan(tree.body);
  1854                 resolveContinues(tree);
  1855                 scanCond(tree.cond);
  1856                 if (!flowKind.isFinal()) {
  1857                     initsSkip.assign(initsWhenFalse);
  1858                     uninitsSkip.assign(uninitsWhenFalse);
  1860                 if (getLogNumberOfErrors() !=  prevErrors ||
  1861                     flowKind.isFinal() ||
  1862                     new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1863                     break;
  1864                 assignToInits(tree.cond, initsWhenTrue);
  1865                 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
  1866                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1867             } while (true);
  1868             flowKind = prevFlowKind;
  1869             assignToInits(tree, initsSkip);
  1870             uninits.assign(uninitsSkip);
  1871             resolveBreaks(tree, prevPendingExits);
  1874         public void visitWhileLoop(JCWhileLoop tree) {
  1875             ListBuffer<P> prevPendingExits = pendingExits;
  1876             FlowKind prevFlowKind = flowKind;
  1877             flowKind = FlowKind.NORMAL;
  1878             final Bits initsSkip = new Bits(true);
  1879             final Bits uninitsSkip = new Bits(true);
  1880             pendingExits = new ListBuffer<>();
  1881             int prevErrors = getLogNumberOfErrors();
  1882             final Bits uninitsEntry = new Bits(uninits);
  1883             uninitsEntry.excludeFrom(nextadr);
  1884             do {
  1885                 scanCond(tree.cond);
  1886                 if (!flowKind.isFinal()) {
  1887                     initsSkip.assign(initsWhenFalse) ;
  1888                     uninitsSkip.assign(uninitsWhenFalse);
  1890                 assignToInits(tree, initsWhenTrue);
  1891                 uninits.assign(uninitsWhenTrue);
  1892                 scan(tree.body);
  1893                 resolveContinues(tree);
  1894                 if (getLogNumberOfErrors() != prevErrors ||
  1895                     flowKind.isFinal() ||
  1896                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
  1897                     break;
  1899                 uninits.assign(uninitsEntry.andSet(uninits));
  1900                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1901             } while (true);
  1902             flowKind = prevFlowKind;
  1903             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
  1904             //branch is not taken AND if it's DA/DU before any break statement
  1905             assignToInits(tree.body, initsSkip);
  1906             uninits.assign(uninitsSkip);
  1907             resolveBreaks(tree, prevPendingExits);
  1910         public void visitForLoop(JCForLoop tree) {
  1911             ListBuffer<P> prevPendingExits = pendingExits;
  1912             FlowKind prevFlowKind = flowKind;
  1913             flowKind = FlowKind.NORMAL;
  1914             int nextadrPrev = nextadr;
  1915             scan(tree.init);
  1916             final Bits initsSkip = new Bits(true);
  1917             final Bits uninitsSkip = new Bits(true);
  1918             pendingExits = new ListBuffer<P>();
  1919             int prevErrors = getLogNumberOfErrors();
  1920             do {
  1921                 final Bits uninitsEntry = new Bits(uninits);
  1922                 uninitsEntry.excludeFrom(nextadr);
  1923                 if (tree.cond != null) {
  1924                     scanCond(tree.cond);
  1925                     if (!flowKind.isFinal()) {
  1926                         initsSkip.assign(initsWhenFalse);
  1927                         uninitsSkip.assign(uninitsWhenFalse);
  1929                     assignToInits(tree.body, initsWhenTrue);
  1930                     uninits.assign(uninitsWhenTrue);
  1931                 } else if (!flowKind.isFinal()) {
  1932                     initsSkip.assign(inits);
  1933                     initsSkip.inclRange(firstadr, nextadr);
  1934                     uninitsSkip.assign(uninits);
  1935                     uninitsSkip.inclRange(firstadr, nextadr);
  1937                 scan(tree.body);
  1938                 resolveContinues(tree);
  1939                 scan(tree.step);
  1940                 if (getLogNumberOfErrors() != prevErrors ||
  1941                     flowKind.isFinal() ||
  1942                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  1943                     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 a for loop, if it's DA/DU assuming the
  1949             //branch is not taken AND if it's DA/DU before any break statement
  1950             assignToInits(tree.body, initsSkip);
  1951             uninits.assign(uninitsSkip);
  1952             resolveBreaks(tree, prevPendingExits);
  1953             nextadr = nextadrPrev;
  1956         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1957             visitVarDef(tree.var);
  1959             ListBuffer<P> prevPendingExits = pendingExits;
  1960             FlowKind prevFlowKind = flowKind;
  1961             flowKind = FlowKind.NORMAL;
  1962             int nextadrPrev = nextadr;
  1963             scan(tree.expr);
  1964             final Bits initsStart = new Bits(inits);
  1965             final Bits uninitsStart = new Bits(uninits);
  1967             letInit(tree.pos(), tree.var.sym);
  1968             pendingExits = new ListBuffer<P>();
  1969             int prevErrors = getLogNumberOfErrors();
  1970             do {
  1971                 final Bits uninitsEntry = new Bits(uninits);
  1972                 uninitsEntry.excludeFrom(nextadr);
  1973                 scan(tree.body);
  1974                 resolveContinues(tree);
  1975                 if (getLogNumberOfErrors() != prevErrors ||
  1976                     flowKind.isFinal() ||
  1977                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  1978                     break;
  1979                 uninits.assign(uninitsEntry.andSet(uninits));
  1980                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1981             } while (true);
  1982             flowKind = prevFlowKind;
  1983             assignToInits(tree.body, initsStart);
  1984             uninits.assign(uninitsStart.andSet(uninits));
  1985             resolveBreaks(tree, prevPendingExits);
  1986             nextadr = nextadrPrev;
  1989         public void visitLabelled(JCLabeledStatement tree) {
  1990             ListBuffer<P> prevPendingExits = pendingExits;
  1991             pendingExits = new ListBuffer<P>();
  1992             scan(tree.body);
  1993             resolveBreaks(tree, prevPendingExits);
  1996         public void visitSwitch(JCSwitch tree) {
  1997             ListBuffer<P> prevPendingExits = pendingExits;
  1998             pendingExits = new ListBuffer<>();
  1999             int nextadrPrev = nextadr;
  2000             scanExpr(tree.selector);
  2001             final Bits initsSwitch = new Bits(inits);
  2002             final Bits uninitsSwitch = new Bits(uninits);
  2003             boolean hasDefault = false;
  2004             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  2005                 assignToInits(l.head, initsSwitch);
  2006                 uninits.assign(uninits.andSet(uninitsSwitch));
  2007                 JCCase c = l.head;
  2008                 if (c.pat == null) {
  2009                     hasDefault = true;
  2010                 } else {
  2011                     scanExpr(c.pat);
  2013                 if (hasDefault) {
  2014                     assignToInits(null, initsSwitch);
  2015                     uninits.assign(uninits.andSet(uninitsSwitch));
  2017                 scan(c.stats);
  2018                 addVars(c.stats, initsSwitch, uninitsSwitch);
  2019                 if (!hasDefault) {
  2020                     assignToInits(l.head.stats.last(), initsSwitch);
  2021                     uninits.assign(uninits.andSet(uninitsSwitch));
  2023                 // Warn about fall-through if lint switch fallthrough enabled.
  2025             if (!hasDefault) {
  2026                 andSetInits(null, initsSwitch);
  2028             resolveBreaks(tree, prevPendingExits);
  2029             nextadr = nextadrPrev;
  2031         // where
  2032             /** Add any variables defined in stats to inits and uninits. */
  2033             private void addVars(List<JCStatement> stats, final Bits inits,
  2034                                         final Bits uninits) {
  2035                 for (;stats.nonEmpty(); stats = stats.tail) {
  2036                     JCTree stat = stats.head;
  2037                     if (stat.hasTag(VARDEF)) {
  2038                         int adr = ((JCVariableDecl) stat).sym.adr;
  2039                         inits.excl(adr);
  2040                         uninits.incl(adr);
  2045         boolean isEnabled(Lint.LintCategory lc) {
  2046             return false;
  2049         void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {}
  2051         public void visitTry(JCTry tree) {
  2052             ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
  2053             final Bits uninitsTryPrev = new Bits(uninitsTry);
  2054             ListBuffer<P> prevPendingExits = pendingExits;
  2055             pendingExits = new ListBuffer<>();
  2056             final Bits initsTry = new Bits(inits);
  2057             uninitsTry.assign(uninits);
  2058             for (JCTree resource : tree.resources) {
  2059                 if (resource instanceof JCVariableDecl) {
  2060                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  2061                     visitVarDef(vdecl);
  2062                     unrefdResources.enter(vdecl.sym);
  2063                     resourceVarDecls.append(vdecl);
  2064                 } else if (resource instanceof JCExpression) {
  2065                     scanExpr((JCExpression) resource);
  2066                 } else {
  2067                     throw new AssertionError(tree);  // parser error
  2070             scan(tree.body);
  2071             uninitsTry.andSet(uninits);
  2072             final Bits initsEnd = new Bits(inits);
  2073             final Bits uninitsEnd = new Bits(uninits);
  2074             int nextadrCatch = nextadr;
  2076             if (!resourceVarDecls.isEmpty() &&
  2077                     isEnabled(Lint.LintCategory.TRY)) {
  2078                 for (JCVariableDecl resVar : resourceVarDecls) {
  2079                     if (unrefdResources.includes(resVar.sym)) {
  2080                         reportWarning(Lint.LintCategory.TRY, resVar.pos(),
  2081                                     "try.resource.not.referenced", resVar.sym);
  2082                         unrefdResources.remove(resVar.sym);
  2087             /*  The analysis of each catch should be independent.
  2088              *  Each one should have the same initial values of inits and
  2089              *  uninits.
  2090              */
  2091             final Bits initsCatchPrev = new Bits(initsTry);
  2092             final Bits uninitsCatchPrev = new Bits(uninitsTry);
  2094             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  2095                 JCVariableDecl param = l.head.param;
  2096                 assignToInits(tree.body, initsCatchPrev);
  2097                 uninits.assign(uninitsCatchPrev);
  2098                 scan(param);
  2099                 /* If this is a TWR and we are executing the code from Gen,
  2100                  * then there can be synthetic variables, ignore them.
  2101                  */
  2102                 initParam(param);
  2103                 scan(l.head.body);
  2104                 initsEnd.andSet(inits);
  2105                 uninitsEnd.andSet(uninits);
  2106                 nextadr = nextadrCatch;
  2108             if (tree.finalizer != null) {
  2109                 assignToInits(tree.finalizer, initsTry);
  2110                 uninits.assign(uninitsTry);
  2111                 ListBuffer<P> exits = pendingExits;
  2112                 pendingExits = prevPendingExits;
  2113                 scan(tree.finalizer);
  2114                 if (!tree.finallyCanCompleteNormally) {
  2115                     // discard exits and exceptions from try and finally
  2116                 } else {
  2117                     uninits.andSet(uninitsEnd);
  2118                     // FIX: this doesn't preserve source order of exits in catch
  2119                     // versus finally!
  2120                     while (exits.nonEmpty()) {
  2121                         P exit = exits.next();
  2122                         if (exit.exit_inits != null) {
  2123                             exit.exit_inits.orSet(inits);
  2124                             exit.exit_uninits.andSet(uninits);
  2126                         pendingExits.append(exit);
  2128                     orSetInits(tree, initsEnd);
  2130             } else {
  2131                 assignToInits(tree, initsEnd);
  2132                 uninits.assign(uninitsEnd);
  2133                 ListBuffer<P> exits = pendingExits;
  2134                 pendingExits = prevPendingExits;
  2135                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  2137             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  2140         public void visitConditional(JCConditional tree) {
  2141             scanCond(tree.cond);
  2142             final Bits initsBeforeElse = new Bits(initsWhenFalse);
  2143             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
  2144             assignToInits(tree.cond, initsWhenTrue);
  2145             uninits.assign(uninitsWhenTrue);
  2146             if (tree.truepart.type.hasTag(BOOLEAN) &&
  2147                 tree.falsepart.type.hasTag(BOOLEAN)) {
  2148                 // if b and c are boolean valued, then
  2149                 // v is (un)assigned after a?b:c when true iff
  2150                 //    v is (un)assigned after b when true and
  2151                 //    v is (un)assigned after c when true
  2152                 scanCond(tree.truepart);
  2153                 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
  2154                 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
  2155                 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
  2156                 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
  2157                 assignToInits(tree.truepart, initsBeforeElse);
  2158                 uninits.assign(uninitsBeforeElse);
  2159                 scanCond(tree.falsepart);
  2160                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
  2161                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
  2162                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
  2163                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
  2164             } else {
  2165                 scanExpr(tree.truepart);
  2166                 final Bits initsAfterThen = new Bits(inits);
  2167                 final Bits uninitsAfterThen = new Bits(uninits);
  2168                 assignToInits(tree.truepart, initsBeforeElse);
  2169                 uninits.assign(uninitsBeforeElse);
  2170                 scanExpr(tree.falsepart);
  2171                 andSetInits(tree.falsepart, initsAfterThen);
  2172                 uninits.andSet(uninitsAfterThen);
  2176         public void visitIf(JCIf tree) {
  2177             scanCond(tree.cond);
  2178             final Bits initsBeforeElse = new Bits(initsWhenFalse);
  2179             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
  2180             assignToInits(tree.cond, initsWhenTrue);
  2181             uninits.assign(uninitsWhenTrue);
  2182             scan(tree.thenpart);
  2183             if (tree.elsepart != null) {
  2184                 final Bits initsAfterThen = new Bits(inits);
  2185                 final Bits uninitsAfterThen = new Bits(uninits);
  2186                 assignToInits(tree.thenpart, initsBeforeElse);
  2187                 uninits.assign(uninitsBeforeElse);
  2188                 scan(tree.elsepart);
  2189                 andSetInits(tree.elsepart, initsAfterThen);
  2190                 uninits.andSet(uninitsAfterThen);
  2191             } else {
  2192                 andSetInits(tree.thenpart, initsBeforeElse);
  2193                 uninits.andSet(uninitsBeforeElse);
  2197         protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
  2198             return null;
  2201         @Override
  2202         public void visitBreak(JCBreak tree) {
  2203             recordExit(tree, createNewPendingExit(tree, inits, uninits));
  2206         @Override
  2207         public void visitContinue(JCContinue tree) {
  2208             recordExit(tree, createNewPendingExit(tree, inits, uninits));
  2211         @Override
  2212         public void visitReturn(JCReturn tree) {
  2213             scanExpr(tree.expr);
  2214             recordExit(tree, createNewPendingExit(tree, inits, uninits));
  2217         public void visitThrow(JCThrow tree) {
  2218             scanExpr(tree.expr);
  2219             markDead(tree.expr);
  2222         public void visitApply(JCMethodInvocation tree) {
  2223             scanExpr(tree.meth);
  2224             scanExprs(tree.args);
  2227         public void visitNewClass(JCNewClass tree) {
  2228             scanExpr(tree.encl);
  2229             scanExprs(tree.args);
  2230             scan(tree.def);
  2233         @Override
  2234         public void visitLambda(JCLambda tree) {
  2235             final Bits prevUninits = new Bits(uninits);
  2236             final Bits prevInits = new Bits(inits);
  2237             int returnadrPrev = returnadr;
  2238             ListBuffer<P> prevPending = pendingExits;
  2239             try {
  2240                 returnadr = nextadr;
  2241                 pendingExits = new ListBuffer<P>();
  2242                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  2243                     JCVariableDecl def = l.head;
  2244                     scan(def);
  2245                     inits.incl(def.sym.adr);
  2246                     uninits.excl(def.sym.adr);
  2248                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
  2249                     scanExpr(tree.body);
  2250                 } else {
  2251                     scan(tree.body);
  2254             finally {
  2255                 returnadr = returnadrPrev;
  2256                 uninits.assign(prevUninits);
  2257                 assignToInits(tree, prevInits);
  2258                 pendingExits = prevPending;
  2262         public void visitNewArray(JCNewArray tree) {
  2263             scanExprs(tree.dims);
  2264             scanExprs(tree.elems);
  2267         public void visitAssert(JCAssert tree) {
  2268             final Bits initsExit = new Bits(inits);
  2269             final Bits uninitsExit = new Bits(uninits);
  2270             scanCond(tree.cond);
  2271             uninitsExit.andSet(uninitsWhenTrue);
  2272             if (tree.detail != null) {
  2273                 assignToInits(tree, initsWhenFalse);
  2274                 uninits.assign(uninitsWhenFalse);
  2275                 scanExpr(tree.detail);
  2277             assignToInits(tree, initsExit);
  2278             uninits.assign(uninitsExit);
  2281         public void visitAssign(JCAssign tree) {
  2282             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2283             if (!(lhs instanceof JCIdent)) {
  2284                 scanExpr(lhs);
  2286             scanExpr(tree.rhs);
  2287             letInit(lhs);
  2290         public void visitAssignop(JCAssignOp tree) {
  2291             scanExpr(tree.lhs);
  2292             scanExpr(tree.rhs);
  2293             letInit(tree.lhs);
  2296         public void visitUnary(JCUnary tree) {
  2297             switch (tree.getTag()) {
  2298             case NOT:
  2299                 scanCond(tree.arg);
  2300                 final Bits t = new Bits(initsWhenFalse);
  2301                 initsWhenFalse.assign(initsWhenTrue);
  2302                 initsWhenTrue.assign(t);
  2303                 t.assign(uninitsWhenFalse);
  2304                 uninitsWhenFalse.assign(uninitsWhenTrue);
  2305                 uninitsWhenTrue.assign(t);
  2306                 break;
  2307             case PREINC: case POSTINC:
  2308             case PREDEC: case POSTDEC:
  2309                 scanExpr(tree.arg);
  2310                 letInit(tree.arg);
  2311                 break;
  2312             default:
  2313                 scanExpr(tree.arg);
  2317         public void visitBinary(JCBinary tree) {
  2318             switch (tree.getTag()) {
  2319             case AND:
  2320                 scanCond(tree.lhs);
  2321                 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
  2322                 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
  2323                 assignToInits(tree.lhs, initsWhenTrue);
  2324                 uninits.assign(uninitsWhenTrue);
  2325                 scanCond(tree.rhs);
  2326                 initsWhenFalse.andSet(initsWhenFalseLeft);
  2327                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
  2328                 break;
  2329             case OR:
  2330                 scanCond(tree.lhs);
  2331                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
  2332                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
  2333                 assignToInits(tree.lhs, initsWhenFalse);
  2334                 uninits.assign(uninitsWhenFalse);
  2335                 scanCond(tree.rhs);
  2336                 initsWhenTrue.andSet(initsWhenTrueLeft);
  2337                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
  2338                 break;
  2339             default:
  2340                 scanExpr(tree.lhs);
  2341                 scanExpr(tree.rhs);
  2345         public void visitIdent(JCIdent tree) {
  2346             if (tree.sym.kind == VAR) {
  2347                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2348                 referenced(tree.sym);
  2352         void referenced(Symbol sym) {
  2353             unrefdResources.remove(sym);
  2356         public void visitAnnotatedType(JCAnnotatedType tree) {
  2357             // annotations don't get scanned
  2358             tree.underlyingType.accept(this);
  2361         public void visitTopLevel(JCCompilationUnit tree) {
  2362             // Do nothing for TopLevel since each class is visited individually
  2365     /**************************************************************************
  2366      * main method
  2367      *************************************************************************/
  2369         /** Perform definite assignment/unassignment analysis on a tree.
  2370          */
  2371         public void analyzeTree(Env<?> env) {
  2372             analyzeTree(env, env.tree);
  2375         public void analyzeTree(Env<?> env, JCTree tree) {
  2376             try {
  2377                 startPos = tree.pos().getStartPosition();
  2379                 if (vardecls == null)
  2380                     vardecls = new JCVariableDecl[32];
  2381                 else
  2382                     for (int i=0; i<vardecls.length; i++)
  2383                         vardecls[i] = null;
  2384                 firstadr = 0;
  2385                 nextadr = 0;
  2386                 pendingExits = new ListBuffer<>();
  2387                 this.classDef = null;
  2388                 unrefdResources = new Scope(env.enclClass.sym);
  2389                 scan(tree);
  2390             } finally {
  2391                 // note that recursive invocations of this method fail hard
  2392                 startPos = -1;
  2393                 resetBits(inits, uninits, uninitsTry, initsWhenTrue,
  2394                         initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
  2395                 if (vardecls != null) {
  2396                     for (int i=0; i<vardecls.length; i++)
  2397                         vardecls[i] = null;
  2399                 firstadr = 0;
  2400                 nextadr = 0;
  2401                 pendingExits = null;
  2402                 this.classDef = null;
  2403                 unrefdResources = null;
  2408     public static class AssignAnalyzer
  2409         extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> {
  2411         Log log;
  2412         Lint lint;
  2414         public static class AssignPendingExit
  2415             extends AbstractAssignAnalyzer.AbstractAssignPendingExit {
  2417             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
  2418                 super(tree, inits, uninits);
  2422         public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) {
  2423             super(new Bits(), syms, names);
  2424             this.log = log;
  2425             this.lint = lint;
  2428         @Override
  2429         protected AssignPendingExit createNewPendingExit(JCTree tree,
  2430             Bits inits, Bits uninits) {
  2431             return new AssignPendingExit(tree, inits, uninits);
  2434         /** Record an initialization of a trackable variable.
  2435          */
  2436         @Override
  2437         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  2438             if (sym.adr >= firstadr && trackable(sym)) {
  2439                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
  2440                     if (!uninits.isMember(sym.adr)) {
  2441                         //assignment targeting an effectively final variable
  2442                         //makes the variable lose its status of effectively final
  2443                         //if the variable is _not_ definitively unassigned
  2444                         sym.flags_field &= ~EFFECTIVELY_FINAL;
  2445                     } else {
  2446                         uninit(sym);
  2449                 else if ((sym.flags() & FINAL) != 0) {
  2450                     if ((sym.flags() & PARAMETER) != 0) {
  2451                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  2452                             log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
  2454                         else {
  2455                             log.error(pos, "final.parameter.may.not.be.assigned",
  2456                                   sym);
  2458                     } else if (!uninits.isMember(sym.adr)) {
  2459                         log.error(pos, flowKind.errKey, sym);
  2460                     } else {
  2461                         uninit(sym);
  2464                 inits.incl(sym.adr);
  2465             } else if ((sym.flags() & FINAL) != 0) {
  2466                 log.error(pos, "var.might.already.be.assigned", sym);
  2470         @Override
  2471         void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
  2472             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  2473                 trackable(sym) &&
  2474                 !inits.isMember(sym.adr)) {
  2475                 log.error(pos, errkey, sym);
  2476                 inits.incl(sym.adr);
  2480         @Override
  2481         void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
  2482             String key, Object ... args) {
  2483             log.warning(lc, pos, key, args);
  2486         @Override
  2487         int getLogNumberOfErrors() {
  2488             return log.nerrors;
  2491         @Override
  2492         boolean isEnabled(Lint.LintCategory lc) {
  2493             return lint.isEnabled(lc);
  2496         @Override
  2497         public void visitClassDef(JCClassDecl tree) {
  2498             if (tree.sym == null) {
  2499                 return;
  2502             Lint lintPrev = lint;
  2503             lint = lint.augment(tree.sym);
  2504             try {
  2505                 super.visitClassDef(tree);
  2506             } finally {
  2507                 lint = lintPrev;
  2511         @Override
  2512         public void visitMethodDef(JCMethodDecl tree) {
  2513             if (tree.body == null) {
  2514                 return;
  2517             /*  MemberEnter can generate synthetic methods ignore them
  2518              */
  2519             if ((tree.sym.flags() & SYNTHETIC) != 0) {
  2520                 return;
  2523             Lint lintPrev = lint;
  2524             lint = lint.augment(tree.sym);
  2525             try {
  2526                 super.visitMethodDef(tree);
  2527             } finally {
  2528                 lint = lintPrev;
  2532         @Override
  2533         public void visitVarDef(JCVariableDecl tree) {
  2534             if (tree.init == null) {
  2535                 super.visitVarDef(tree);
  2536             } else {
  2537                 Lint lintPrev = lint;
  2538                 lint = lint.augment(tree.sym);
  2539                 try{
  2540                     super.visitVarDef(tree);
  2541                 } finally {
  2542                     lint = lintPrev;
  2549     /**
  2550      * This pass implements the last step of the dataflow analysis, namely
  2551      * the effectively-final analysis check. This checks that every local variable
  2552      * reference from a lambda body/local inner class is either final or effectively final.
  2553      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2554      * AssignAnalyzer.
  2555      */
  2556     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
  2558         JCTree currentTree; //local class or lambda
  2560         @Override
  2561         void markDead(JCTree tree) {
  2562             //do nothing
  2565         @SuppressWarnings("fallthrough")
  2566         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
  2567             if (currentTree != null &&
  2568                     sym.owner.kind == MTH &&
  2569                     sym.pos < currentTree.getStartPosition()) {
  2570                 switch (currentTree.getTag()) {
  2571                     case CLASSDEF:
  2572                         if (!allowEffectivelyFinalInInnerClasses) {
  2573                             if ((sym.flags() & FINAL) == 0) {
  2574                                 reportInnerClsNeedsFinalError(pos, sym);
  2576                             break;
  2578                     case LAMBDA:
  2579                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
  2580                            reportEffectivelyFinalError(pos, sym);
  2586         @SuppressWarnings("fallthrough")
  2587         void letInit(JCTree tree) {
  2588             tree = TreeInfo.skipParens(tree);
  2589             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  2590                 Symbol sym = TreeInfo.symbol(tree);
  2591                 if (currentTree != null &&
  2592                         sym.kind == VAR &&
  2593                         sym.owner.kind == MTH &&
  2594                         ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
  2595                     switch (currentTree.getTag()) {
  2596                         case CLASSDEF:
  2597                             if (!allowEffectivelyFinalInInnerClasses) {
  2598                                 reportInnerClsNeedsFinalError(tree, sym);
  2599                                 break;
  2601                         case LAMBDA:
  2602                             reportEffectivelyFinalError(tree, sym);
  2608         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
  2609             String subKey = currentTree.hasTag(LAMBDA) ?
  2610                   "lambda"  : "inner.cls";
  2611             log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
  2614         void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
  2615             log.error(pos,
  2616                     "local.var.accessed.from.icls.needs.final",
  2617                     sym);
  2620     /*************************************************************************
  2621      * Visitor methods for statements and definitions
  2622      *************************************************************************/
  2624         /* ------------ Visitor methods for various sorts of trees -------------*/
  2626         public void visitClassDef(JCClassDecl tree) {
  2627             JCTree prevTree = currentTree;
  2628             try {
  2629                 currentTree = tree.sym.isLocal() ? tree : null;
  2630                 super.visitClassDef(tree);
  2631             } finally {
  2632                 currentTree = prevTree;
  2636         @Override
  2637         public void visitLambda(JCLambda tree) {
  2638             JCTree prevTree = currentTree;
  2639             try {
  2640                 currentTree = tree;
  2641                 super.visitLambda(tree);
  2642             } finally {
  2643                 currentTree = prevTree;
  2647         @Override
  2648         public void visitIdent(JCIdent tree) {
  2649             if (tree.sym.kind == VAR) {
  2650                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
  2654         public void visitAssign(JCAssign tree) {
  2655             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2656             if (!(lhs instanceof JCIdent)) {
  2657                 scan(lhs);
  2659             scan(tree.rhs);
  2660             letInit(lhs);
  2663         public void visitAssignop(JCAssignOp tree) {
  2664             scan(tree.lhs);
  2665             scan(tree.rhs);
  2666             letInit(tree.lhs);
  2669         public void visitUnary(JCUnary tree) {
  2670             switch (tree.getTag()) {
  2671                 case PREINC: case POSTINC:
  2672                 case PREDEC: case POSTDEC:
  2673                     scan(tree.arg);
  2674                     letInit(tree.arg);
  2675                     break;
  2676                 default:
  2677                     scan(tree.arg);
  2681         public void visitTopLevel(JCCompilationUnit tree) {
  2682             // Do nothing for TopLevel since each class is visited individually
  2685     /**************************************************************************
  2686      * main method
  2687      *************************************************************************/
  2689         /** Perform definite assignment/unassignment analysis on a tree.
  2690          */
  2691         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2692             analyzeTree(env, env.tree, make);
  2694         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2695             try {
  2696                 attrEnv = env;
  2697                 Flow.this.make = make;
  2698                 pendingExits = new ListBuffer<PendingExit>();
  2699                 scan(tree);
  2700             } finally {
  2701                 pendingExits = null;
  2702                 Flow.this.make = null;

mercurial