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

Thu, 01 Nov 2012 10:48:36 +0100

author
ohrstrom
date
Thu, 01 Nov 2012 10:48:36 +0100
changeset 1384
bf54daa9dcd8
parent 1374
c002fdee76fd
child 1406
2901c7b5339e
permissions
-rw-r--r--

7153951: Add new lint option -Xlint:auxiliaryclass
Reviewed-by: jjg, mcimadamore, forax

     1 /*
     2  * Copyright (c) 1999, 2012, 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         java.util.Queue<JCDiagnostic> prevDeferredDiagnostics = log.deferredDiagnostics;
   217         Filter<JCDiagnostic> prevDeferDiagsFilter = log.deferredDiagFilter;
   218         //we need to disable diagnostics temporarily; the problem is that if
   219         //a lambda expression contains e.g. an unreachable statement, an error
   220         //message will be reported and will cause compilation to skip the flow analyis
   221         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
   222         //related errors, which will allow for more errors to be detected
   223         if (!speculative) {
   224             log.deferAll();
   225             log.deferredDiagnostics = ListBuffer.lb();
   226         }
   227         try {
   228             new AliveAnalyzer().analyzeTree(env, that, make);
   229             new FlowAnalyzer().analyzeTree(env, that, make);
   230         } finally {
   231             if (!speculative) {
   232                 log.deferredDiagFilter = prevDeferDiagsFilter;
   233                 log.deferredDiagnostics = prevDeferredDiagnostics;
   234             }
   235         }
   236     }
   238     /**
   239      * Definite assignment scan mode
   240      */
   241     enum FlowKind {
   242         /**
   243          * This is the normal DA/DU analysis mode
   244          */
   245         NORMAL("var.might.already.be.assigned", false),
   246         /**
   247          * This is the speculative DA/DU analysis mode used to speculatively
   248          * derive assertions within loop bodies
   249          */
   250         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
   252         String errKey;
   253         boolean isFinal;
   255         FlowKind(String errKey, boolean isFinal) {
   256             this.errKey = errKey;
   257             this.isFinal = isFinal;
   258         }
   260         boolean isFinal() {
   261             return isFinal;
   262         }
   263     }
   265     protected Flow(Context context) {
   266         context.put(flowKey, this);
   267         names = Names.instance(context);
   268         log = Log.instance(context);
   269         syms = Symtab.instance(context);
   270         types = Types.instance(context);
   271         chk = Check.instance(context);
   272         lint = Lint.instance(context);
   273         rs = Resolve.instance(context);
   274         diags = JCDiagnostic.Factory.instance(context);
   275         Source source = Source.instance(context);
   276         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   277         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   278         Options options = Options.instance(context);
   279         allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses() &&
   280                 options.isSet("allowEffectivelyFinalInInnerClasses"); //pre-lambda guard
   281     }
   283     /**
   284      * Base visitor class for all visitors implementing dataflow analysis logic.
   285      * This class define the shared logic for handling jumps (break/continue statements).
   286      */
   287     static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
   289         enum JumpKind {
   290             BREAK(JCTree.Tag.BREAK) {
   291                 @Override
   292                 JCTree getTarget(JCTree tree) {
   293                     return ((JCBreak)tree).target;
   294                 }
   295             },
   296             CONTINUE(JCTree.Tag.CONTINUE) {
   297                 @Override
   298                 JCTree getTarget(JCTree tree) {
   299                     return ((JCContinue)tree).target;
   300                 }
   301             };
   303             JCTree.Tag treeTag;
   305             private JumpKind(Tag treeTag) {
   306                 this.treeTag = treeTag;
   307             }
   309             abstract JCTree getTarget(JCTree tree);
   310         }
   312         /** The currently pending exits that go from current inner blocks
   313          *  to an enclosing block, in source order.
   314          */
   315         ListBuffer<P> pendingExits;
   317         /** A pending exit.  These are the statements return, break, and
   318          *  continue.  In addition, exception-throwing expressions or
   319          *  statements are put here when not known to be caught.  This
   320          *  will typically result in an error unless it is within a
   321          *  try-finally whose finally block cannot complete normally.
   322          */
   323         static class PendingExit {
   324             JCTree tree;
   326             PendingExit(JCTree tree) {
   327                 this.tree = tree;
   328             }
   330             void resolveJump() {
   331                 //do nothing
   332             }
   333         }
   335         abstract void markDead();
   337         /** Record an outward transfer of control. */
   338         void recordExit(JCTree tree, P pe) {
   339             pendingExits.append(pe);
   340             markDead();
   341         }
   343         /** Resolve all jumps of this statement. */
   344         private boolean resolveJump(JCTree tree,
   345                         ListBuffer<P> oldPendingExits,
   346                         JumpKind jk) {
   347             boolean resolved = false;
   348             List<P> exits = pendingExits.toList();
   349             pendingExits = oldPendingExits;
   350             for (; exits.nonEmpty(); exits = exits.tail) {
   351                 P exit = exits.head;
   352                 if (exit.tree.hasTag(jk.treeTag) &&
   353                         jk.getTarget(exit.tree) == tree) {
   354                     exit.resolveJump();
   355                     resolved = true;
   356                 } else {
   357                     pendingExits.append(exit);
   358                 }
   359             }
   360             return resolved;
   361         }
   363         /** Resolve all breaks of this statement. */
   364         boolean resolveContinues(JCTree tree) {
   365             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
   366         }
   368         /** Resolve all continues of this statement. */
   369         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
   370             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   371         }
   372     }
   374     /**
   375      * This pass implements the first step of the dataflow analysis, namely
   376      * the liveness analysis check. This checks that every statement is reachable.
   377      * The output of this analysis pass are used by other analyzers. This analyzer
   378      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   379      */
   380     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
   382         /** A flag that indicates whether the last statement could
   383          *  complete normally.
   384          */
   385         private boolean alive;
   387         @Override
   388         void markDead() {
   389             alive = false;
   390         }
   392     /*************************************************************************
   393      * Visitor methods for statements and definitions
   394      *************************************************************************/
   396         /** Analyze a definition.
   397          */
   398         void scanDef(JCTree tree) {
   399             scanStat(tree);
   400             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
   401                 log.error(tree.pos(),
   402                           "initializer.must.be.able.to.complete.normally");
   403             }
   404         }
   406         /** Analyze a statement. Check that statement is reachable.
   407          */
   408         void scanStat(JCTree tree) {
   409             if (!alive && tree != null) {
   410                 log.error(tree.pos(), "unreachable.stmt");
   411                 if (!tree.hasTag(SKIP)) alive = true;
   412             }
   413             scan(tree);
   414         }
   416         /** Analyze list of statements.
   417          */
   418         void scanStats(List<? extends JCStatement> trees) {
   419             if (trees != null)
   420                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
   421                     scanStat(l.head);
   422         }
   424         /* ------------ Visitor methods for various sorts of trees -------------*/
   426         public void visitClassDef(JCClassDecl tree) {
   427             if (tree.sym == null) return;
   428             boolean alivePrev = alive;
   429             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   430             Lint lintPrev = lint;
   432             pendingExits = new ListBuffer<PendingExit>();
   433             lint = lint.augment(tree.sym.annotations);
   435             try {
   436                 // process all the static initializers
   437                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   438                     if (!l.head.hasTag(METHODDEF) &&
   439                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   440                         scanDef(l.head);
   441                     }
   442                 }
   444                 // process all the instance initializers
   445                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   446                     if (!l.head.hasTag(METHODDEF) &&
   447                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   448                         scanDef(l.head);
   449                     }
   450                 }
   452                 // process all the methods
   453                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   454                     if (l.head.hasTag(METHODDEF)) {
   455                         scan(l.head);
   456                     }
   457                 }
   458             } finally {
   459                 pendingExits = pendingExitsPrev;
   460                 alive = alivePrev;
   461                 lint = lintPrev;
   462             }
   463         }
   465         public void visitMethodDef(JCMethodDecl tree) {
   466             if (tree.body == null) return;
   467             Lint lintPrev = lint;
   469             lint = lint.augment(tree.sym.annotations);
   471             Assert.check(pendingExits.isEmpty());
   473             try {
   474                 alive = true;
   475                 scanStat(tree.body);
   477                 if (alive && !tree.sym.type.getReturnType().hasTag(VOID))
   478                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   480                 List<PendingExit> exits = pendingExits.toList();
   481                 pendingExits = new ListBuffer<PendingExit>();
   482                 while (exits.nonEmpty()) {
   483                     PendingExit exit = exits.head;
   484                     exits = exits.tail;
   485                     Assert.check(exit.tree.hasTag(RETURN));
   486                 }
   487             } finally {
   488                 lint = lintPrev;
   489             }
   490         }
   492         public void visitVarDef(JCVariableDecl tree) {
   493             if (tree.init != null) {
   494                 Lint lintPrev = lint;
   495                 lint = lint.augment(tree.sym.annotations);
   496                 try{
   497                     scan(tree.init);
   498                 } finally {
   499                     lint = lintPrev;
   500                 }
   501             }
   502         }
   504         public void visitBlock(JCBlock tree) {
   505             scanStats(tree.stats);
   506         }
   508         public void visitDoLoop(JCDoWhileLoop tree) {
   509             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   510             pendingExits = new ListBuffer<PendingExit>();
   511             scanStat(tree.body);
   512             alive |= resolveContinues(tree);
   513             scan(tree.cond);
   514             alive = alive && !tree.cond.type.isTrue();
   515             alive |= resolveBreaks(tree, prevPendingExits);
   516         }
   518         public void visitWhileLoop(JCWhileLoop tree) {
   519             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   520             pendingExits = new ListBuffer<PendingExit>();
   521             scan(tree.cond);
   522             alive = !tree.cond.type.isFalse();
   523             scanStat(tree.body);
   524             alive |= resolveContinues(tree);
   525             alive = resolveBreaks(tree, prevPendingExits) ||
   526                 !tree.cond.type.isTrue();
   527         }
   529         public void visitForLoop(JCForLoop tree) {
   530             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   531             scanStats(tree.init);
   532             pendingExits = new ListBuffer<PendingExit>();
   533             if (tree.cond != null) {
   534                 scan(tree.cond);
   535                 alive = !tree.cond.type.isFalse();
   536             } else {
   537                 alive = true;
   538             }
   539             scanStat(tree.body);
   540             alive |= resolveContinues(tree);
   541             scan(tree.step);
   542             alive = resolveBreaks(tree, prevPendingExits) ||
   543                 tree.cond != null && !tree.cond.type.isTrue();
   544         }
   546         public void visitForeachLoop(JCEnhancedForLoop tree) {
   547             visitVarDef(tree.var);
   548             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   549             scan(tree.expr);
   550             pendingExits = new ListBuffer<PendingExit>();
   551             scanStat(tree.body);
   552             alive |= resolveContinues(tree);
   553             resolveBreaks(tree, prevPendingExits);
   554             alive = true;
   555         }
   557         public void visitLabelled(JCLabeledStatement tree) {
   558             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   559             pendingExits = new ListBuffer<PendingExit>();
   560             scanStat(tree.body);
   561             alive |= resolveBreaks(tree, prevPendingExits);
   562         }
   564         public void visitSwitch(JCSwitch tree) {
   565             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   566             pendingExits = new ListBuffer<PendingExit>();
   567             scan(tree.selector);
   568             boolean hasDefault = false;
   569             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   570                 alive = true;
   571                 JCCase c = l.head;
   572                 if (c.pat == null)
   573                     hasDefault = true;
   574                 else
   575                     scan(c.pat);
   576                 scanStats(c.stats);
   577                 // Warn about fall-through if lint switch fallthrough enabled.
   578                 if (alive &&
   579                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   580                     c.stats.nonEmpty() && l.tail.nonEmpty())
   581                     log.warning(Lint.LintCategory.FALLTHROUGH,
   582                                 l.tail.head.pos(),
   583                                 "possible.fall-through.into.case");
   584             }
   585             if (!hasDefault) {
   586                 alive = true;
   587             }
   588             alive |= resolveBreaks(tree, prevPendingExits);
   589         }
   591         public void visitTry(JCTry tree) {
   592             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   593             pendingExits = new ListBuffer<PendingExit>();
   594             for (JCTree resource : tree.resources) {
   595                 if (resource instanceof JCVariableDecl) {
   596                     JCVariableDecl vdecl = (JCVariableDecl) resource;
   597                     visitVarDef(vdecl);
   598                 } else if (resource instanceof JCExpression) {
   599                     scan((JCExpression) resource);
   600                 } else {
   601                     throw new AssertionError(tree);  // parser error
   602                 }
   603             }
   605             scanStat(tree.body);
   606             boolean aliveEnd = alive;
   608             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   609                 alive = true;
   610                 JCVariableDecl param = l.head.param;
   611                 scan(param);
   612                 scanStat(l.head.body);
   613                 aliveEnd |= alive;
   614             }
   615             if (tree.finalizer != null) {
   616                 ListBuffer<PendingExit> exits = pendingExits;
   617                 pendingExits = prevPendingExits;
   618                 alive = true;
   619                 scanStat(tree.finalizer);
   620                 tree.finallyCanCompleteNormally = alive;
   621                 if (!alive) {
   622                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
   623                         log.warning(Lint.LintCategory.FINALLY,
   624                                 TreeInfo.diagEndPos(tree.finalizer),
   625                                 "finally.cannot.complete");
   626                     }
   627                 } else {
   628                     while (exits.nonEmpty()) {
   629                         pendingExits.append(exits.next());
   630                     }
   631                     alive = aliveEnd;
   632                 }
   633             } else {
   634                 alive = aliveEnd;
   635                 ListBuffer<PendingExit> exits = pendingExits;
   636                 pendingExits = prevPendingExits;
   637                 while (exits.nonEmpty()) pendingExits.append(exits.next());
   638             }
   639         }
   641         @Override
   642         public void visitIf(JCIf tree) {
   643             scan(tree.cond);
   644             scanStat(tree.thenpart);
   645             if (tree.elsepart != null) {
   646                 boolean aliveAfterThen = alive;
   647                 alive = true;
   648                 scanStat(tree.elsepart);
   649                 alive = alive | aliveAfterThen;
   650             } else {
   651                 alive = true;
   652             }
   653         }
   655         public void visitBreak(JCBreak tree) {
   656             recordExit(tree, new PendingExit(tree));
   657         }
   659         public void visitContinue(JCContinue tree) {
   660             recordExit(tree, new PendingExit(tree));
   661         }
   663         public void visitReturn(JCReturn tree) {
   664             scan(tree.expr);
   665             recordExit(tree, new PendingExit(tree));
   666         }
   668         public void visitThrow(JCThrow tree) {
   669             scan(tree.expr);
   670             markDead();
   671         }
   673         public void visitApply(JCMethodInvocation tree) {
   674             scan(tree.meth);
   675             scan(tree.args);
   676         }
   678         public void visitNewClass(JCNewClass tree) {
   679             scan(tree.encl);
   680             scan(tree.args);
   681             if (tree.def != null) {
   682                 scan(tree.def);
   683             }
   684         }
   686         @Override
   687         public void visitLambda(JCLambda tree) {
   688             if (tree.type != null &&
   689                     tree.type.isErroneous()) {
   690                 return;
   691             }
   693             ListBuffer<PendingExit> prevPending = pendingExits;
   694             boolean prevAlive = alive;
   695             try {
   696                 pendingExits = ListBuffer.lb();
   697                 alive = true;
   698                 scanStat(tree.body);
   699                 tree.canCompleteNormally = alive;
   700             }
   701             finally {
   702                 pendingExits = prevPending;
   703                 alive = prevAlive;
   704             }
   705         }
   707         public void visitTopLevel(JCCompilationUnit tree) {
   708             // Do nothing for TopLevel since each class is visited individually
   709         }
   711     /**************************************************************************
   712      * main method
   713      *************************************************************************/
   715         /** Perform definite assignment/unassignment analysis on a tree.
   716          */
   717         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   718             analyzeTree(env, env.tree, make);
   719         }
   720         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
   721             try {
   722                 attrEnv = env;
   723                 Flow.this.make = make;
   724                 pendingExits = new ListBuffer<PendingExit>();
   725                 alive = true;
   726                 scan(env.tree);
   727             } finally {
   728                 pendingExits = null;
   729                 Flow.this.make = null;
   730             }
   731         }
   732     }
   734     /**
   735      * This pass implements the second step of the dataflow analysis, namely
   736      * the exception analysis. This is to ensure that every checked exception that is
   737      * thrown is declared or caught. The analyzer uses some info that has been set by
   738      * the liveliness analyzer.
   739      */
   740     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   742         /** A flag that indicates whether the last statement could
   743          *  complete normally.
   744          */
   745         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   747         /** The current class being defined.
   748          */
   749         JCClassDecl classDef;
   751         /** The list of possibly thrown declarable exceptions.
   752          */
   753         List<Type> thrown;
   755         /** The list of exceptions that are either caught or declared to be
   756          *  thrown.
   757          */
   758         List<Type> caught;
   760         class FlowPendingExit extends BaseAnalyzer.PendingExit {
   762             Type thrown;
   764             FlowPendingExit(JCTree tree, Type thrown) {
   765                 super(tree);
   766                 this.thrown = thrown;
   767             }
   768         }
   770         @Override
   771         void markDead() {
   772             //do nothing
   773         }
   775         /*-------------------- Exceptions ----------------------*/
   777         /** Complain that pending exceptions are not caught.
   778          */
   779         void errorUncaught() {
   780             for (FlowPendingExit exit = pendingExits.next();
   781                  exit != null;
   782                  exit = pendingExits.next()) {
   783                 if (classDef != null &&
   784                     classDef.pos == exit.tree.pos) {
   785                     log.error(exit.tree.pos(),
   786                             "unreported.exception.default.constructor",
   787                             exit.thrown);
   788                 } else if (exit.tree.hasTag(VARDEF) &&
   789                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   790                     log.error(exit.tree.pos(),
   791                             "unreported.exception.implicit.close",
   792                             exit.thrown,
   793                             ((JCVariableDecl)exit.tree).sym.name);
   794                 } else {
   795                     log.error(exit.tree.pos(),
   796                             "unreported.exception.need.to.catch.or.throw",
   797                             exit.thrown);
   798                 }
   799             }
   800         }
   802         /** Record that exception is potentially thrown and check that it
   803          *  is caught.
   804          */
   805         void markThrown(JCTree tree, Type exc) {
   806             if (!chk.isUnchecked(tree.pos(), exc)) {
   807                 if (!chk.isHandled(exc, caught))
   808                     pendingExits.append(new FlowPendingExit(tree, exc));
   809                     thrown = chk.incl(exc, thrown);
   810             }
   811         }
   813     /*************************************************************************
   814      * Visitor methods for statements and definitions
   815      *************************************************************************/
   817         /* ------------ Visitor methods for various sorts of trees -------------*/
   819         public void visitClassDef(JCClassDecl tree) {
   820             if (tree.sym == null) return;
   822             JCClassDecl classDefPrev = classDef;
   823             List<Type> thrownPrev = thrown;
   824             List<Type> caughtPrev = caught;
   825             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   826             Lint lintPrev = lint;
   828             pendingExits = new ListBuffer<FlowPendingExit>();
   829             if (tree.name != names.empty) {
   830                 caught = List.nil();
   831             }
   832             classDef = tree;
   833             thrown = List.nil();
   834             lint = lint.augment(tree.sym.annotations);
   836             try {
   837                 // process all the static initializers
   838                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   839                     if (!l.head.hasTag(METHODDEF) &&
   840                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   841                         scan(l.head);
   842                         errorUncaught();
   843                     }
   844                 }
   846                 // add intersection of all thrown clauses of initial constructors
   847                 // to set of caught exceptions, unless class is anonymous.
   848                 if (tree.name != names.empty) {
   849                     boolean firstConstructor = true;
   850                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   851                         if (TreeInfo.isInitialConstructor(l.head)) {
   852                             List<Type> mthrown =
   853                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
   854                             if (firstConstructor) {
   855                                 caught = mthrown;
   856                                 firstConstructor = false;
   857                             } else {
   858                                 caught = chk.intersect(mthrown, caught);
   859                             }
   860                         }
   861                     }
   862                 }
   864                 // process all the instance initializers
   865                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   866                     if (!l.head.hasTag(METHODDEF) &&
   867                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   868                         scan(l.head);
   869                         errorUncaught();
   870                     }
   871                 }
   873                 // in an anonymous class, add the set of thrown exceptions to
   874                 // the throws clause of the synthetic constructor and propagate
   875                 // outwards.
   876                 // Changing the throws clause on the fly is okay here because
   877                 // the anonymous constructor can't be invoked anywhere else,
   878                 // and its type hasn't been cached.
   879                 if (tree.name == names.empty) {
   880                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   881                         if (TreeInfo.isInitialConstructor(l.head)) {
   882                             JCMethodDecl mdef = (JCMethodDecl)l.head;
   883                             mdef.thrown = make.Types(thrown);
   884                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
   885                         }
   886                     }
   887                     thrownPrev = chk.union(thrown, thrownPrev);
   888                 }
   890                 // process all the methods
   891                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   892                     if (l.head.hasTag(METHODDEF)) {
   893                         scan(l.head);
   894                         errorUncaught();
   895                     }
   896                 }
   898                 thrown = thrownPrev;
   899             } finally {
   900                 pendingExits = pendingExitsPrev;
   901                 caught = caughtPrev;
   902                 classDef = classDefPrev;
   903                 lint = lintPrev;
   904             }
   905         }
   907         public void visitMethodDef(JCMethodDecl tree) {
   908             if (tree.body == null) return;
   910             List<Type> caughtPrev = caught;
   911             List<Type> mthrown = tree.sym.type.getThrownTypes();
   912             Lint lintPrev = lint;
   914             lint = lint.augment(tree.sym.annotations);
   916             Assert.check(pendingExits.isEmpty());
   918             try {
   919                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   920                     JCVariableDecl def = l.head;
   921                     scan(def);
   922                 }
   923                 if (TreeInfo.isInitialConstructor(tree))
   924                     caught = chk.union(caught, mthrown);
   925                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   926                     caught = mthrown;
   927                 // else we are in an instance initializer block;
   928                 // leave caught unchanged.
   930                 scan(tree.body);
   932                 List<FlowPendingExit> exits = pendingExits.toList();
   933                 pendingExits = new ListBuffer<FlowPendingExit>();
   934                 while (exits.nonEmpty()) {
   935                     FlowPendingExit exit = exits.head;
   936                     exits = exits.tail;
   937                     if (exit.thrown == null) {
   938                         Assert.check(exit.tree.hasTag(RETURN));
   939                     } else {
   940                         // uncaught throws will be reported later
   941                         pendingExits.append(exit);
   942                     }
   943                 }
   944             } finally {
   945                 caught = caughtPrev;
   946                 lint = lintPrev;
   947             }
   948         }
   950         public void visitVarDef(JCVariableDecl tree) {
   951             if (tree.init != null) {
   952                 Lint lintPrev = lint;
   953                 lint = lint.augment(tree.sym.annotations);
   954                 try{
   955                     scan(tree.init);
   956                 } finally {
   957                     lint = lintPrev;
   958                 }
   959             }
   960         }
   962         public void visitBlock(JCBlock tree) {
   963             scan(tree.stats);
   964         }
   966         public void visitDoLoop(JCDoWhileLoop tree) {
   967             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   968             pendingExits = new ListBuffer<FlowPendingExit>();
   969             scan(tree.body);
   970             resolveContinues(tree);
   971             scan(tree.cond);
   972             resolveBreaks(tree, prevPendingExits);
   973         }
   975         public void visitWhileLoop(JCWhileLoop tree) {
   976             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   977             pendingExits = new ListBuffer<FlowPendingExit>();
   978             scan(tree.cond);
   979             scan(tree.body);
   980             resolveContinues(tree);
   981             resolveBreaks(tree, prevPendingExits);
   982         }
   984         public void visitForLoop(JCForLoop tree) {
   985             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   986             scan(tree.init);
   987             pendingExits = new ListBuffer<FlowPendingExit>();
   988             if (tree.cond != null) {
   989                 scan(tree.cond);
   990             }
   991             scan(tree.body);
   992             resolveContinues(tree);
   993             scan(tree.step);
   994             resolveBreaks(tree, prevPendingExits);
   995         }
   997         public void visitForeachLoop(JCEnhancedForLoop tree) {
   998             visitVarDef(tree.var);
   999             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1000             scan(tree.expr);
  1001             pendingExits = new ListBuffer<FlowPendingExit>();
  1002             scan(tree.body);
  1003             resolveContinues(tree);
  1004             resolveBreaks(tree, prevPendingExits);
  1007         public void visitLabelled(JCLabeledStatement tree) {
  1008             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1009             pendingExits = new ListBuffer<FlowPendingExit>();
  1010             scan(tree.body);
  1011             resolveBreaks(tree, prevPendingExits);
  1014         public void visitSwitch(JCSwitch tree) {
  1015             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1016             pendingExits = new ListBuffer<FlowPendingExit>();
  1017             scan(tree.selector);
  1018             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1019                 JCCase c = l.head;
  1020                 if (c.pat != null) {
  1021                     scan(c.pat);
  1023                 scan(c.stats);
  1025             resolveBreaks(tree, prevPendingExits);
  1028         public void visitTry(JCTry tree) {
  1029             List<Type> caughtPrev = caught;
  1030             List<Type> thrownPrev = thrown;
  1031             thrown = List.nil();
  1032             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1033                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1034                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1035                         List.of(l.head.param.vartype);
  1036                 for (JCExpression ct : subClauses) {
  1037                     caught = chk.incl(ct.type, caught);
  1041             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1042             pendingExits = new ListBuffer<FlowPendingExit>();
  1043             for (JCTree resource : tree.resources) {
  1044                 if (resource instanceof JCVariableDecl) {
  1045                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1046                     visitVarDef(vdecl);
  1047                 } else if (resource instanceof JCExpression) {
  1048                     scan((JCExpression) resource);
  1049                 } else {
  1050                     throw new AssertionError(tree);  // parser error
  1053             for (JCTree resource : tree.resources) {
  1054                 List<Type> closeableSupertypes = resource.type.isCompound() ?
  1055                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
  1056                     List.of(resource.type);
  1057                 for (Type sup : closeableSupertypes) {
  1058                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
  1059                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
  1060                                 attrEnv,
  1061                                 sup,
  1062                                 names.close,
  1063                                 List.<Type>nil(),
  1064                                 List.<Type>nil());
  1065                         if (closeMethod.kind == MTH) {
  1066                             for (Type t : ((MethodSymbol)closeMethod).getThrownTypes()) {
  1067                                 markThrown(resource, t);
  1073             scan(tree.body);
  1074             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1075                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1076                 thrown;
  1077             thrown = thrownPrev;
  1078             caught = caughtPrev;
  1080             List<Type> caughtInTry = List.nil();
  1081             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1082                 JCVariableDecl param = l.head.param;
  1083                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1084                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1085                         List.of(l.head.param.vartype);
  1086                 List<Type> ctypes = List.nil();
  1087                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
  1088                 for (JCExpression ct : subClauses) {
  1089                     Type exc = ct.type;
  1090                     if (exc != syms.unknownType) {
  1091                         ctypes = ctypes.append(exc);
  1092                         if (types.isSameType(exc, syms.objectType))
  1093                             continue;
  1094                         checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
  1095                         caughtInTry = chk.incl(exc, caughtInTry);
  1098                 scan(param);
  1099                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1100                 scan(l.head.body);
  1101                 preciseRethrowTypes.remove(param.sym);
  1103             if (tree.finalizer != null) {
  1104                 List<Type> savedThrown = thrown;
  1105                 thrown = List.nil();
  1106                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1107                 pendingExits = prevPendingExits;
  1108                 scan(tree.finalizer);
  1109                 if (!tree.finallyCanCompleteNormally) {
  1110                     // discard exits and exceptions from try and finally
  1111                     thrown = chk.union(thrown, thrownPrev);
  1112                 } else {
  1113                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1114                     thrown = chk.union(thrown, savedThrown);
  1115                     // FIX: this doesn't preserve source order of exits in catch
  1116                     // versus finally!
  1117                     while (exits.nonEmpty()) {
  1118                         pendingExits.append(exits.next());
  1121             } else {
  1122                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1123                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1124                 pendingExits = prevPendingExits;
  1125                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1129         @Override
  1130         public void visitIf(JCIf tree) {
  1131             scan(tree.cond);
  1132             scan(tree.thenpart);
  1133             if (tree.elsepart != null) {
  1134                 scan(tree.elsepart);
  1138         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1139             if (chk.subset(exc, caughtInTry)) {
  1140                 log.error(pos, "except.already.caught", exc);
  1141             } else if (!chk.isUnchecked(pos, exc) &&
  1142                     !isExceptionOrThrowable(exc) &&
  1143                     !chk.intersects(exc, thrownInTry)) {
  1144                 log.error(pos, "except.never.thrown.in.try", exc);
  1145             } else if (allowImprovedCatchAnalysis) {
  1146                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
  1147                 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
  1148                 // unchecked exception, the result list would not be empty, as the augmented
  1149                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
  1150                 // exception, that would have been covered in the branch above
  1151                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
  1152                         !isExceptionOrThrowable(exc)) {
  1153                     String key = catchableThrownTypes.length() == 1 ?
  1154                             "unreachable.catch" :
  1155                             "unreachable.catch.1";
  1156                     log.warning(pos, key, catchableThrownTypes);
  1160         //where
  1161             private boolean isExceptionOrThrowable(Type exc) {
  1162                 return exc.tsym == syms.throwableType.tsym ||
  1163                     exc.tsym == syms.exceptionType.tsym;
  1166         public void visitBreak(JCBreak tree) {
  1167             recordExit(tree, new FlowPendingExit(tree, null));
  1170         public void visitContinue(JCContinue tree) {
  1171             recordExit(tree, new FlowPendingExit(tree, null));
  1174         public void visitReturn(JCReturn tree) {
  1175             scan(tree.expr);
  1176             recordExit(tree, new FlowPendingExit(tree, null));
  1179         public void visitThrow(JCThrow tree) {
  1180             scan(tree.expr);
  1181             Symbol sym = TreeInfo.symbol(tree.expr);
  1182             if (sym != null &&
  1183                 sym.kind == VAR &&
  1184                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
  1185                 preciseRethrowTypes.get(sym) != null &&
  1186                 allowImprovedRethrowAnalysis) {
  1187                 for (Type t : preciseRethrowTypes.get(sym)) {
  1188                     markThrown(tree, t);
  1191             else {
  1192                 markThrown(tree, tree.expr.type);
  1194             markDead();
  1197         public void visitApply(JCMethodInvocation tree) {
  1198             scan(tree.meth);
  1199             scan(tree.args);
  1200             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
  1201                 markThrown(tree, l.head);
  1204         public void visitNewClass(JCNewClass tree) {
  1205             scan(tree.encl);
  1206             scan(tree.args);
  1207            // scan(tree.def);
  1208             for (List<Type> l = tree.constructorType.getThrownTypes();
  1209                  l.nonEmpty();
  1210                  l = l.tail) {
  1211                 markThrown(tree, l.head);
  1213             List<Type> caughtPrev = caught;
  1214             try {
  1215                 // If the new class expression defines an anonymous class,
  1216                 // analysis of the anonymous constructor may encounter thrown
  1217                 // types which are unsubstituted type variables.
  1218                 // However, since the constructor's actual thrown types have
  1219                 // already been marked as thrown, it is safe to simply include
  1220                 // each of the constructor's formal thrown types in the set of
  1221                 // 'caught/declared to be thrown' types, for the duration of
  1222                 // the class def analysis.
  1223                 if (tree.def != null)
  1224                     for (List<Type> l = tree.constructor.type.getThrownTypes();
  1225                          l.nonEmpty();
  1226                          l = l.tail) {
  1227                         caught = chk.incl(l.head, caught);
  1229                 scan(tree.def);
  1231             finally {
  1232                 caught = caughtPrev;
  1236         @Override
  1237         public void visitLambda(JCLambda tree) {
  1238             if (tree.type != null &&
  1239                     tree.type.isErroneous()) {
  1240                 return;
  1242             List<Type> prevCaught = caught;
  1243             List<Type> prevThrown = thrown;
  1244             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1245             try {
  1246                 pendingExits = ListBuffer.lb();
  1247                 caught = List.of(syms.throwableType); //inhibit exception checking
  1248                 thrown = List.nil();
  1249                 scan(tree.body);
  1250                 tree.inferredThrownTypes = thrown;
  1252             finally {
  1253                 pendingExits = prevPending;
  1254                 caught = prevCaught;
  1255                 thrown = prevThrown;
  1259         public void visitTopLevel(JCCompilationUnit tree) {
  1260             // Do nothing for TopLevel since each class is visited individually
  1263     /**************************************************************************
  1264      * main method
  1265      *************************************************************************/
  1267         /** Perform definite assignment/unassignment analysis on a tree.
  1268          */
  1269         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1270             analyzeTree(env, env.tree, make);
  1272         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  1273             try {
  1274                 attrEnv = env;
  1275                 Flow.this.make = make;
  1276                 pendingExits = new ListBuffer<FlowPendingExit>();
  1277                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1278                 this.thrown = this.caught = null;
  1279                 this.classDef = null;
  1280                 scan(tree);
  1281             } finally {
  1282                 pendingExits = null;
  1283                 Flow.this.make = null;
  1284                 this.thrown = this.caught = null;
  1285                 this.classDef = null;
  1290     /**
  1291      * This pass implements (i) definite assignment analysis, which ensures that
  1292      * each variable is assigned when used and (ii) definite unassignment analysis,
  1293      * which ensures that no final variable is assigned more than once. This visitor
  1294      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1295      * effectively-final local variables/parameters.
  1296      */
  1297     class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
  1299         /** The set of definitely assigned variables.
  1300          */
  1301         Bits inits;
  1303         /** The set of definitely unassigned variables.
  1304          */
  1305         Bits uninits;
  1307         /** The set of variables that are definitely unassigned everywhere
  1308          *  in current try block. This variable is maintained lazily; it is
  1309          *  updated only when something gets removed from uninits,
  1310          *  typically by being assigned in reachable code.  To obtain the
  1311          *  correct set of variables which are definitely unassigned
  1312          *  anywhere in current try block, intersect uninitsTry and
  1313          *  uninits.
  1314          */
  1315         Bits uninitsTry;
  1317         /** When analyzing a condition, inits and uninits are null.
  1318          *  Instead we have:
  1319          */
  1320         Bits initsWhenTrue;
  1321         Bits initsWhenFalse;
  1322         Bits uninitsWhenTrue;
  1323         Bits uninitsWhenFalse;
  1325         /** A mapping from addresses to variable symbols.
  1326          */
  1327         VarSymbol[] vars;
  1329         /** The current class being defined.
  1330          */
  1331         JCClassDecl classDef;
  1333         /** The first variable sequence number in this class definition.
  1334          */
  1335         int firstadr;
  1337         /** The next available variable sequence number.
  1338          */
  1339         int nextadr;
  1341         /** The first variable sequence number in a block that can return.
  1342          */
  1343         int returnadr;
  1345         /** The list of unreferenced automatic resources.
  1346          */
  1347         Scope unrefdResources;
  1349         /** Set when processing a loop body the second time for DU analysis. */
  1350         FlowKind flowKind = FlowKind.NORMAL;
  1352         /** The starting position of the analysed tree */
  1353         int startPos;
  1355         class AssignPendingExit extends BaseAnalyzer.PendingExit {
  1357             Bits exit_inits;
  1358             Bits exit_uninits;
  1360             AssignPendingExit(JCTree tree, Bits inits, Bits uninits) {
  1361                 super(tree);
  1362                 this.exit_inits = inits.dup();
  1363                 this.exit_uninits = uninits.dup();
  1366             void resolveJump() {
  1367                 inits.andSet(exit_inits);
  1368                 uninits.andSet(exit_uninits);
  1372         @Override
  1373         void markDead() {
  1374             inits.inclRange(returnadr, nextadr);
  1375             uninits.inclRange(returnadr, nextadr);
  1378         /*-------------- Processing variables ----------------------*/
  1380         /** Do we need to track init/uninit state of this symbol?
  1381          *  I.e. is symbol either a local or a blank final variable?
  1382          */
  1383         boolean trackable(VarSymbol sym) {
  1384             return
  1385                 sym.pos >= startPos &&
  1386                 ((sym.owner.kind == MTH ||
  1387                  ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1388                   classDef.sym.isEnclosedBy((ClassSymbol)sym.owner))));
  1391         /** Initialize new trackable variable by setting its address field
  1392          *  to the next available sequence number and entering it under that
  1393          *  index into the vars array.
  1394          */
  1395         void newVar(VarSymbol sym) {
  1396             vars = ArrayUtils.ensureCapacity(vars, nextadr);
  1397             if ((sym.flags() & FINAL) == 0) {
  1398                 sym.flags_field |= EFFECTIVELY_FINAL;
  1400             sym.adr = nextadr;
  1401             vars[nextadr] = sym;
  1402             inits.excl(nextadr);
  1403             uninits.incl(nextadr);
  1404             nextadr++;
  1407         /** Record an initialization of a trackable variable.
  1408          */
  1409         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1410             if (sym.adr >= firstadr && trackable(sym)) {
  1411                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
  1412                     if (!uninits.isMember(sym.adr)) {
  1413                         //assignment targeting an effectively final variable
  1414                         //makes the variable lose its status of effectively final
  1415                         //if the variable is _not_ definitively unassigned
  1416                         sym.flags_field &= ~EFFECTIVELY_FINAL;
  1417                     } else {
  1418                         uninit(sym);
  1421                 else if ((sym.flags() & FINAL) != 0) {
  1422                     if ((sym.flags() & PARAMETER) != 0) {
  1423                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  1424                             log.error(pos, "multicatch.parameter.may.not.be.assigned",
  1425                                       sym);
  1427                         else {
  1428                             log.error(pos, "final.parameter.may.not.be.assigned",
  1429                                   sym);
  1431                     } else if (!uninits.isMember(sym.adr)) {
  1432                         log.error(pos, flowKind.errKey, sym);
  1433                     } else {
  1434                         uninit(sym);
  1437                 inits.incl(sym.adr);
  1438             } else if ((sym.flags() & FINAL) != 0) {
  1439                 log.error(pos, "var.might.already.be.assigned", sym);
  1442         //where
  1443             void uninit(VarSymbol sym) {
  1444                 if (!inits.isMember(sym.adr)) {
  1445                     // reachable assignment
  1446                     uninits.excl(sym.adr);
  1447                     uninitsTry.excl(sym.adr);
  1448                 } else {
  1449                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
  1450                     uninits.excl(sym.adr);
  1454         /** If tree is either a simple name or of the form this.name or
  1455          *  C.this.name, and tree represents a trackable variable,
  1456          *  record an initialization of the variable.
  1457          */
  1458         void letInit(JCTree tree) {
  1459             tree = TreeInfo.skipParens(tree);
  1460             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  1461                 Symbol sym = TreeInfo.symbol(tree);
  1462                 if (sym.kind == VAR) {
  1463                     letInit(tree.pos(), (VarSymbol)sym);
  1468         /** Check that trackable variable is initialized.
  1469          */
  1470         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
  1471             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  1472                 trackable(sym) &&
  1473                 !inits.isMember(sym.adr)) {
  1474                 log.error(pos, "var.might.not.have.been.initialized",
  1475                           sym);
  1476                 inits.incl(sym.adr);
  1480         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
  1481          */
  1482         void split(boolean setToNull) {
  1483             initsWhenFalse = inits.dup();
  1484             uninitsWhenFalse = uninits.dup();
  1485             initsWhenTrue = inits;
  1486             uninitsWhenTrue = uninits;
  1487             if (setToNull)
  1488                 inits = uninits = null;
  1491         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
  1492          */
  1493         void merge() {
  1494             inits = initsWhenFalse.andSet(initsWhenTrue);
  1495             uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
  1498     /* ************************************************************************
  1499      * Visitor methods for statements and definitions
  1500      *************************************************************************/
  1502         /** Analyze an expression. Make sure to set (un)inits rather than
  1503          *  (un)initsWhenTrue(WhenFalse) on exit.
  1504          */
  1505         void scanExpr(JCTree tree) {
  1506             if (tree != null) {
  1507                 scan(tree);
  1508                 if (inits == null) merge();
  1512         /** Analyze a list of expressions.
  1513          */
  1514         void scanExprs(List<? extends JCExpression> trees) {
  1515             if (trees != null)
  1516                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
  1517                     scanExpr(l.head);
  1520         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
  1521          *  rather than (un)inits on exit.
  1522          */
  1523         void scanCond(JCTree tree) {
  1524             if (tree.type.isFalse()) {
  1525                 if (inits == null) merge();
  1526                 initsWhenTrue = inits.dup();
  1527                 initsWhenTrue.inclRange(firstadr, nextadr);
  1528                 uninitsWhenTrue = uninits.dup();
  1529                 uninitsWhenTrue.inclRange(firstadr, nextadr);
  1530                 initsWhenFalse = inits;
  1531                 uninitsWhenFalse = uninits;
  1532             } else if (tree.type.isTrue()) {
  1533                 if (inits == null) merge();
  1534                 initsWhenFalse = inits.dup();
  1535                 initsWhenFalse.inclRange(firstadr, nextadr);
  1536                 uninitsWhenFalse = uninits.dup();
  1537                 uninitsWhenFalse.inclRange(firstadr, nextadr);
  1538                 initsWhenTrue = inits;
  1539                 uninitsWhenTrue = uninits;
  1540             } else {
  1541                 scan(tree);
  1542                 if (inits != null)
  1543                     split(tree.type != syms.unknownType);
  1545             if (tree.type != syms.unknownType)
  1546                 inits = uninits = null;
  1549         /* ------------ Visitor methods for various sorts of trees -------------*/
  1551         public void visitClassDef(JCClassDecl tree) {
  1552             if (tree.sym == null) return;
  1554             JCClassDecl classDefPrev = classDef;
  1555             int firstadrPrev = firstadr;
  1556             int nextadrPrev = nextadr;
  1557             ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
  1558             Lint lintPrev = lint;
  1560             pendingExits = new ListBuffer<AssignPendingExit>();
  1561             if (tree.name != names.empty) {
  1562                 firstadr = nextadr;
  1564             classDef = tree;
  1565             lint = lint.augment(tree.sym.annotations);
  1567             try {
  1568                 // define all the static fields
  1569                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1570                     if (l.head.hasTag(VARDEF)) {
  1571                         JCVariableDecl def = (JCVariableDecl)l.head;
  1572                         if ((def.mods.flags & STATIC) != 0) {
  1573                             VarSymbol sym = def.sym;
  1574                             if (trackable(sym))
  1575                                 newVar(sym);
  1580                 // process all the static initializers
  1581                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1582                     if (!l.head.hasTag(METHODDEF) &&
  1583                         (TreeInfo.flags(l.head) & STATIC) != 0) {
  1584                         scan(l.head);
  1588                 // define all the instance fields
  1589                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1590                     if (l.head.hasTag(VARDEF)) {
  1591                         JCVariableDecl def = (JCVariableDecl)l.head;
  1592                         if ((def.mods.flags & STATIC) == 0) {
  1593                             VarSymbol sym = def.sym;
  1594                             if (trackable(sym))
  1595                                 newVar(sym);
  1600                 // process all the instance initializers
  1601                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1602                     if (!l.head.hasTag(METHODDEF) &&
  1603                         (TreeInfo.flags(l.head) & STATIC) == 0) {
  1604                         scan(l.head);
  1608                 // process all the methods
  1609                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1610                     if (l.head.hasTag(METHODDEF)) {
  1611                         scan(l.head);
  1614             } finally {
  1615                 pendingExits = pendingExitsPrev;
  1616                 nextadr = nextadrPrev;
  1617                 firstadr = firstadrPrev;
  1618                 classDef = classDefPrev;
  1619                 lint = lintPrev;
  1623         public void visitMethodDef(JCMethodDecl tree) {
  1624             if (tree.body == null) return;
  1626             Bits initsPrev = inits.dup();
  1627             Bits uninitsPrev = uninits.dup();
  1628             int nextadrPrev = nextadr;
  1629             int firstadrPrev = firstadr;
  1630             int returnadrPrev = returnadr;
  1631             Lint lintPrev = lint;
  1633             lint = lint.augment(tree.sym.annotations);
  1635             Assert.check(pendingExits.isEmpty());
  1637             try {
  1638                 boolean isInitialConstructor =
  1639                     TreeInfo.isInitialConstructor(tree);
  1641                 if (!isInitialConstructor)
  1642                     firstadr = nextadr;
  1643                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  1644                     JCVariableDecl def = l.head;
  1645                     scan(def);
  1646                     inits.incl(def.sym.adr);
  1647                     uninits.excl(def.sym.adr);
  1649                 // else we are in an instance initializer block;
  1650                 // leave caught unchanged.
  1651                 scan(tree.body);
  1653                 if (isInitialConstructor) {
  1654                     for (int i = firstadr; i < nextadr; i++)
  1655                         if (vars[i].owner == classDef.sym)
  1656                             checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
  1658                 List<AssignPendingExit> exits = pendingExits.toList();
  1659                 pendingExits = new ListBuffer<AssignPendingExit>();
  1660                 while (exits.nonEmpty()) {
  1661                     AssignPendingExit exit = exits.head;
  1662                     exits = exits.tail;
  1663                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1664                     if (isInitialConstructor) {
  1665                         inits = exit.exit_inits;
  1666                         for (int i = firstadr; i < nextadr; i++)
  1667                             checkInit(exit.tree.pos(), vars[i]);
  1670             } finally {
  1671                 inits = initsPrev;
  1672                 uninits = uninitsPrev;
  1673                 nextadr = nextadrPrev;
  1674                 firstadr = firstadrPrev;
  1675                 returnadr = returnadrPrev;
  1676                 lint = lintPrev;
  1680         public void visitVarDef(JCVariableDecl tree) {
  1681             boolean track = trackable(tree.sym);
  1682             if (track && tree.sym.owner.kind == MTH) newVar(tree.sym);
  1683             if (tree.init != null) {
  1684                 Lint lintPrev = lint;
  1685                 lint = lint.augment(tree.sym.annotations);
  1686                 try{
  1687                     scanExpr(tree.init);
  1688                     if (track) letInit(tree.pos(), tree.sym);
  1689                 } finally {
  1690                     lint = lintPrev;
  1695         public void visitBlock(JCBlock tree) {
  1696             int nextadrPrev = nextadr;
  1697             scan(tree.stats);
  1698             nextadr = nextadrPrev;
  1701         public void visitDoLoop(JCDoWhileLoop tree) {
  1702             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1703             FlowKind prevFlowKind = flowKind;
  1704             flowKind = FlowKind.NORMAL;
  1705             Bits initsSkip = null;
  1706             Bits uninitsSkip = null;
  1707             pendingExits = new ListBuffer<AssignPendingExit>();
  1708             int prevErrors = log.nerrors;
  1709             do {
  1710                 Bits uninitsEntry = uninits.dup();
  1711                 uninitsEntry.excludeFrom(nextadr);
  1712                 scan(tree.body);
  1713                 resolveContinues(tree);
  1714                 scanCond(tree.cond);
  1715                 if (!flowKind.isFinal()) {
  1716                     initsSkip = initsWhenFalse;
  1717                     uninitsSkip = uninitsWhenFalse;
  1719                 if (log.nerrors !=  prevErrors ||
  1720                     flowKind.isFinal() ||
  1721                     uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1722                     break;
  1723                 inits = initsWhenTrue;
  1724                 uninits = uninitsEntry.andSet(uninitsWhenTrue);
  1725                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1726             } while (true);
  1727             flowKind = prevFlowKind;
  1728             inits = initsSkip;
  1729             uninits = uninitsSkip;
  1730             resolveBreaks(tree, prevPendingExits);
  1733         public void visitWhileLoop(JCWhileLoop tree) {
  1734             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1735             FlowKind prevFlowKind = flowKind;
  1736             flowKind = FlowKind.NORMAL;
  1737             Bits initsSkip = null;
  1738             Bits uninitsSkip = null;
  1739             pendingExits = new ListBuffer<AssignPendingExit>();
  1740             int prevErrors = log.nerrors;
  1741             Bits uninitsEntry = uninits.dup();
  1742             uninitsEntry.excludeFrom(nextadr);
  1743             do {
  1744                 scanCond(tree.cond);
  1745                 if (!flowKind.isFinal()) {
  1746                     initsSkip = initsWhenFalse;
  1747                     uninitsSkip = uninitsWhenFalse;
  1749                 inits = initsWhenTrue;
  1750                 uninits = uninitsWhenTrue;
  1751                 scan(tree.body);
  1752                 resolveContinues(tree);
  1753                 if (log.nerrors != prevErrors ||
  1754                     flowKind.isFinal() ||
  1755                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1756                     break;
  1757                 uninits = uninitsEntry.andSet(uninits);
  1758                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1759             } while (true);
  1760             flowKind = prevFlowKind;
  1761             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
  1762             //branch is not taken AND if it's DA/DU before any break statement
  1763             inits = initsSkip;
  1764             uninits = uninitsSkip;
  1765             resolveBreaks(tree, prevPendingExits);
  1768         public void visitForLoop(JCForLoop tree) {
  1769             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1770             FlowKind prevFlowKind = flowKind;
  1771             flowKind = FlowKind.NORMAL;
  1772             int nextadrPrev = nextadr;
  1773             scan(tree.init);
  1774             Bits initsSkip = null;
  1775             Bits uninitsSkip = null;
  1776             pendingExits = new ListBuffer<AssignPendingExit>();
  1777             int prevErrors = log.nerrors;
  1778             do {
  1779                 Bits uninitsEntry = uninits.dup();
  1780                 uninitsEntry.excludeFrom(nextadr);
  1781                 if (tree.cond != null) {
  1782                     scanCond(tree.cond);
  1783                     if (!flowKind.isFinal()) {
  1784                         initsSkip = initsWhenFalse;
  1785                         uninitsSkip = uninitsWhenFalse;
  1787                     inits = initsWhenTrue;
  1788                     uninits = uninitsWhenTrue;
  1789                 } else if (!flowKind.isFinal()) {
  1790                     initsSkip = inits.dup();
  1791                     initsSkip.inclRange(firstadr, nextadr);
  1792                     uninitsSkip = uninits.dup();
  1793                     uninitsSkip.inclRange(firstadr, nextadr);
  1795                 scan(tree.body);
  1796                 resolveContinues(tree);
  1797                 scan(tree.step);
  1798                 if (log.nerrors != prevErrors ||
  1799                     flowKind.isFinal() ||
  1800                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1801                     break;
  1802                 uninits = uninitsEntry.andSet(uninits);
  1803                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1804             } while (true);
  1805             flowKind = prevFlowKind;
  1806             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
  1807             //branch is not taken AND if it's DA/DU before any break statement
  1808             inits = initsSkip;
  1809             uninits = uninitsSkip;
  1810             resolveBreaks(tree, prevPendingExits);
  1811             nextadr = nextadrPrev;
  1814         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1815             visitVarDef(tree.var);
  1817             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1818             FlowKind prevFlowKind = flowKind;
  1819             flowKind = FlowKind.NORMAL;
  1820             int nextadrPrev = nextadr;
  1821             scan(tree.expr);
  1822             Bits initsStart = inits.dup();
  1823             Bits uninitsStart = uninits.dup();
  1825             letInit(tree.pos(), tree.var.sym);
  1826             pendingExits = new ListBuffer<AssignPendingExit>();
  1827             int prevErrors = log.nerrors;
  1828             do {
  1829                 Bits uninitsEntry = uninits.dup();
  1830                 uninitsEntry.excludeFrom(nextadr);
  1831                 scan(tree.body);
  1832                 resolveContinues(tree);
  1833                 if (log.nerrors != prevErrors ||
  1834                     flowKind.isFinal() ||
  1835                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1836                     break;
  1837                 uninits = uninitsEntry.andSet(uninits);
  1838                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1839             } while (true);
  1840             flowKind = prevFlowKind;
  1841             inits = initsStart;
  1842             uninits = uninitsStart.andSet(uninits);
  1843             resolveBreaks(tree, prevPendingExits);
  1844             nextadr = nextadrPrev;
  1847         public void visitLabelled(JCLabeledStatement tree) {
  1848             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1849             pendingExits = new ListBuffer<AssignPendingExit>();
  1850             scan(tree.body);
  1851             resolveBreaks(tree, prevPendingExits);
  1854         public void visitSwitch(JCSwitch tree) {
  1855             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1856             pendingExits = new ListBuffer<AssignPendingExit>();
  1857             int nextadrPrev = nextadr;
  1858             scanExpr(tree.selector);
  1859             Bits initsSwitch = inits;
  1860             Bits uninitsSwitch = uninits.dup();
  1861             boolean hasDefault = false;
  1862             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1863                 inits = initsSwitch.dup();
  1864                 uninits = uninits.andSet(uninitsSwitch);
  1865                 JCCase c = l.head;
  1866                 if (c.pat == null)
  1867                     hasDefault = true;
  1868                 else
  1869                     scanExpr(c.pat);
  1870                 scan(c.stats);
  1871                 addVars(c.stats, initsSwitch, uninitsSwitch);
  1872                 // Warn about fall-through if lint switch fallthrough enabled.
  1874             if (!hasDefault) {
  1875                 inits.andSet(initsSwitch);
  1877             resolveBreaks(tree, prevPendingExits);
  1878             nextadr = nextadrPrev;
  1880         // where
  1881             /** Add any variables defined in stats to inits and uninits. */
  1882             private void addVars(List<JCStatement> stats, Bits inits,
  1883                                         Bits uninits) {
  1884                 for (;stats.nonEmpty(); stats = stats.tail) {
  1885                     JCTree stat = stats.head;
  1886                     if (stat.hasTag(VARDEF)) {
  1887                         int adr = ((JCVariableDecl) stat).sym.adr;
  1888                         inits.excl(adr);
  1889                         uninits.incl(adr);
  1894         public void visitTry(JCTry tree) {
  1895             ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
  1896             Bits uninitsTryPrev = uninitsTry;
  1897             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1898             pendingExits = new ListBuffer<AssignPendingExit>();
  1899             Bits initsTry = inits.dup();
  1900             uninitsTry = uninits.dup();
  1901             for (JCTree resource : tree.resources) {
  1902                 if (resource instanceof JCVariableDecl) {
  1903                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1904                     visitVarDef(vdecl);
  1905                     unrefdResources.enter(vdecl.sym);
  1906                     resourceVarDecls.append(vdecl);
  1907                 } else if (resource instanceof JCExpression) {
  1908                     scanExpr((JCExpression) resource);
  1909                 } else {
  1910                     throw new AssertionError(tree);  // parser error
  1913             scan(tree.body);
  1914             uninitsTry.andSet(uninits);
  1915             Bits initsEnd = inits;
  1916             Bits uninitsEnd = uninits;
  1917             int nextadrCatch = nextadr;
  1919             if (!resourceVarDecls.isEmpty() &&
  1920                     lint.isEnabled(Lint.LintCategory.TRY)) {
  1921                 for (JCVariableDecl resVar : resourceVarDecls) {
  1922                     if (unrefdResources.includes(resVar.sym)) {
  1923                         log.warning(Lint.LintCategory.TRY, resVar.pos(),
  1924                                     "try.resource.not.referenced", resVar.sym);
  1925                         unrefdResources.remove(resVar.sym);
  1930             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1931                 JCVariableDecl param = l.head.param;
  1932                 inits = initsTry.dup();
  1933                 uninits = uninitsTry.dup();
  1934                 scan(param);
  1935                 inits.incl(param.sym.adr);
  1936                 uninits.excl(param.sym.adr);
  1937                 scan(l.head.body);
  1938                 initsEnd.andSet(inits);
  1939                 uninitsEnd.andSet(uninits);
  1940                 nextadr = nextadrCatch;
  1942             if (tree.finalizer != null) {
  1943                 inits = initsTry.dup();
  1944                 uninits = uninitsTry.dup();
  1945                 ListBuffer<AssignPendingExit> exits = pendingExits;
  1946                 pendingExits = prevPendingExits;
  1947                 scan(tree.finalizer);
  1948                 if (!tree.finallyCanCompleteNormally) {
  1949                     // discard exits and exceptions from try and finally
  1950                 } else {
  1951                     uninits.andSet(uninitsEnd);
  1952                     // FIX: this doesn't preserve source order of exits in catch
  1953                     // versus finally!
  1954                     while (exits.nonEmpty()) {
  1955                         AssignPendingExit exit = exits.next();
  1956                         if (exit.exit_inits != null) {
  1957                             exit.exit_inits.orSet(inits);
  1958                             exit.exit_uninits.andSet(uninits);
  1960                         pendingExits.append(exit);
  1962                     inits.orSet(initsEnd);
  1964             } else {
  1965                 inits = initsEnd;
  1966                 uninits = uninitsEnd;
  1967                 ListBuffer<AssignPendingExit> exits = pendingExits;
  1968                 pendingExits = prevPendingExits;
  1969                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1971             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  1974         public void visitConditional(JCConditional tree) {
  1975             scanCond(tree.cond);
  1976             Bits initsBeforeElse = initsWhenFalse;
  1977             Bits uninitsBeforeElse = uninitsWhenFalse;
  1978             inits = initsWhenTrue;
  1979             uninits = uninitsWhenTrue;
  1980             if (tree.truepart.type.hasTag(BOOLEAN) &&
  1981                 tree.falsepart.type.hasTag(BOOLEAN)) {
  1982                 // if b and c are boolean valued, then
  1983                 // v is (un)assigned after a?b:c when true iff
  1984                 //    v is (un)assigned after b when true and
  1985                 //    v is (un)assigned after c when true
  1986                 scanCond(tree.truepart);
  1987                 Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
  1988                 Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
  1989                 Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
  1990                 Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
  1991                 inits = initsBeforeElse;
  1992                 uninits = uninitsBeforeElse;
  1993                 scanCond(tree.falsepart);
  1994                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
  1995                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
  1996                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
  1997                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
  1998             } else {
  1999                 scanExpr(tree.truepart);
  2000                 Bits initsAfterThen = inits.dup();
  2001                 Bits uninitsAfterThen = uninits.dup();
  2002                 inits = initsBeforeElse;
  2003                 uninits = uninitsBeforeElse;
  2004                 scanExpr(tree.falsepart);
  2005                 inits.andSet(initsAfterThen);
  2006                 uninits.andSet(uninitsAfterThen);
  2010         public void visitIf(JCIf tree) {
  2011             scanCond(tree.cond);
  2012             Bits initsBeforeElse = initsWhenFalse;
  2013             Bits uninitsBeforeElse = uninitsWhenFalse;
  2014             inits = initsWhenTrue;
  2015             uninits = uninitsWhenTrue;
  2016             scan(tree.thenpart);
  2017             if (tree.elsepart != null) {
  2018                 Bits initsAfterThen = inits.dup();
  2019                 Bits uninitsAfterThen = uninits.dup();
  2020                 inits = initsBeforeElse;
  2021                 uninits = uninitsBeforeElse;
  2022                 scan(tree.elsepart);
  2023                 inits.andSet(initsAfterThen);
  2024                 uninits.andSet(uninitsAfterThen);
  2025             } else {
  2026                 inits.andSet(initsBeforeElse);
  2027                 uninits.andSet(uninitsBeforeElse);
  2031         public void visitBreak(JCBreak tree) {
  2032             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2035         public void visitContinue(JCContinue tree) {
  2036             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2039         public void visitReturn(JCReturn tree) {
  2040             scanExpr(tree.expr);
  2041             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2044         public void visitThrow(JCThrow tree) {
  2045             scanExpr(tree.expr);
  2046             markDead();
  2049         public void visitApply(JCMethodInvocation tree) {
  2050             scanExpr(tree.meth);
  2051             scanExprs(tree.args);
  2054         public void visitNewClass(JCNewClass tree) {
  2055             scanExpr(tree.encl);
  2056             scanExprs(tree.args);
  2057             scan(tree.def);
  2060         @Override
  2061         public void visitLambda(JCLambda tree) {
  2062             Bits prevUninits = uninits;
  2063             Bits prevInits = inits;
  2064             int returnadrPrev = returnadr;
  2065             ListBuffer<AssignPendingExit> prevPending = pendingExits;
  2066             try {
  2067                 returnadr = nextadr;
  2068                 pendingExits = new ListBuffer<AssignPendingExit>();
  2069                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  2070                     JCVariableDecl def = l.head;
  2071                     scan(def);
  2072                     inits.incl(def.sym.adr);
  2073                     uninits.excl(def.sym.adr);
  2075                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
  2076                     scanExpr(tree.body);
  2077                 } else {
  2078                     scan(tree.body);
  2081             finally {
  2082                 returnadr = returnadrPrev;
  2083                 uninits = prevUninits;
  2084                 inits = prevInits;
  2085                 pendingExits = prevPending;
  2089         public void visitNewArray(JCNewArray tree) {
  2090             scanExprs(tree.dims);
  2091             scanExprs(tree.elems);
  2094         public void visitAssert(JCAssert tree) {
  2095             Bits initsExit = inits.dup();
  2096             Bits uninitsExit = uninits.dup();
  2097             scanCond(tree.cond);
  2098             uninitsExit.andSet(uninitsWhenTrue);
  2099             if (tree.detail != null) {
  2100                 inits = initsWhenFalse;
  2101                 uninits = uninitsWhenFalse;
  2102                 scanExpr(tree.detail);
  2104             inits = initsExit;
  2105             uninits = uninitsExit;
  2108         public void visitAssign(JCAssign tree) {
  2109             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2110             if (!(lhs instanceof JCIdent)) {
  2111                 scanExpr(lhs);
  2113             scanExpr(tree.rhs);
  2114             letInit(lhs);
  2117         public void visitAssignop(JCAssignOp tree) {
  2118             scanExpr(tree.lhs);
  2119             scanExpr(tree.rhs);
  2120             letInit(tree.lhs);
  2123         public void visitUnary(JCUnary tree) {
  2124             switch (tree.getTag()) {
  2125             case NOT:
  2126                 scanCond(tree.arg);
  2127                 Bits t = initsWhenFalse;
  2128                 initsWhenFalse = initsWhenTrue;
  2129                 initsWhenTrue = t;
  2130                 t = uninitsWhenFalse;
  2131                 uninitsWhenFalse = uninitsWhenTrue;
  2132                 uninitsWhenTrue = t;
  2133                 break;
  2134             case PREINC: case POSTINC:
  2135             case PREDEC: case POSTDEC:
  2136                 scanExpr(tree.arg);
  2137                 letInit(tree.arg);
  2138                 break;
  2139             default:
  2140                 scanExpr(tree.arg);
  2144         public void visitBinary(JCBinary tree) {
  2145             switch (tree.getTag()) {
  2146             case AND:
  2147                 scanCond(tree.lhs);
  2148                 Bits initsWhenFalseLeft = initsWhenFalse;
  2149                 Bits uninitsWhenFalseLeft = uninitsWhenFalse;
  2150                 inits = initsWhenTrue;
  2151                 uninits = uninitsWhenTrue;
  2152                 scanCond(tree.rhs);
  2153                 initsWhenFalse.andSet(initsWhenFalseLeft);
  2154                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
  2155                 break;
  2156             case OR:
  2157                 scanCond(tree.lhs);
  2158                 Bits initsWhenTrueLeft = initsWhenTrue;
  2159                 Bits uninitsWhenTrueLeft = uninitsWhenTrue;
  2160                 inits = initsWhenFalse;
  2161                 uninits = uninitsWhenFalse;
  2162                 scanCond(tree.rhs);
  2163                 initsWhenTrue.andSet(initsWhenTrueLeft);
  2164                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
  2165                 break;
  2166             default:
  2167                 scanExpr(tree.lhs);
  2168                 scanExpr(tree.rhs);
  2172         public void visitIdent(JCIdent tree) {
  2173             if (tree.sym.kind == VAR) {
  2174                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2175                 referenced(tree.sym);
  2179         void referenced(Symbol sym) {
  2180             unrefdResources.remove(sym);
  2183         public void visitTopLevel(JCCompilationUnit tree) {
  2184             // Do nothing for TopLevel since each class is visited individually
  2187     /**************************************************************************
  2188      * main method
  2189      *************************************************************************/
  2191         /** Perform definite assignment/unassignment analysis on a tree.
  2192          */
  2193         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2194             analyzeTree(env, env.tree, make);
  2197         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2198             try {
  2199                 attrEnv = env;
  2200                 Flow.this.make = make;
  2201                 startPos = tree.pos().getStartPosition();
  2202                 inits = new Bits();
  2203                 uninits = new Bits();
  2204                 uninitsTry = new Bits();
  2205                 initsWhenTrue = initsWhenFalse =
  2206                     uninitsWhenTrue = uninitsWhenFalse = null;
  2207                 if (vars == null)
  2208                     vars = new VarSymbol[32];
  2209                 else
  2210                     for (int i=0; i<vars.length; i++)
  2211                         vars[i] = null;
  2212                 firstadr = 0;
  2213                 nextadr = 0;
  2214                 pendingExits = new ListBuffer<AssignPendingExit>();
  2215                 this.classDef = null;
  2216                 unrefdResources = new Scope(env.enclClass.sym);
  2217                 scan(tree);
  2218             } finally {
  2219                 // note that recursive invocations of this method fail hard
  2220                 startPos = -1;
  2221                 inits = uninits = uninitsTry = null;
  2222                 initsWhenTrue = initsWhenFalse =
  2223                     uninitsWhenTrue = uninitsWhenFalse = null;
  2224                 if (vars != null) for (int i=0; i<vars.length; i++)
  2225                     vars[i] = null;
  2226                 firstadr = 0;
  2227                 nextadr = 0;
  2228                 pendingExits = null;
  2229                 Flow.this.make = null;
  2230                 this.classDef = null;
  2231                 unrefdResources = null;
  2236     /**
  2237      * This pass implements the last step of the dataflow analysis, namely
  2238      * the effectively-final analysis check. This checks that every local variable
  2239      * reference from a lambda body/local inner class is either final or effectively final.
  2240      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2241      * AssignAnalyzer.
  2242      */
  2243     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
  2245         JCTree currentTree; //local class or lambda
  2247         @Override
  2248         void markDead() {
  2249             //do nothing
  2252         @SuppressWarnings("fallthrough")
  2253         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
  2254             if (currentTree != null &&
  2255                     sym.owner.kind == MTH &&
  2256                     sym.pos < currentTree.getStartPosition()) {
  2257                 switch (currentTree.getTag()) {
  2258                     case CLASSDEF:
  2259                         if (!allowEffectivelyFinalInInnerClasses) {
  2260                             if ((sym.flags() & FINAL) == 0) {
  2261                                 reportInnerClsNeedsFinalError(pos, sym);
  2263                             break;
  2265                     case LAMBDA:
  2266                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
  2267                            reportEffectivelyFinalError(pos, sym);
  2273         @SuppressWarnings("fallthrough")
  2274         void letInit(JCTree tree) {
  2275             tree = TreeInfo.skipParens(tree);
  2276             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  2277                 Symbol sym = TreeInfo.symbol(tree);
  2278                 if (currentTree != null &&
  2279                         sym.kind == VAR &&
  2280                         sym.owner.kind == MTH &&
  2281                         ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
  2282                     switch (currentTree.getTag()) {
  2283                         case CLASSDEF:
  2284                             if (!allowEffectivelyFinalInInnerClasses) {
  2285                                 reportInnerClsNeedsFinalError(tree, sym);
  2286                                 break;
  2288                         case LAMBDA:
  2289                             reportEffectivelyFinalError(tree, sym);
  2295         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
  2296             String subKey = currentTree.hasTag(LAMBDA) ?
  2297                   "lambda"  : "inner.cls";
  2298             log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
  2301         void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
  2302             log.error(pos,
  2303                     "local.var.accessed.from.icls.needs.final",
  2304                     sym);
  2307     /*************************************************************************
  2308      * Visitor methods for statements and definitions
  2309      *************************************************************************/
  2311         /* ------------ Visitor methods for various sorts of trees -------------*/
  2313         public void visitClassDef(JCClassDecl tree) {
  2314             JCTree prevTree = currentTree;
  2315             try {
  2316                 currentTree = tree.sym.isLocal() ? tree : null;
  2317                 super.visitClassDef(tree);
  2318             } finally {
  2319                 currentTree = prevTree;
  2323         @Override
  2324         public void visitLambda(JCLambda tree) {
  2325             JCTree prevTree = currentTree;
  2326             try {
  2327                 currentTree = tree;
  2328                 super.visitLambda(tree);
  2329             } finally {
  2330                 currentTree = prevTree;
  2334         @Override
  2335         public void visitIdent(JCIdent tree) {
  2336             if (tree.sym.kind == VAR) {
  2337                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
  2341         public void visitAssign(JCAssign tree) {
  2342             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2343             if (!(lhs instanceof JCIdent)) {
  2344                 scan(lhs);
  2346             scan(tree.rhs);
  2347             letInit(lhs);
  2350         public void visitAssignop(JCAssignOp tree) {
  2351             scan(tree.lhs);
  2352             scan(tree.rhs);
  2353             letInit(tree.lhs);
  2356         public void visitUnary(JCUnary tree) {
  2357             switch (tree.getTag()) {
  2358                 case PREINC: case POSTINC:
  2359                 case PREDEC: case POSTDEC:
  2360                     scan(tree.arg);
  2361                     letInit(tree.arg);
  2362                     break;
  2363                 default:
  2364                     scan(tree.arg);
  2368         public void visitTopLevel(JCCompilationUnit tree) {
  2369             // Do nothing for TopLevel since each class is visited individually
  2372     /**************************************************************************
  2373      * main method
  2374      *************************************************************************/
  2376         /** Perform definite assignment/unassignment analysis on a tree.
  2377          */
  2378         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2379             analyzeTree(env, env.tree, make);
  2381         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2382             try {
  2383                 attrEnv = env;
  2384                 Flow.this.make = make;
  2385                 pendingExits = new ListBuffer<PendingExit>();
  2386                 scan(tree);
  2387             } finally {
  2388                 pendingExits = null;
  2389                 Flow.this.make = null;

mercurial