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

Thu, 22 Aug 2013 13:12:43 +0100

author
vromero
date
Thu, 22 Aug 2013 13:12:43 +0100
changeset 1974
25aaff78d754
parent 1955
ec77c7b46c37
child 2019
77d395862700
permissions
-rw-r--r--

8023112: javac should not use lazy constant evaluation approach for method references
Reviewed-by: jjg, mcimadamore

     1 /*
     2  * Copyright (c) 1999, 2013, 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().analyzeTree(env, make);
   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             new LambdaFlowAnalyzer().analyzeTree(env, that, make);
   228         } finally {
   229             if (!speculative) {
   230                 log.popDiagnosticHandler(diagHandler);
   231             }
   232         }
   233     }
   235     /**
   236      * Definite assignment scan mode
   237      */
   238     enum FlowKind {
   239         /**
   240          * This is the normal DA/DU analysis mode
   241          */
   242         NORMAL("var.might.already.be.assigned", false),
   243         /**
   244          * This is the speculative DA/DU analysis mode used to speculatively
   245          * derive assertions within loop bodies
   246          */
   247         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
   249         final String errKey;
   250         final boolean isFinal;
   252         FlowKind(String errKey, boolean isFinal) {
   253             this.errKey = errKey;
   254             this.isFinal = isFinal;
   255         }
   257         boolean isFinal() {
   258             return isFinal;
   259         }
   260     }
   262     protected Flow(Context context) {
   263         context.put(flowKey, this);
   264         names = Names.instance(context);
   265         log = Log.instance(context);
   266         syms = Symtab.instance(context);
   267         types = Types.instance(context);
   268         chk = Check.instance(context);
   269         lint = Lint.instance(context);
   270         rs = Resolve.instance(context);
   271         diags = JCDiagnostic.Factory.instance(context);
   272         Source source = Source.instance(context);
   273         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   274         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   275         allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
   276     }
   278     /**
   279      * Utility method to reset several Bits instances.
   280      */
   281     private void resetBits(Bits... bits) {
   282         for (Bits b : bits) {
   283             b.reset();
   284         }
   285     }
   287     /**
   288      * Base visitor class for all visitors implementing dataflow analysis logic.
   289      * This class define the shared logic for handling jumps (break/continue statements).
   290      */
   291     static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
   293         enum JumpKind {
   294             BREAK(JCTree.Tag.BREAK) {
   295                 @Override
   296                 JCTree getTarget(JCTree tree) {
   297                     return ((JCBreak)tree).target;
   298                 }
   299             },
   300             CONTINUE(JCTree.Tag.CONTINUE) {
   301                 @Override
   302                 JCTree getTarget(JCTree tree) {
   303                     return ((JCContinue)tree).target;
   304                 }
   305             };
   307             final JCTree.Tag treeTag;
   309             private JumpKind(Tag treeTag) {
   310                 this.treeTag = treeTag;
   311             }
   313             abstract JCTree getTarget(JCTree tree);
   314         }
   316         /** The currently pending exits that go from current inner blocks
   317          *  to an enclosing block, in source order.
   318          */
   319         ListBuffer<P> pendingExits;
   321         /** A pending exit.  These are the statements return, break, and
   322          *  continue.  In addition, exception-throwing expressions or
   323          *  statements are put here when not known to be caught.  This
   324          *  will typically result in an error unless it is within a
   325          *  try-finally whose finally block cannot complete normally.
   326          */
   327         static class PendingExit {
   328             JCTree tree;
   330             PendingExit(JCTree tree) {
   331                 this.tree = tree;
   332             }
   334             void resolveJump() {
   335                 //do nothing
   336             }
   337         }
   339         abstract void markDead();
   341         /** Record an outward transfer of control. */
   342         void recordExit(JCTree tree, P pe) {
   343             pendingExits.append(pe);
   344             markDead();
   345         }
   347         /** Resolve all jumps of this statement. */
   348         private boolean resolveJump(JCTree tree,
   349                         ListBuffer<P> oldPendingExits,
   350                         JumpKind jk) {
   351             boolean resolved = false;
   352             List<P> exits = pendingExits.toList();
   353             pendingExits = oldPendingExits;
   354             for (; exits.nonEmpty(); exits = exits.tail) {
   355                 P exit = exits.head;
   356                 if (exit.tree.hasTag(jk.treeTag) &&
   357                         jk.getTarget(exit.tree) == tree) {
   358                     exit.resolveJump();
   359                     resolved = true;
   360                 } else {
   361                     pendingExits.append(exit);
   362                 }
   363             }
   364             return resolved;
   365         }
   367         /** Resolve all breaks of this statement. */
   368         boolean resolveContinues(JCTree tree) {
   369             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
   370         }
   372         /** Resolve all continues of this statement. */
   373         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
   374             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   375         }
   377         @Override
   378         public void scan(JCTree tree) {
   379             if (tree != null && (
   380                     tree.type == null ||
   381                     tree.type != Type.stuckType)) {
   382                 super.scan(tree);
   383             }
   384         }
   385     }
   387     /**
   388      * This pass implements the first step of the dataflow analysis, namely
   389      * the liveness analysis check. This checks that every statement is reachable.
   390      * The output of this analysis pass are used by other analyzers. This analyzer
   391      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   392      */
   393     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
   395         /** A flag that indicates whether the last statement could
   396          *  complete normally.
   397          */
   398         private boolean alive;
   400         @Override
   401         void markDead() {
   402             alive = false;
   403         }
   405     /*************************************************************************
   406      * Visitor methods for statements and definitions
   407      *************************************************************************/
   409         /** Analyze a definition.
   410          */
   411         void scanDef(JCTree tree) {
   412             scanStat(tree);
   413             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
   414                 log.error(tree.pos(),
   415                           "initializer.must.be.able.to.complete.normally");
   416             }
   417         }
   419         /** Analyze a statement. Check that statement is reachable.
   420          */
   421         void scanStat(JCTree tree) {
   422             if (!alive && tree != null) {
   423                 log.error(tree.pos(), "unreachable.stmt");
   424                 if (!tree.hasTag(SKIP)) alive = true;
   425             }
   426             scan(tree);
   427         }
   429         /** Analyze list of statements.
   430          */
   431         void scanStats(List<? extends JCStatement> trees) {
   432             if (trees != null)
   433                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
   434                     scanStat(l.head);
   435         }
   437         /* ------------ Visitor methods for various sorts of trees -------------*/
   439         public void visitClassDef(JCClassDecl tree) {
   440             if (tree.sym == null) return;
   441             boolean alivePrev = alive;
   442             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   443             Lint lintPrev = lint;
   445             pendingExits = new ListBuffer<PendingExit>();
   446             lint = lint.augment(tree.sym);
   448             try {
   449                 // process all the static initializers
   450                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   451                     if (!l.head.hasTag(METHODDEF) &&
   452                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   453                         scanDef(l.head);
   454                     }
   455                 }
   457                 // process all the instance initializers
   458                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   459                     if (!l.head.hasTag(METHODDEF) &&
   460                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   461                         scanDef(l.head);
   462                     }
   463                 }
   465                 // process all the methods
   466                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   467                     if (l.head.hasTag(METHODDEF)) {
   468                         scan(l.head);
   469                     }
   470                 }
   471             } finally {
   472                 pendingExits = pendingExitsPrev;
   473                 alive = alivePrev;
   474                 lint = lintPrev;
   475             }
   476         }
   478         public void visitMethodDef(JCMethodDecl tree) {
   479             if (tree.body == null) return;
   480             Lint lintPrev = lint;
   482             lint = lint.augment(tree.sym);
   484             Assert.check(pendingExits.isEmpty());
   486             try {
   487                 alive = true;
   488                 scanStat(tree.body);
   490                 if (alive && !tree.sym.type.getReturnType().hasTag(VOID))
   491                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   493                 List<PendingExit> exits = pendingExits.toList();
   494                 pendingExits = new ListBuffer<PendingExit>();
   495                 while (exits.nonEmpty()) {
   496                     PendingExit exit = exits.head;
   497                     exits = exits.tail;
   498                     Assert.check(exit.tree.hasTag(RETURN));
   499                 }
   500             } finally {
   501                 lint = lintPrev;
   502             }
   503         }
   505         public void visitVarDef(JCVariableDecl tree) {
   506             if (tree.init != null) {
   507                 Lint lintPrev = lint;
   508                 lint = lint.augment(tree.sym);
   509                 try{
   510                     scan(tree.init);
   511                 } finally {
   512                     lint = lintPrev;
   513                 }
   514             }
   515         }
   517         public void visitBlock(JCBlock tree) {
   518             scanStats(tree.stats);
   519         }
   521         public void visitDoLoop(JCDoWhileLoop tree) {
   522             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   523             pendingExits = new ListBuffer<PendingExit>();
   524             scanStat(tree.body);
   525             alive |= resolveContinues(tree);
   526             scan(tree.cond);
   527             alive = alive && !tree.cond.type.isTrue();
   528             alive |= resolveBreaks(tree, prevPendingExits);
   529         }
   531         public void visitWhileLoop(JCWhileLoop tree) {
   532             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   533             pendingExits = new ListBuffer<PendingExit>();
   534             scan(tree.cond);
   535             alive = !tree.cond.type.isFalse();
   536             scanStat(tree.body);
   537             alive |= resolveContinues(tree);
   538             alive = resolveBreaks(tree, prevPendingExits) ||
   539                 !tree.cond.type.isTrue();
   540         }
   542         public void visitForLoop(JCForLoop tree) {
   543             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   544             scanStats(tree.init);
   545             pendingExits = new ListBuffer<PendingExit>();
   546             if (tree.cond != null) {
   547                 scan(tree.cond);
   548                 alive = !tree.cond.type.isFalse();
   549             } else {
   550                 alive = true;
   551             }
   552             scanStat(tree.body);
   553             alive |= resolveContinues(tree);
   554             scan(tree.step);
   555             alive = resolveBreaks(tree, prevPendingExits) ||
   556                 tree.cond != null && !tree.cond.type.isTrue();
   557         }
   559         public void visitForeachLoop(JCEnhancedForLoop tree) {
   560             visitVarDef(tree.var);
   561             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   562             scan(tree.expr);
   563             pendingExits = new ListBuffer<PendingExit>();
   564             scanStat(tree.body);
   565             alive |= resolveContinues(tree);
   566             resolveBreaks(tree, prevPendingExits);
   567             alive = true;
   568         }
   570         public void visitLabelled(JCLabeledStatement tree) {
   571             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   572             pendingExits = new ListBuffer<PendingExit>();
   573             scanStat(tree.body);
   574             alive |= resolveBreaks(tree, prevPendingExits);
   575         }
   577         public void visitSwitch(JCSwitch tree) {
   578             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   579             pendingExits = new ListBuffer<PendingExit>();
   580             scan(tree.selector);
   581             boolean hasDefault = false;
   582             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   583                 alive = true;
   584                 JCCase c = l.head;
   585                 if (c.pat == null)
   586                     hasDefault = true;
   587                 else
   588                     scan(c.pat);
   589                 scanStats(c.stats);
   590                 // Warn about fall-through if lint switch fallthrough enabled.
   591                 if (alive &&
   592                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   593                     c.stats.nonEmpty() && l.tail.nonEmpty())
   594                     log.warning(Lint.LintCategory.FALLTHROUGH,
   595                                 l.tail.head.pos(),
   596                                 "possible.fall-through.into.case");
   597             }
   598             if (!hasDefault) {
   599                 alive = true;
   600             }
   601             alive |= resolveBreaks(tree, prevPendingExits);
   602         }
   604         public void visitTry(JCTry tree) {
   605             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   606             pendingExits = new ListBuffer<PendingExit>();
   607             for (JCTree resource : tree.resources) {
   608                 if (resource instanceof JCVariableDecl) {
   609                     JCVariableDecl vdecl = (JCVariableDecl) resource;
   610                     visitVarDef(vdecl);
   611                 } else if (resource instanceof JCExpression) {
   612                     scan((JCExpression) resource);
   613                 } else {
   614                     throw new AssertionError(tree);  // parser error
   615                 }
   616             }
   618             scanStat(tree.body);
   619             boolean aliveEnd = alive;
   621             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   622                 alive = true;
   623                 JCVariableDecl param = l.head.param;
   624                 scan(param);
   625                 scanStat(l.head.body);
   626                 aliveEnd |= alive;
   627             }
   628             if (tree.finalizer != null) {
   629                 ListBuffer<PendingExit> exits = pendingExits;
   630                 pendingExits = prevPendingExits;
   631                 alive = true;
   632                 scanStat(tree.finalizer);
   633                 tree.finallyCanCompleteNormally = alive;
   634                 if (!alive) {
   635                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
   636                         log.warning(Lint.LintCategory.FINALLY,
   637                                 TreeInfo.diagEndPos(tree.finalizer),
   638                                 "finally.cannot.complete");
   639                     }
   640                 } else {
   641                     while (exits.nonEmpty()) {
   642                         pendingExits.append(exits.next());
   643                     }
   644                     alive = aliveEnd;
   645                 }
   646             } else {
   647                 alive = aliveEnd;
   648                 ListBuffer<PendingExit> exits = pendingExits;
   649                 pendingExits = prevPendingExits;
   650                 while (exits.nonEmpty()) pendingExits.append(exits.next());
   651             }
   652         }
   654         @Override
   655         public void visitIf(JCIf tree) {
   656             scan(tree.cond);
   657             scanStat(tree.thenpart);
   658             if (tree.elsepart != null) {
   659                 boolean aliveAfterThen = alive;
   660                 alive = true;
   661                 scanStat(tree.elsepart);
   662                 alive = alive | aliveAfterThen;
   663             } else {
   664                 alive = true;
   665             }
   666         }
   668         public void visitBreak(JCBreak tree) {
   669             recordExit(tree, new PendingExit(tree));
   670         }
   672         public void visitContinue(JCContinue tree) {
   673             recordExit(tree, new PendingExit(tree));
   674         }
   676         public void visitReturn(JCReturn tree) {
   677             scan(tree.expr);
   678             recordExit(tree, new PendingExit(tree));
   679         }
   681         public void visitThrow(JCThrow tree) {
   682             scan(tree.expr);
   683             markDead();
   684         }
   686         public void visitApply(JCMethodInvocation tree) {
   687             scan(tree.meth);
   688             scan(tree.args);
   689         }
   691         public void visitNewClass(JCNewClass tree) {
   692             scan(tree.encl);
   693             scan(tree.args);
   694             if (tree.def != null) {
   695                 scan(tree.def);
   696             }
   697         }
   699         @Override
   700         public void visitLambda(JCLambda tree) {
   701             if (tree.type != null &&
   702                     tree.type.isErroneous()) {
   703                 return;
   704             }
   706             ListBuffer<PendingExit> prevPending = pendingExits;
   707             boolean prevAlive = alive;
   708             try {
   709                 pendingExits = ListBuffer.lb();
   710                 alive = true;
   711                 scanStat(tree.body);
   712                 tree.canCompleteNormally = alive;
   713             }
   714             finally {
   715                 pendingExits = prevPending;
   716                 alive = prevAlive;
   717             }
   718         }
   720         public void visitTopLevel(JCCompilationUnit tree) {
   721             // Do nothing for TopLevel since each class is visited individually
   722         }
   724     /**************************************************************************
   725      * main method
   726      *************************************************************************/
   728         /** Perform definite assignment/unassignment analysis on a tree.
   729          */
   730         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   731             analyzeTree(env, env.tree, make);
   732         }
   733         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
   734             try {
   735                 attrEnv = env;
   736                 Flow.this.make = make;
   737                 pendingExits = new ListBuffer<PendingExit>();
   738                 alive = true;
   739                 scan(tree);
   740             } finally {
   741                 pendingExits = null;
   742                 Flow.this.make = null;
   743             }
   744         }
   745     }
   747     /**
   748      * This pass implements the second step of the dataflow analysis, namely
   749      * the exception analysis. This is to ensure that every checked exception that is
   750      * thrown is declared or caught. The analyzer uses some info that has been set by
   751      * the liveliness analyzer.
   752      */
   753     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   755         /** A flag that indicates whether the last statement could
   756          *  complete normally.
   757          */
   758         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   760         /** The current class being defined.
   761          */
   762         JCClassDecl classDef;
   764         /** The list of possibly thrown declarable exceptions.
   765          */
   766         List<Type> thrown;
   768         /** The list of exceptions that are either caught or declared to be
   769          *  thrown.
   770          */
   771         List<Type> caught;
   773         class FlowPendingExit extends BaseAnalyzer.PendingExit {
   775             Type thrown;
   777             FlowPendingExit(JCTree tree, Type thrown) {
   778                 super(tree);
   779                 this.thrown = thrown;
   780             }
   781         }
   783         @Override
   784         void markDead() {
   785             //do nothing
   786         }
   788         /*-------------------- Exceptions ----------------------*/
   790         /** Complain that pending exceptions are not caught.
   791          */
   792         void errorUncaught() {
   793             for (FlowPendingExit exit = pendingExits.next();
   794                  exit != null;
   795                  exit = pendingExits.next()) {
   796                 if (classDef != null &&
   797                     classDef.pos == exit.tree.pos) {
   798                     log.error(exit.tree.pos(),
   799                             "unreported.exception.default.constructor",
   800                             exit.thrown);
   801                 } else if (exit.tree.hasTag(VARDEF) &&
   802                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   803                     log.error(exit.tree.pos(),
   804                             "unreported.exception.implicit.close",
   805                             exit.thrown,
   806                             ((JCVariableDecl)exit.tree).sym.name);
   807                 } else {
   808                     log.error(exit.tree.pos(),
   809                             "unreported.exception.need.to.catch.or.throw",
   810                             exit.thrown);
   811                 }
   812             }
   813         }
   815         /** Record that exception is potentially thrown and check that it
   816          *  is caught.
   817          */
   818         void markThrown(JCTree tree, Type exc) {
   819             if (!chk.isUnchecked(tree.pos(), exc)) {
   820                 if (!chk.isHandled(exc, caught)) {
   821                     pendingExits.append(new FlowPendingExit(tree, exc));
   822                 }
   823                 thrown = chk.incl(exc, thrown);
   824             }
   825         }
   827     /*************************************************************************
   828      * Visitor methods for statements and definitions
   829      *************************************************************************/
   831         /* ------------ Visitor methods for various sorts of trees -------------*/
   833         public void visitClassDef(JCClassDecl tree) {
   834             if (tree.sym == null) return;
   836             JCClassDecl classDefPrev = classDef;
   837             List<Type> thrownPrev = thrown;
   838             List<Type> caughtPrev = caught;
   839             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   840             Lint lintPrev = lint;
   842             pendingExits = new ListBuffer<FlowPendingExit>();
   843             if (tree.name != names.empty) {
   844                 caught = List.nil();
   845             }
   846             classDef = tree;
   847             thrown = List.nil();
   848             lint = lint.augment(tree.sym);
   850             try {
   851                 // process all the static initializers
   852                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   853                     if (!l.head.hasTag(METHODDEF) &&
   854                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   855                         scan(l.head);
   856                         errorUncaught();
   857                     }
   858                 }
   860                 // add intersection of all thrown clauses of initial constructors
   861                 // to set of caught exceptions, unless class is anonymous.
   862                 if (tree.name != names.empty) {
   863                     boolean firstConstructor = true;
   864                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   865                         if (TreeInfo.isInitialConstructor(l.head)) {
   866                             List<Type> mthrown =
   867                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
   868                             if (firstConstructor) {
   869                                 caught = mthrown;
   870                                 firstConstructor = false;
   871                             } else {
   872                                 caught = chk.intersect(mthrown, caught);
   873                             }
   874                         }
   875                     }
   876                 }
   878                 // process all the instance initializers
   879                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   880                     if (!l.head.hasTag(METHODDEF) &&
   881                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   882                         scan(l.head);
   883                         errorUncaught();
   884                     }
   885                 }
   887                 // in an anonymous class, add the set of thrown exceptions to
   888                 // the throws clause of the synthetic constructor and propagate
   889                 // outwards.
   890                 // Changing the throws clause on the fly is okay here because
   891                 // the anonymous constructor can't be invoked anywhere else,
   892                 // and its type hasn't been cached.
   893                 if (tree.name == names.empty) {
   894                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   895                         if (TreeInfo.isInitialConstructor(l.head)) {
   896                             JCMethodDecl mdef = (JCMethodDecl)l.head;
   897                             mdef.thrown = make.Types(thrown);
   898                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
   899                         }
   900                     }
   901                     thrownPrev = chk.union(thrown, thrownPrev);
   902                 }
   904                 // process all the methods
   905                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   906                     if (l.head.hasTag(METHODDEF)) {
   907                         scan(l.head);
   908                         errorUncaught();
   909                     }
   910                 }
   912                 thrown = thrownPrev;
   913             } finally {
   914                 pendingExits = pendingExitsPrev;
   915                 caught = caughtPrev;
   916                 classDef = classDefPrev;
   917                 lint = lintPrev;
   918             }
   919         }
   921         public void visitMethodDef(JCMethodDecl tree) {
   922             if (tree.body == null) return;
   924             List<Type> caughtPrev = caught;
   925             List<Type> mthrown = tree.sym.type.getThrownTypes();
   926             Lint lintPrev = lint;
   928             lint = lint.augment(tree.sym);
   930             Assert.check(pendingExits.isEmpty());
   932             try {
   933                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   934                     JCVariableDecl def = l.head;
   935                     scan(def);
   936                 }
   937                 if (TreeInfo.isInitialConstructor(tree))
   938                     caught = chk.union(caught, mthrown);
   939                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   940                     caught = mthrown;
   941                 // else we are in an instance initializer block;
   942                 // leave caught unchanged.
   944                 scan(tree.body);
   946                 List<FlowPendingExit> exits = pendingExits.toList();
   947                 pendingExits = new ListBuffer<FlowPendingExit>();
   948                 while (exits.nonEmpty()) {
   949                     FlowPendingExit exit = exits.head;
   950                     exits = exits.tail;
   951                     if (exit.thrown == null) {
   952                         Assert.check(exit.tree.hasTag(RETURN));
   953                     } else {
   954                         // uncaught throws will be reported later
   955                         pendingExits.append(exit);
   956                     }
   957                 }
   958             } finally {
   959                 caught = caughtPrev;
   960                 lint = lintPrev;
   961             }
   962         }
   964         public void visitVarDef(JCVariableDecl tree) {
   965             if (tree.init != null) {
   966                 Lint lintPrev = lint;
   967                 lint = lint.augment(tree.sym);
   968                 try{
   969                     scan(tree.init);
   970                 } finally {
   971                     lint = lintPrev;
   972                 }
   973             }
   974         }
   976         public void visitBlock(JCBlock tree) {
   977             scan(tree.stats);
   978         }
   980         public void visitDoLoop(JCDoWhileLoop tree) {
   981             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   982             pendingExits = new ListBuffer<FlowPendingExit>();
   983             scan(tree.body);
   984             resolveContinues(tree);
   985             scan(tree.cond);
   986             resolveBreaks(tree, prevPendingExits);
   987         }
   989         public void visitWhileLoop(JCWhileLoop tree) {
   990             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   991             pendingExits = new ListBuffer<FlowPendingExit>();
   992             scan(tree.cond);
   993             scan(tree.body);
   994             resolveContinues(tree);
   995             resolveBreaks(tree, prevPendingExits);
   996         }
   998         public void visitForLoop(JCForLoop tree) {
   999             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1000             scan(tree.init);
  1001             pendingExits = new ListBuffer<FlowPendingExit>();
  1002             if (tree.cond != null) {
  1003                 scan(tree.cond);
  1005             scan(tree.body);
  1006             resolveContinues(tree);
  1007             scan(tree.step);
  1008             resolveBreaks(tree, prevPendingExits);
  1011         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1012             visitVarDef(tree.var);
  1013             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1014             scan(tree.expr);
  1015             pendingExits = new ListBuffer<FlowPendingExit>();
  1016             scan(tree.body);
  1017             resolveContinues(tree);
  1018             resolveBreaks(tree, prevPendingExits);
  1021         public void visitLabelled(JCLabeledStatement tree) {
  1022             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1023             pendingExits = new ListBuffer<FlowPendingExit>();
  1024             scan(tree.body);
  1025             resolveBreaks(tree, prevPendingExits);
  1028         public void visitSwitch(JCSwitch tree) {
  1029             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1030             pendingExits = new ListBuffer<FlowPendingExit>();
  1031             scan(tree.selector);
  1032             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1033                 JCCase c = l.head;
  1034                 if (c.pat != null) {
  1035                     scan(c.pat);
  1037                 scan(c.stats);
  1039             resolveBreaks(tree, prevPendingExits);
  1042         public void visitTry(JCTry tree) {
  1043             List<Type> caughtPrev = caught;
  1044             List<Type> thrownPrev = thrown;
  1045             thrown = List.nil();
  1046             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1047                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1048                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1049                         List.of(l.head.param.vartype);
  1050                 for (JCExpression ct : subClauses) {
  1051                     caught = chk.incl(ct.type, caught);
  1055             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1056             pendingExits = new ListBuffer<FlowPendingExit>();
  1057             for (JCTree resource : tree.resources) {
  1058                 if (resource instanceof JCVariableDecl) {
  1059                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1060                     visitVarDef(vdecl);
  1061                 } else if (resource instanceof JCExpression) {
  1062                     scan((JCExpression) resource);
  1063                 } else {
  1064                     throw new AssertionError(tree);  // parser error
  1067             for (JCTree resource : tree.resources) {
  1068                 List<Type> closeableSupertypes = resource.type.isCompound() ?
  1069                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
  1070                     List.of(resource.type);
  1071                 for (Type sup : closeableSupertypes) {
  1072                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
  1073                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
  1074                                 attrEnv,
  1075                                 sup,
  1076                                 names.close,
  1077                                 List.<Type>nil(),
  1078                                 List.<Type>nil());
  1079                         Type mt = types.memberType(resource.type, closeMethod);
  1080                         if (closeMethod.kind == MTH) {
  1081                             for (Type t : mt.getThrownTypes()) {
  1082                                 markThrown(resource, t);
  1088             scan(tree.body);
  1089             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1090                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1091                 thrown;
  1092             thrown = thrownPrev;
  1093             caught = caughtPrev;
  1095             List<Type> caughtInTry = List.nil();
  1096             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1097                 JCVariableDecl param = l.head.param;
  1098                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1099                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1100                         List.of(l.head.param.vartype);
  1101                 List<Type> ctypes = List.nil();
  1102                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
  1103                 for (JCExpression ct : subClauses) {
  1104                     Type exc = ct.type;
  1105                     if (exc != syms.unknownType) {
  1106                         ctypes = ctypes.append(exc);
  1107                         if (types.isSameType(exc, syms.objectType))
  1108                             continue;
  1109                         checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
  1110                         caughtInTry = chk.incl(exc, caughtInTry);
  1113                 scan(param);
  1114                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1115                 scan(l.head.body);
  1116                 preciseRethrowTypes.remove(param.sym);
  1118             if (tree.finalizer != null) {
  1119                 List<Type> savedThrown = thrown;
  1120                 thrown = List.nil();
  1121                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1122                 pendingExits = prevPendingExits;
  1123                 scan(tree.finalizer);
  1124                 if (!tree.finallyCanCompleteNormally) {
  1125                     // discard exits and exceptions from try and finally
  1126                     thrown = chk.union(thrown, thrownPrev);
  1127                 } else {
  1128                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1129                     thrown = chk.union(thrown, savedThrown);
  1130                     // FIX: this doesn't preserve source order of exits in catch
  1131                     // versus finally!
  1132                     while (exits.nonEmpty()) {
  1133                         pendingExits.append(exits.next());
  1136             } else {
  1137                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1138                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1139                 pendingExits = prevPendingExits;
  1140                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1144         @Override
  1145         public void visitIf(JCIf tree) {
  1146             scan(tree.cond);
  1147             scan(tree.thenpart);
  1148             if (tree.elsepart != null) {
  1149                 scan(tree.elsepart);
  1153         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1154             if (chk.subset(exc, caughtInTry)) {
  1155                 log.error(pos, "except.already.caught", exc);
  1156             } else if (!chk.isUnchecked(pos, exc) &&
  1157                     !isExceptionOrThrowable(exc) &&
  1158                     !chk.intersects(exc, thrownInTry)) {
  1159                 log.error(pos, "except.never.thrown.in.try", exc);
  1160             } else if (allowImprovedCatchAnalysis) {
  1161                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
  1162                 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
  1163                 // unchecked exception, the result list would not be empty, as the augmented
  1164                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
  1165                 // exception, that would have been covered in the branch above
  1166                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
  1167                         !isExceptionOrThrowable(exc)) {
  1168                     String key = catchableThrownTypes.length() == 1 ?
  1169                             "unreachable.catch" :
  1170                             "unreachable.catch.1";
  1171                     log.warning(pos, key, catchableThrownTypes);
  1175         //where
  1176             private boolean isExceptionOrThrowable(Type exc) {
  1177                 return exc.tsym == syms.throwableType.tsym ||
  1178                     exc.tsym == syms.exceptionType.tsym;
  1181         public void visitBreak(JCBreak tree) {
  1182             recordExit(tree, new FlowPendingExit(tree, null));
  1185         public void visitContinue(JCContinue tree) {
  1186             recordExit(tree, new FlowPendingExit(tree, null));
  1189         public void visitReturn(JCReturn tree) {
  1190             scan(tree.expr);
  1191             recordExit(tree, new FlowPendingExit(tree, null));
  1194         public void visitThrow(JCThrow tree) {
  1195             scan(tree.expr);
  1196             Symbol sym = TreeInfo.symbol(tree.expr);
  1197             if (sym != null &&
  1198                 sym.kind == VAR &&
  1199                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
  1200                 preciseRethrowTypes.get(sym) != null &&
  1201                 allowImprovedRethrowAnalysis) {
  1202                 for (Type t : preciseRethrowTypes.get(sym)) {
  1203                     markThrown(tree, t);
  1206             else {
  1207                 markThrown(tree, tree.expr.type);
  1209             markDead();
  1212         public void visitApply(JCMethodInvocation tree) {
  1213             scan(tree.meth);
  1214             scan(tree.args);
  1215             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
  1216                 markThrown(tree, l.head);
  1219         public void visitNewClass(JCNewClass tree) {
  1220             scan(tree.encl);
  1221             scan(tree.args);
  1222            // scan(tree.def);
  1223             for (List<Type> l = tree.constructorType.getThrownTypes();
  1224                  l.nonEmpty();
  1225                  l = l.tail) {
  1226                 markThrown(tree, l.head);
  1228             List<Type> caughtPrev = caught;
  1229             try {
  1230                 // If the new class expression defines an anonymous class,
  1231                 // analysis of the anonymous constructor may encounter thrown
  1232                 // types which are unsubstituted type variables.
  1233                 // However, since the constructor's actual thrown types have
  1234                 // already been marked as thrown, it is safe to simply include
  1235                 // each of the constructor's formal thrown types in the set of
  1236                 // 'caught/declared to be thrown' types, for the duration of
  1237                 // the class def analysis.
  1238                 if (tree.def != null)
  1239                     for (List<Type> l = tree.constructor.type.getThrownTypes();
  1240                          l.nonEmpty();
  1241                          l = l.tail) {
  1242                         caught = chk.incl(l.head, caught);
  1244                 scan(tree.def);
  1246             finally {
  1247                 caught = caughtPrev;
  1251         @Override
  1252         public void visitLambda(JCLambda tree) {
  1253             if (tree.type != null &&
  1254                     tree.type.isErroneous()) {
  1255                 return;
  1257             List<Type> prevCaught = caught;
  1258             List<Type> prevThrown = thrown;
  1259             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1260             try {
  1261                 pendingExits = ListBuffer.lb();
  1262                 caught = tree.getDescriptorType(types).getThrownTypes();
  1263                 thrown = List.nil();
  1264                 scan(tree.body);
  1265                 List<FlowPendingExit> exits = pendingExits.toList();
  1266                 pendingExits = new ListBuffer<FlowPendingExit>();
  1267                 while (exits.nonEmpty()) {
  1268                     FlowPendingExit exit = exits.head;
  1269                     exits = exits.tail;
  1270                     if (exit.thrown == null) {
  1271                         Assert.check(exit.tree.hasTag(RETURN));
  1272                     } else {
  1273                         // uncaught throws will be reported later
  1274                         pendingExits.append(exit);
  1278                 errorUncaught();
  1279             } finally {
  1280                 pendingExits = prevPending;
  1281                 caught = prevCaught;
  1282                 thrown = prevThrown;
  1286         public void visitTopLevel(JCCompilationUnit tree) {
  1287             // Do nothing for TopLevel since each class is visited individually
  1290     /**************************************************************************
  1291      * main method
  1292      *************************************************************************/
  1294         /** Perform definite assignment/unassignment analysis on a tree.
  1295          */
  1296         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1297             analyzeTree(env, env.tree, make);
  1299         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  1300             try {
  1301                 attrEnv = env;
  1302                 Flow.this.make = make;
  1303                 pendingExits = new ListBuffer<FlowPendingExit>();
  1304                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1305                 this.thrown = this.caught = null;
  1306                 this.classDef = null;
  1307                 scan(tree);
  1308             } finally {
  1309                 pendingExits = null;
  1310                 Flow.this.make = null;
  1311                 this.thrown = this.caught = null;
  1312                 this.classDef = null;
  1317     /**
  1318      * Specialized pass that performs inference of thrown types for lambdas.
  1319      */
  1320     class LambdaFlowAnalyzer extends FlowAnalyzer {
  1321         @Override
  1322         public void visitLambda(JCLambda tree) {
  1323             if (tree.type != null &&
  1324                     tree.type.isErroneous()) {
  1325                 return;
  1327             List<Type> prevCaught = caught;
  1328             List<Type> prevThrown = thrown;
  1329             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1330             try {
  1331                 pendingExits = ListBuffer.lb();
  1332                 caught = List.of(syms.throwableType);
  1333                 thrown = List.nil();
  1334                 scan(tree.body);
  1335                 tree.inferredThrownTypes = thrown;
  1336             } finally {
  1337                 pendingExits = prevPending;
  1338                 caught = prevCaught;
  1339                 thrown = prevThrown;
  1344     /**
  1345      * This pass implements (i) definite assignment analysis, which ensures that
  1346      * each variable is assigned when used and (ii) definite unassignment analysis,
  1347      * which ensures that no final variable is assigned more than once. This visitor
  1348      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1349      * effectively-final local variables/parameters.
  1350      */
  1351     class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
  1353         /** The set of definitely assigned variables.
  1354          */
  1355         final Bits inits;
  1357         /** The set of definitely unassigned variables.
  1358          */
  1359         final Bits uninits;
  1361         /** The set of variables that are definitely unassigned everywhere
  1362          *  in current try block. This variable is maintained lazily; it is
  1363          *  updated only when something gets removed from uninits,
  1364          *  typically by being assigned in reachable code.  To obtain the
  1365          *  correct set of variables which are definitely unassigned
  1366          *  anywhere in current try block, intersect uninitsTry and
  1367          *  uninits.
  1368          */
  1369         final Bits uninitsTry;
  1371         /** When analyzing a condition, inits and uninits are null.
  1372          *  Instead we have:
  1373          */
  1374         final Bits initsWhenTrue;
  1375         final Bits initsWhenFalse;
  1376         final Bits uninitsWhenTrue;
  1377         final Bits uninitsWhenFalse;
  1379         /** A mapping from addresses to variable symbols.
  1380          */
  1381         JCVariableDecl[] vardecls;
  1383         /** The current class being defined.
  1384          */
  1385         JCClassDecl classDef;
  1387         /** The first variable sequence number in this class definition.
  1388          */
  1389         int firstadr;
  1391         /** The next available variable sequence number.
  1392          */
  1393         int nextadr;
  1395         /** The first variable sequence number in a block that can return.
  1396          */
  1397         int returnadr;
  1399         /** The list of unreferenced automatic resources.
  1400          */
  1401         Scope unrefdResources;
  1403         /** Set when processing a loop body the second time for DU analysis. */
  1404         FlowKind flowKind = FlowKind.NORMAL;
  1406         /** The starting position of the analysed tree */
  1407         int startPos;
  1409         AssignAnalyzer() {
  1410             inits = new Bits();
  1411             uninits = new Bits();
  1412             uninitsTry = new Bits();
  1413             initsWhenTrue = new Bits(true);
  1414             initsWhenFalse = new Bits(true);
  1415             uninitsWhenTrue = new Bits(true);
  1416             uninitsWhenFalse = new Bits(true);
  1419         class AssignPendingExit extends BaseAnalyzer.PendingExit {
  1421             final Bits exit_inits = new Bits(true);
  1422             final Bits exit_uninits = new Bits(true);
  1424             AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
  1425                 super(tree);
  1426                 this.exit_inits.assign(inits);
  1427                 this.exit_uninits.assign(uninits);
  1430             void resolveJump() {
  1431                 inits.andSet(exit_inits);
  1432                 uninits.andSet(exit_uninits);
  1436         @Override
  1437         void markDead() {
  1438             inits.inclRange(returnadr, nextadr);
  1439             uninits.inclRange(returnadr, nextadr);
  1442         /*-------------- Processing variables ----------------------*/
  1444         /** Do we need to track init/uninit state of this symbol?
  1445          *  I.e. is symbol either a local or a blank final variable?
  1446          */
  1447         boolean trackable(VarSymbol sym) {
  1448             return
  1449                 sym.pos >= startPos &&
  1450                 ((sym.owner.kind == MTH ||
  1451                  ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1452                   classDef.sym.isEnclosedBy((ClassSymbol)sym.owner))));
  1455         /** Initialize new trackable variable by setting its address field
  1456          *  to the next available sequence number and entering it under that
  1457          *  index into the vars array.
  1458          */
  1459         void newVar(JCVariableDecl varDecl) {
  1460             VarSymbol sym = varDecl.sym;
  1461             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
  1462             if ((sym.flags() & FINAL) == 0) {
  1463                 sym.flags_field |= EFFECTIVELY_FINAL;
  1465             sym.adr = nextadr;
  1466             vardecls[nextadr] = varDecl;
  1467             inits.excl(nextadr);
  1468             uninits.incl(nextadr);
  1469             nextadr++;
  1472         /** Record an initialization of a trackable variable.
  1473          */
  1474         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1475             if (sym.adr >= firstadr && trackable(sym)) {
  1476                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
  1477                     if (!uninits.isMember(sym.adr)) {
  1478                         //assignment targeting an effectively final variable
  1479                         //makes the variable lose its status of effectively final
  1480                         //if the variable is _not_ definitively unassigned
  1481                         sym.flags_field &= ~EFFECTIVELY_FINAL;
  1482                     } else {
  1483                         uninit(sym);
  1486                 else if ((sym.flags() & FINAL) != 0) {
  1487                     if ((sym.flags() & PARAMETER) != 0) {
  1488                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  1489                             log.error(pos, "multicatch.parameter.may.not.be.assigned",
  1490                                       sym);
  1492                         else {
  1493                             log.error(pos, "final.parameter.may.not.be.assigned",
  1494                                   sym);
  1496                     } else if (!uninits.isMember(sym.adr)) {
  1497                         log.error(pos, flowKind.errKey, sym);
  1498                     } else {
  1499                         uninit(sym);
  1502                 inits.incl(sym.adr);
  1503             } else if ((sym.flags() & FINAL) != 0) {
  1504                 log.error(pos, "var.might.already.be.assigned", sym);
  1507         //where
  1508             void uninit(VarSymbol sym) {
  1509                 if (!inits.isMember(sym.adr)) {
  1510                     // reachable assignment
  1511                     uninits.excl(sym.adr);
  1512                     uninitsTry.excl(sym.adr);
  1513                 } else {
  1514                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
  1515                     uninits.excl(sym.adr);
  1519         /** If tree is either a simple name or of the form this.name or
  1520          *  C.this.name, and tree represents a trackable variable,
  1521          *  record an initialization of the variable.
  1522          */
  1523         void letInit(JCTree tree) {
  1524             tree = TreeInfo.skipParens(tree);
  1525             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  1526                 Symbol sym = TreeInfo.symbol(tree);
  1527                 if (sym.kind == VAR) {
  1528                     letInit(tree.pos(), (VarSymbol)sym);
  1533         /** Check that trackable variable is initialized.
  1534          */
  1535         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
  1536             checkInit(pos, sym, "var.might.not.have.been.initialized");
  1538         void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
  1539             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  1540                 trackable(sym) &&
  1541                 !inits.isMember(sym.adr)) {
  1542                 log.error(pos, errkey, sym);
  1543                 inits.incl(sym.adr);
  1547         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
  1548          */
  1549         void split(boolean setToNull) {
  1550             initsWhenFalse.assign(inits);
  1551             uninitsWhenFalse.assign(uninits);
  1552             initsWhenTrue.assign(inits);
  1553             uninitsWhenTrue.assign(uninits);
  1554             if (setToNull) {
  1555                 resetBits(inits, uninits);
  1559         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
  1560          */
  1561         void merge() {
  1562             inits.assign(initsWhenFalse.andSet(initsWhenTrue));
  1563             uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
  1566     /* ************************************************************************
  1567      * Visitor methods for statements and definitions
  1568      *************************************************************************/
  1570         /** Analyze an expression. Make sure to set (un)inits rather than
  1571          *  (un)initsWhenTrue(WhenFalse) on exit.
  1572          */
  1573         void scanExpr(JCTree tree) {
  1574             if (tree != null) {
  1575                 scan(tree);
  1576                 if (inits.isReset()) merge();
  1580         /** Analyze a list of expressions.
  1581          */
  1582         void scanExprs(List<? extends JCExpression> trees) {
  1583             if (trees != null)
  1584                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
  1585                     scanExpr(l.head);
  1588         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
  1589          *  rather than (un)inits on exit.
  1590          */
  1591         void scanCond(JCTree tree) {
  1592             if (tree.type.isFalse()) {
  1593                 if (inits.isReset()) merge();
  1594                 initsWhenTrue.assign(inits);
  1595                 initsWhenTrue.inclRange(firstadr, nextadr);
  1596                 uninitsWhenTrue.assign(uninits);
  1597                 uninitsWhenTrue.inclRange(firstadr, nextadr);
  1598                 initsWhenFalse.assign(inits);
  1599                 uninitsWhenFalse.assign(uninits);
  1600             } else if (tree.type.isTrue()) {
  1601                 if (inits.isReset()) merge();
  1602                 initsWhenFalse.assign(inits);
  1603                 initsWhenFalse.inclRange(firstadr, nextadr);
  1604                 uninitsWhenFalse.assign(uninits);
  1605                 uninitsWhenFalse.inclRange(firstadr, nextadr);
  1606                 initsWhenTrue.assign(inits);
  1607                 uninitsWhenTrue.assign(uninits);
  1608             } else {
  1609                 scan(tree);
  1610                 if (!inits.isReset())
  1611                     split(tree.type != syms.unknownType);
  1613             if (tree.type != syms.unknownType) {
  1614                 resetBits(inits, uninits);
  1618         /* ------------ Visitor methods for various sorts of trees -------------*/
  1620         public void visitClassDef(JCClassDecl tree) {
  1621             if (tree.sym == null) return;
  1623             JCClassDecl classDefPrev = classDef;
  1624             int firstadrPrev = firstadr;
  1625             int nextadrPrev = nextadr;
  1626             ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
  1627             Lint lintPrev = lint;
  1629             pendingExits = new ListBuffer<AssignPendingExit>();
  1630             if (tree.name != names.empty) {
  1631                 firstadr = nextadr;
  1633             classDef = tree;
  1634             lint = lint.augment(tree.sym);
  1636             try {
  1637                 // define all the static fields
  1638                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1639                     if (l.head.hasTag(VARDEF)) {
  1640                         JCVariableDecl def = (JCVariableDecl)l.head;
  1641                         if ((def.mods.flags & STATIC) != 0) {
  1642                             VarSymbol sym = def.sym;
  1643                             if (trackable(sym))
  1644                                 newVar(def);
  1649                 // process all the static initializers
  1650                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1651                     if (!l.head.hasTag(METHODDEF) &&
  1652                         (TreeInfo.flags(l.head) & STATIC) != 0) {
  1653                         scan(l.head);
  1657                 // define all the instance fields
  1658                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1659                     if (l.head.hasTag(VARDEF)) {
  1660                         JCVariableDecl def = (JCVariableDecl)l.head;
  1661                         if ((def.mods.flags & STATIC) == 0) {
  1662                             VarSymbol sym = def.sym;
  1663                             if (trackable(sym))
  1664                                 newVar(def);
  1669                 // process all the instance initializers
  1670                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1671                     if (!l.head.hasTag(METHODDEF) &&
  1672                         (TreeInfo.flags(l.head) & STATIC) == 0) {
  1673                         scan(l.head);
  1677                 // process all the methods
  1678                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1679                     if (l.head.hasTag(METHODDEF)) {
  1680                         scan(l.head);
  1683             } finally {
  1684                 pendingExits = pendingExitsPrev;
  1685                 nextadr = nextadrPrev;
  1686                 firstadr = firstadrPrev;
  1687                 classDef = classDefPrev;
  1688                 lint = lintPrev;
  1692         public void visitMethodDef(JCMethodDecl tree) {
  1693             if (tree.body == null) return;
  1695             final Bits initsPrev = new Bits(inits);
  1696             final Bits uninitsPrev = new Bits(uninits);
  1697             int nextadrPrev = nextadr;
  1698             int firstadrPrev = firstadr;
  1699             int returnadrPrev = returnadr;
  1700             Lint lintPrev = lint;
  1702             lint = lint.augment(tree.sym);
  1704             Assert.check(pendingExits.isEmpty());
  1706             try {
  1707                 boolean isInitialConstructor =
  1708                     TreeInfo.isInitialConstructor(tree);
  1710                 if (!isInitialConstructor)
  1711                     firstadr = nextadr;
  1712                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  1713                     JCVariableDecl def = l.head;
  1714                     scan(def);
  1715                     inits.incl(def.sym.adr);
  1716                     uninits.excl(def.sym.adr);
  1718                 // else we are in an instance initializer block;
  1719                 // leave caught unchanged.
  1720                 scan(tree.body);
  1722                 if (isInitialConstructor) {
  1723                     boolean isSynthesized = (tree.sym.flags() &
  1724                                              GENERATEDCONSTR) != 0;
  1725                     for (int i = firstadr; i < nextadr; i++) {
  1726                         JCVariableDecl vardecl = vardecls[i];
  1727                         VarSymbol var = vardecl.sym;
  1728                         if (var.owner == classDef.sym) {
  1729                             // choose the diagnostic position based on whether
  1730                             // the ctor is default(synthesized) or not
  1731                             if (isSynthesized) {
  1732                                 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
  1733                                     var, "var.not.initialized.in.default.constructor");
  1734                             } else {
  1735                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
  1740                 List<AssignPendingExit> exits = pendingExits.toList();
  1741                 pendingExits = new ListBuffer<AssignPendingExit>();
  1742                 while (exits.nonEmpty()) {
  1743                     AssignPendingExit exit = exits.head;
  1744                     exits = exits.tail;
  1745                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1746                     if (isInitialConstructor) {
  1747                         inits.assign(exit.exit_inits);
  1748                         for (int i = firstadr; i < nextadr; i++)
  1749                             checkInit(exit.tree.pos(), vardecls[i].sym);
  1752             } finally {
  1753                 inits.assign(initsPrev);
  1754                 uninits.assign(uninitsPrev);
  1755                 nextadr = nextadrPrev;
  1756                 firstadr = firstadrPrev;
  1757                 returnadr = returnadrPrev;
  1758                 lint = lintPrev;
  1762         public void visitVarDef(JCVariableDecl tree) {
  1763             boolean track = trackable(tree.sym);
  1764             if (track && tree.sym.owner.kind == MTH) newVar(tree);
  1765             if (tree.init != null) {
  1766                 Lint lintPrev = lint;
  1767                 lint = lint.augment(tree.sym);
  1768                 try{
  1769                     scanExpr(tree.init);
  1770                     if (track) letInit(tree.pos(), tree.sym);
  1771                 } finally {
  1772                     lint = lintPrev;
  1777         public void visitBlock(JCBlock tree) {
  1778             int nextadrPrev = nextadr;
  1779             scan(tree.stats);
  1780             nextadr = nextadrPrev;
  1783         public void visitDoLoop(JCDoWhileLoop tree) {
  1784             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1785             FlowKind prevFlowKind = flowKind;
  1786             flowKind = FlowKind.NORMAL;
  1787             final Bits initsSkip = new Bits(true);
  1788             final Bits uninitsSkip = new Bits(true);
  1789             pendingExits = new ListBuffer<AssignPendingExit>();
  1790             int prevErrors = log.nerrors;
  1791             do {
  1792                 final Bits uninitsEntry = new Bits(uninits);
  1793                 uninitsEntry.excludeFrom(nextadr);
  1794                 scan(tree.body);
  1795                 resolveContinues(tree);
  1796                 scanCond(tree.cond);
  1797                 if (!flowKind.isFinal()) {
  1798                     initsSkip.assign(initsWhenFalse);
  1799                     uninitsSkip.assign(uninitsWhenFalse);
  1801                 if (log.nerrors !=  prevErrors ||
  1802                     flowKind.isFinal() ||
  1803                     new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1804                     break;
  1805                 inits.assign(initsWhenTrue);
  1806                 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
  1807                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1808             } while (true);
  1809             flowKind = prevFlowKind;
  1810             inits.assign(initsSkip);
  1811             uninits.assign(uninitsSkip);
  1812             resolveBreaks(tree, prevPendingExits);
  1815         public void visitWhileLoop(JCWhileLoop tree) {
  1816             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1817             FlowKind prevFlowKind = flowKind;
  1818             flowKind = FlowKind.NORMAL;
  1819             final Bits initsSkip = new Bits(true);
  1820             final Bits uninitsSkip = new Bits(true);
  1821             pendingExits = new ListBuffer<AssignPendingExit>();
  1822             int prevErrors = log.nerrors;
  1823             final Bits uninitsEntry = new Bits(uninits);
  1824             uninitsEntry.excludeFrom(nextadr);
  1825             do {
  1826                 scanCond(tree.cond);
  1827                 if (!flowKind.isFinal()) {
  1828                     initsSkip.assign(initsWhenFalse) ;
  1829                     uninitsSkip.assign(uninitsWhenFalse);
  1831                 inits.assign(initsWhenTrue);
  1832                 uninits.assign(uninitsWhenTrue);
  1833                 scan(tree.body);
  1834                 resolveContinues(tree);
  1835                 if (log.nerrors != prevErrors ||
  1836                     flowKind.isFinal() ||
  1837                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  1838                     break;
  1839                 uninits.assign(uninitsEntry.andSet(uninits));
  1840                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1841             } while (true);
  1842             flowKind = prevFlowKind;
  1843             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
  1844             //branch is not taken AND if it's DA/DU before any break statement
  1845             inits.assign(initsSkip);
  1846             uninits.assign(uninitsSkip);
  1847             resolveBreaks(tree, prevPendingExits);
  1850         public void visitForLoop(JCForLoop tree) {
  1851             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1852             FlowKind prevFlowKind = flowKind;
  1853             flowKind = FlowKind.NORMAL;
  1854             int nextadrPrev = nextadr;
  1855             scan(tree.init);
  1856             final Bits initsSkip = new Bits(true);
  1857             final Bits uninitsSkip = new Bits(true);
  1858             pendingExits = new ListBuffer<AssignPendingExit>();
  1859             int prevErrors = log.nerrors;
  1860             do {
  1861                 final Bits uninitsEntry = new Bits(uninits);
  1862                 uninitsEntry.excludeFrom(nextadr);
  1863                 if (tree.cond != null) {
  1864                     scanCond(tree.cond);
  1865                     if (!flowKind.isFinal()) {
  1866                         initsSkip.assign(initsWhenFalse);
  1867                         uninitsSkip.assign(uninitsWhenFalse);
  1869                     inits.assign(initsWhenTrue);
  1870                     uninits.assign(uninitsWhenTrue);
  1871                 } else if (!flowKind.isFinal()) {
  1872                     initsSkip.assign(inits);
  1873                     initsSkip.inclRange(firstadr, nextadr);
  1874                     uninitsSkip.assign(uninits);
  1875                     uninitsSkip.inclRange(firstadr, nextadr);
  1877                 scan(tree.body);
  1878                 resolveContinues(tree);
  1879                 scan(tree.step);
  1880                 if (log.nerrors != prevErrors ||
  1881                     flowKind.isFinal() ||
  1882                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  1883                     break;
  1884                 uninits.assign(uninitsEntry.andSet(uninits));
  1885                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1886             } while (true);
  1887             flowKind = prevFlowKind;
  1888             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
  1889             //branch is not taken AND if it's DA/DU before any break statement
  1890             inits.assign(initsSkip);
  1891             uninits.assign(uninitsSkip);
  1892             resolveBreaks(tree, prevPendingExits);
  1893             nextadr = nextadrPrev;
  1896         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1897             visitVarDef(tree.var);
  1899             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1900             FlowKind prevFlowKind = flowKind;
  1901             flowKind = FlowKind.NORMAL;
  1902             int nextadrPrev = nextadr;
  1903             scan(tree.expr);
  1904             final Bits initsStart = new Bits(inits);
  1905             final Bits uninitsStart = new Bits(uninits);
  1907             letInit(tree.pos(), tree.var.sym);
  1908             pendingExits = new ListBuffer<AssignPendingExit>();
  1909             int prevErrors = log.nerrors;
  1910             do {
  1911                 final Bits uninitsEntry = new Bits(uninits);
  1912                 uninitsEntry.excludeFrom(nextadr);
  1913                 scan(tree.body);
  1914                 resolveContinues(tree);
  1915                 if (log.nerrors != prevErrors ||
  1916                     flowKind.isFinal() ||
  1917                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  1918                     break;
  1919                 uninits.assign(uninitsEntry.andSet(uninits));
  1920                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1921             } while (true);
  1922             flowKind = prevFlowKind;
  1923             inits.assign(initsStart);
  1924             uninits.assign(uninitsStart.andSet(uninits));
  1925             resolveBreaks(tree, prevPendingExits);
  1926             nextadr = nextadrPrev;
  1929         public void visitLabelled(JCLabeledStatement tree) {
  1930             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1931             pendingExits = new ListBuffer<AssignPendingExit>();
  1932             scan(tree.body);
  1933             resolveBreaks(tree, prevPendingExits);
  1936         public void visitSwitch(JCSwitch tree) {
  1937             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1938             pendingExits = new ListBuffer<AssignPendingExit>();
  1939             int nextadrPrev = nextadr;
  1940             scanExpr(tree.selector);
  1941             final Bits initsSwitch = new Bits(inits);
  1942             final Bits uninitsSwitch = new Bits(uninits);
  1943             boolean hasDefault = false;
  1944             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1945                 inits.assign(initsSwitch);
  1946                 uninits.assign(uninits.andSet(uninitsSwitch));
  1947                 JCCase c = l.head;
  1948                 if (c.pat == null)
  1949                     hasDefault = true;
  1950                 else
  1951                     scanExpr(c.pat);
  1952                 scan(c.stats);
  1953                 addVars(c.stats, initsSwitch, uninitsSwitch);
  1954                 // Warn about fall-through if lint switch fallthrough enabled.
  1956             if (!hasDefault) {
  1957                 inits.andSet(initsSwitch);
  1959             resolveBreaks(tree, prevPendingExits);
  1960             nextadr = nextadrPrev;
  1962         // where
  1963             /** Add any variables defined in stats to inits and uninits. */
  1964             private void addVars(List<JCStatement> stats, final Bits inits,
  1965                                         final Bits uninits) {
  1966                 for (;stats.nonEmpty(); stats = stats.tail) {
  1967                     JCTree stat = stats.head;
  1968                     if (stat.hasTag(VARDEF)) {
  1969                         int adr = ((JCVariableDecl) stat).sym.adr;
  1970                         inits.excl(adr);
  1971                         uninits.incl(adr);
  1976         public void visitTry(JCTry tree) {
  1977             ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
  1978             final Bits uninitsTryPrev = new Bits(uninitsTry);
  1979             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1980             pendingExits = new ListBuffer<AssignPendingExit>();
  1981             final Bits initsTry = new Bits(inits);
  1982             uninitsTry.assign(uninits);
  1983             for (JCTree resource : tree.resources) {
  1984                 if (resource instanceof JCVariableDecl) {
  1985                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1986                     visitVarDef(vdecl);
  1987                     unrefdResources.enter(vdecl.sym);
  1988                     resourceVarDecls.append(vdecl);
  1989                 } else if (resource instanceof JCExpression) {
  1990                     scanExpr((JCExpression) resource);
  1991                 } else {
  1992                     throw new AssertionError(tree);  // parser error
  1995             scan(tree.body);
  1996             uninitsTry.andSet(uninits);
  1997             final Bits initsEnd = new Bits(inits);
  1998             final Bits uninitsEnd = new Bits(uninits);
  1999             int nextadrCatch = nextadr;
  2001             if (!resourceVarDecls.isEmpty() &&
  2002                     lint.isEnabled(Lint.LintCategory.TRY)) {
  2003                 for (JCVariableDecl resVar : resourceVarDecls) {
  2004                     if (unrefdResources.includes(resVar.sym)) {
  2005                         log.warning(Lint.LintCategory.TRY, resVar.pos(),
  2006                                     "try.resource.not.referenced", resVar.sym);
  2007                         unrefdResources.remove(resVar.sym);
  2012             /*  The analysis of each catch should be independent.
  2013              *  Each one should have the same initial values of inits and
  2014              *  uninits.
  2015              */
  2016             final Bits initsCatchPrev = new Bits(initsTry);
  2017             final Bits uninitsCatchPrev = new Bits(uninitsTry);
  2019             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  2020                 JCVariableDecl param = l.head.param;
  2021                 inits.assign(initsCatchPrev);
  2022                 uninits.assign(uninitsCatchPrev);
  2023                 scan(param);
  2024                 inits.incl(param.sym.adr);
  2025                 uninits.excl(param.sym.adr);
  2026                 scan(l.head.body);
  2027                 initsEnd.andSet(inits);
  2028                 uninitsEnd.andSet(uninits);
  2029                 nextadr = nextadrCatch;
  2031             if (tree.finalizer != null) {
  2032                 inits.assign(initsTry);
  2033                 uninits.assign(uninitsTry);
  2034                 ListBuffer<AssignPendingExit> exits = pendingExits;
  2035                 pendingExits = prevPendingExits;
  2036                 scan(tree.finalizer);
  2037                 if (!tree.finallyCanCompleteNormally) {
  2038                     // discard exits and exceptions from try and finally
  2039                 } else {
  2040                     uninits.andSet(uninitsEnd);
  2041                     // FIX: this doesn't preserve source order of exits in catch
  2042                     // versus finally!
  2043                     while (exits.nonEmpty()) {
  2044                         AssignPendingExit exit = exits.next();
  2045                         if (exit.exit_inits != null) {
  2046                             exit.exit_inits.orSet(inits);
  2047                             exit.exit_uninits.andSet(uninits);
  2049                         pendingExits.append(exit);
  2051                     inits.orSet(initsEnd);
  2053             } else {
  2054                 inits.assign(initsEnd);
  2055                 uninits.assign(uninitsEnd);
  2056                 ListBuffer<AssignPendingExit> exits = pendingExits;
  2057                 pendingExits = prevPendingExits;
  2058                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  2060             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  2063         public void visitConditional(JCConditional tree) {
  2064             scanCond(tree.cond);
  2065             final Bits initsBeforeElse = new Bits(initsWhenFalse);
  2066             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
  2067             inits.assign(initsWhenTrue);
  2068             uninits.assign(uninitsWhenTrue);
  2069             if (tree.truepart.type.hasTag(BOOLEAN) &&
  2070                 tree.falsepart.type.hasTag(BOOLEAN)) {
  2071                 // if b and c are boolean valued, then
  2072                 // v is (un)assigned after a?b:c when true iff
  2073                 //    v is (un)assigned after b when true and
  2074                 //    v is (un)assigned after c when true
  2075                 scanCond(tree.truepart);
  2076                 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
  2077                 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
  2078                 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
  2079                 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
  2080                 inits.assign(initsBeforeElse);
  2081                 uninits.assign(uninitsBeforeElse);
  2082                 scanCond(tree.falsepart);
  2083                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
  2084                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
  2085                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
  2086                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
  2087             } else {
  2088                 scanExpr(tree.truepart);
  2089                 final Bits initsAfterThen = new Bits(inits);
  2090                 final Bits uninitsAfterThen = new Bits(uninits);
  2091                 inits.assign(initsBeforeElse);
  2092                 uninits.assign(uninitsBeforeElse);
  2093                 scanExpr(tree.falsepart);
  2094                 inits.andSet(initsAfterThen);
  2095                 uninits.andSet(uninitsAfterThen);
  2099         public void visitIf(JCIf tree) {
  2100             scanCond(tree.cond);
  2101             final Bits initsBeforeElse = new Bits(initsWhenFalse);
  2102             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
  2103             inits.assign(initsWhenTrue);
  2104             uninits.assign(uninitsWhenTrue);
  2105             scan(tree.thenpart);
  2106             if (tree.elsepart != null) {
  2107                 final Bits initsAfterThen = new Bits(inits);
  2108                 final Bits uninitsAfterThen = new Bits(uninits);
  2109                 inits.assign(initsBeforeElse);
  2110                 uninits.assign(uninitsBeforeElse);
  2111                 scan(tree.elsepart);
  2112                 inits.andSet(initsAfterThen);
  2113                 uninits.andSet(uninitsAfterThen);
  2114             } else {
  2115                 inits.andSet(initsBeforeElse);
  2116                 uninits.andSet(uninitsBeforeElse);
  2120         public void visitBreak(JCBreak tree) {
  2121             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2124         public void visitContinue(JCContinue tree) {
  2125             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2128         public void visitReturn(JCReturn tree) {
  2129             scanExpr(tree.expr);
  2130             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2133         public void visitThrow(JCThrow tree) {
  2134             scanExpr(tree.expr);
  2135             markDead();
  2138         public void visitApply(JCMethodInvocation tree) {
  2139             scanExpr(tree.meth);
  2140             scanExprs(tree.args);
  2143         public void visitNewClass(JCNewClass tree) {
  2144             scanExpr(tree.encl);
  2145             scanExprs(tree.args);
  2146             scan(tree.def);
  2149         @Override
  2150         public void visitLambda(JCLambda tree) {
  2151             final Bits prevUninits = new Bits(uninits);
  2152             final Bits prevInits = new Bits(inits);
  2153             int returnadrPrev = returnadr;
  2154             ListBuffer<AssignPendingExit> prevPending = pendingExits;
  2155             try {
  2156                 returnadr = nextadr;
  2157                 pendingExits = new ListBuffer<AssignPendingExit>();
  2158                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  2159                     JCVariableDecl def = l.head;
  2160                     scan(def);
  2161                     inits.incl(def.sym.adr);
  2162                     uninits.excl(def.sym.adr);
  2164                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
  2165                     scanExpr(tree.body);
  2166                 } else {
  2167                     scan(tree.body);
  2170             finally {
  2171                 returnadr = returnadrPrev;
  2172                 uninits.assign(prevUninits);
  2173                 inits.assign(prevInits);
  2174                 pendingExits = prevPending;
  2178         public void visitNewArray(JCNewArray tree) {
  2179             scanExprs(tree.dims);
  2180             scanExprs(tree.elems);
  2183         public void visitAssert(JCAssert tree) {
  2184             final Bits initsExit = new Bits(inits);
  2185             final Bits uninitsExit = new Bits(uninits);
  2186             scanCond(tree.cond);
  2187             uninitsExit.andSet(uninitsWhenTrue);
  2188             if (tree.detail != null) {
  2189                 inits.assign(initsWhenFalse);
  2190                 uninits.assign(uninitsWhenFalse);
  2191                 scanExpr(tree.detail);
  2193             inits.assign(initsExit);
  2194             uninits.assign(uninitsExit);
  2197         public void visitAssign(JCAssign tree) {
  2198             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2199             if (!(lhs instanceof JCIdent)) {
  2200                 scanExpr(lhs);
  2202             scanExpr(tree.rhs);
  2203             letInit(lhs);
  2206         public void visitAssignop(JCAssignOp tree) {
  2207             scanExpr(tree.lhs);
  2208             scanExpr(tree.rhs);
  2209             letInit(tree.lhs);
  2212         public void visitUnary(JCUnary tree) {
  2213             switch (tree.getTag()) {
  2214             case NOT:
  2215                 scanCond(tree.arg);
  2216                 final Bits t = new Bits(initsWhenFalse);
  2217                 initsWhenFalse.assign(initsWhenTrue);
  2218                 initsWhenTrue.assign(t);
  2219                 t.assign(uninitsWhenFalse);
  2220                 uninitsWhenFalse.assign(uninitsWhenTrue);
  2221                 uninitsWhenTrue.assign(t);
  2222                 break;
  2223             case PREINC: case POSTINC:
  2224             case PREDEC: case POSTDEC:
  2225                 scanExpr(tree.arg);
  2226                 letInit(tree.arg);
  2227                 break;
  2228             default:
  2229                 scanExpr(tree.arg);
  2233         public void visitBinary(JCBinary tree) {
  2234             switch (tree.getTag()) {
  2235             case AND:
  2236                 scanCond(tree.lhs);
  2237                 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
  2238                 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
  2239                 inits.assign(initsWhenTrue);
  2240                 uninits.assign(uninitsWhenTrue);
  2241                 scanCond(tree.rhs);
  2242                 initsWhenFalse.andSet(initsWhenFalseLeft);
  2243                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
  2244                 break;
  2245             case OR:
  2246                 scanCond(tree.lhs);
  2247                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
  2248                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
  2249                 inits.assign(initsWhenFalse);
  2250                 uninits.assign(uninitsWhenFalse);
  2251                 scanCond(tree.rhs);
  2252                 initsWhenTrue.andSet(initsWhenTrueLeft);
  2253                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
  2254                 break;
  2255             default:
  2256                 scanExpr(tree.lhs);
  2257                 scanExpr(tree.rhs);
  2261         public void visitIdent(JCIdent tree) {
  2262             if (tree.sym.kind == VAR) {
  2263                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2264                 referenced(tree.sym);
  2268         void referenced(Symbol sym) {
  2269             unrefdResources.remove(sym);
  2272         public void visitAnnotatedType(JCAnnotatedType tree) {
  2273             // annotations don't get scanned
  2274             tree.underlyingType.accept(this);
  2277         public void visitTopLevel(JCCompilationUnit tree) {
  2278             // Do nothing for TopLevel since each class is visited individually
  2281     /**************************************************************************
  2282      * main method
  2283      *************************************************************************/
  2285         /** Perform definite assignment/unassignment analysis on a tree.
  2286          */
  2287         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2288             analyzeTree(env, env.tree, make);
  2291         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2292             try {
  2293                 attrEnv = env;
  2294                 Flow.this.make = make;
  2295                 startPos = tree.pos().getStartPosition();
  2297                 if (vardecls == null)
  2298                     vardecls = new JCVariableDecl[32];
  2299                 else
  2300                     for (int i=0; i<vardecls.length; i++)
  2301                         vardecls[i] = null;
  2302                 firstadr = 0;
  2303                 nextadr = 0;
  2304                 pendingExits = new ListBuffer<AssignPendingExit>();
  2305                 this.classDef = null;
  2306                 unrefdResources = new Scope(env.enclClass.sym);
  2307                 scan(tree);
  2308             } finally {
  2309                 // note that recursive invocations of this method fail hard
  2310                 startPos = -1;
  2311                 resetBits(inits, uninits, uninitsTry, initsWhenTrue,
  2312                         initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
  2313                 if (vardecls != null) for (int i=0; i<vardecls.length; i++)
  2314                     vardecls[i] = null;
  2315                 firstadr = 0;
  2316                 nextadr = 0;
  2317                 pendingExits = null;
  2318                 Flow.this.make = null;
  2319                 this.classDef = null;
  2320                 unrefdResources = null;
  2325     /**
  2326      * This pass implements the last step of the dataflow analysis, namely
  2327      * the effectively-final analysis check. This checks that every local variable
  2328      * reference from a lambda body/local inner class is either final or effectively final.
  2329      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2330      * AssignAnalyzer.
  2331      */
  2332     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
  2334         JCTree currentTree; //local class or lambda
  2336         @Override
  2337         void markDead() {
  2338             //do nothing
  2341         @SuppressWarnings("fallthrough")
  2342         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
  2343             if (currentTree != null &&
  2344                     sym.owner.kind == MTH &&
  2345                     sym.pos < currentTree.getStartPosition()) {
  2346                 switch (currentTree.getTag()) {
  2347                     case CLASSDEF:
  2348                         if (!allowEffectivelyFinalInInnerClasses) {
  2349                             if ((sym.flags() & FINAL) == 0) {
  2350                                 reportInnerClsNeedsFinalError(pos, sym);
  2352                             break;
  2354                     case LAMBDA:
  2355                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
  2356                            reportEffectivelyFinalError(pos, sym);
  2362         @SuppressWarnings("fallthrough")
  2363         void letInit(JCTree tree) {
  2364             tree = TreeInfo.skipParens(tree);
  2365             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  2366                 Symbol sym = TreeInfo.symbol(tree);
  2367                 if (currentTree != null &&
  2368                         sym.kind == VAR &&
  2369                         sym.owner.kind == MTH &&
  2370                         ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
  2371                     switch (currentTree.getTag()) {
  2372                         case CLASSDEF:
  2373                             if (!allowEffectivelyFinalInInnerClasses) {
  2374                                 reportInnerClsNeedsFinalError(tree, sym);
  2375                                 break;
  2377                         case LAMBDA:
  2378                             reportEffectivelyFinalError(tree, sym);
  2384         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
  2385             String subKey = currentTree.hasTag(LAMBDA) ?
  2386                   "lambda"  : "inner.cls";
  2387             log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
  2390         void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
  2391             log.error(pos,
  2392                     "local.var.accessed.from.icls.needs.final",
  2393                     sym);
  2396     /*************************************************************************
  2397      * Visitor methods for statements and definitions
  2398      *************************************************************************/
  2400         /* ------------ Visitor methods for various sorts of trees -------------*/
  2402         public void visitClassDef(JCClassDecl tree) {
  2403             JCTree prevTree = currentTree;
  2404             try {
  2405                 currentTree = tree.sym.isLocal() ? tree : null;
  2406                 super.visitClassDef(tree);
  2407             } finally {
  2408                 currentTree = prevTree;
  2412         @Override
  2413         public void visitLambda(JCLambda tree) {
  2414             JCTree prevTree = currentTree;
  2415             try {
  2416                 currentTree = tree;
  2417                 super.visitLambda(tree);
  2418             } finally {
  2419                 currentTree = prevTree;
  2423         @Override
  2424         public void visitIdent(JCIdent tree) {
  2425             if (tree.sym.kind == VAR) {
  2426                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
  2430         public void visitAssign(JCAssign tree) {
  2431             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2432             if (!(lhs instanceof JCIdent)) {
  2433                 scan(lhs);
  2435             scan(tree.rhs);
  2436             letInit(lhs);
  2439         public void visitAssignop(JCAssignOp tree) {
  2440             scan(tree.lhs);
  2441             scan(tree.rhs);
  2442             letInit(tree.lhs);
  2445         public void visitUnary(JCUnary tree) {
  2446             switch (tree.getTag()) {
  2447                 case PREINC: case POSTINC:
  2448                 case PREDEC: case POSTDEC:
  2449                     scan(tree.arg);
  2450                     letInit(tree.arg);
  2451                     break;
  2452                 default:
  2453                     scan(tree.arg);
  2457         public void visitTopLevel(JCCompilationUnit tree) {
  2458             // Do nothing for TopLevel since each class is visited individually
  2461     /**************************************************************************
  2462      * main method
  2463      *************************************************************************/
  2465         /** Perform definite assignment/unassignment analysis on a tree.
  2466          */
  2467         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2468             analyzeTree(env, env.tree, make);
  2470         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2471             try {
  2472                 attrEnv = env;
  2473                 Flow.this.make = make;
  2474                 pendingExits = new ListBuffer<PendingExit>();
  2475                 scan(tree);
  2476             } finally {
  2477                 pendingExits = null;
  2478                 Flow.this.make = null;

mercurial