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

Wed, 23 Jan 2013 13:27:24 -0800

author
jjg
date
Wed, 23 Jan 2013 13:27:24 -0800
changeset 1521
71f35e4b93a5
parent 1442
fcf89720ae71
child 1693
c430f1cde21c
permissions
-rw-r--r--

8006775: JSR 308: Compiler changes in JDK8
Reviewed-by: jjg
Contributed-by: mernst@cs.washington.edu, wmdietl@cs.washington.edu, mpapi@csail.mit.edu, mahmood@notnoop.com

     1 /*
     2  * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 //todo: one might eliminate uninits.andSets when monotonic
    28 package com.sun.tools.javac.comp;
    30 import java.util.HashMap;
    32 import com.sun.tools.javac.code.*;
    33 import com.sun.tools.javac.tree.*;
    34 import com.sun.tools.javac.util.*;
    35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    37 import com.sun.tools.javac.code.Symbol.*;
    38 import com.sun.tools.javac.comp.Resolve;
    39 import com.sun.tools.javac.tree.JCTree.*;
    41 import static com.sun.tools.javac.code.Flags.*;
    42 import static com.sun.tools.javac.code.Flags.BLOCK;
    43 import static com.sun.tools.javac.code.Kinds.*;
    44 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
    45 import static com.sun.tools.javac.code.TypeTag.VOID;
    46 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    48 /** This pass implements dataflow analysis for Java programs though
    49  *  different AST visitor steps. Liveness analysis (see AliveAlanyzer) checks that
    50  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
    51  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
    52  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
    53  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
    54  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
    55  *  determines that local variables accessed within the scope of an inner class/lambda
    56  *  are either final or effectively-final.
    57  *
    58  *  <p>The JLS has a number of problems in the
    59  *  specification of these flow analysis problems. This implementation
    60  *  attempts to address those issues.
    61  *
    62  *  <p>First, there is no accommodation for a finally clause that cannot
    63  *  complete normally. For liveness analysis, an intervening finally
    64  *  clause can cause a break, continue, or return not to reach its
    65  *  target.  For exception analysis, an intervening finally clause can
    66  *  cause any exception to be "caught".  For DA/DU analysis, the finally
    67  *  clause can prevent a transfer of control from propagating DA/DU
    68  *  state to the target.  In addition, code in the finally clause can
    69  *  affect the DA/DU status of variables.
    70  *
    71  *  <p>For try statements, we introduce the idea of a variable being
    72  *  definitely unassigned "everywhere" in a block.  A variable V is
    73  *  "unassigned everywhere" in a block iff it is unassigned at the
    74  *  beginning of the block and there is no reachable assignment to V
    75  *  in the block.  An assignment V=e is reachable iff V is not DA
    76  *  after e.  Then we can say that V is DU at the beginning of the
    77  *  catch block iff V is DU everywhere in the try block.  Similarly, V
    78  *  is DU at the beginning of the finally block iff V is DU everywhere
    79  *  in the try block and in every catch block.  Specifically, the
    80  *  following bullet is added to 16.2.2
    81  *  <pre>
    82  *      V is <em>unassigned everywhere</em> in a block if it is
    83  *      unassigned before the block and there is no reachable
    84  *      assignment to V within the block.
    85  *  </pre>
    86  *  <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all
    87  *  try blocks is changed to
    88  *  <pre>
    89  *      V is definitely unassigned before a catch block iff V is
    90  *      definitely unassigned everywhere in the try block.
    91  *  </pre>
    92  *  <p>The last bullet (and all of its sub-bullets) for try blocks that
    93  *  have a finally block is changed to
    94  *  <pre>
    95  *      V is definitely unassigned before the finally block iff
    96  *      V is definitely unassigned everywhere in the try block
    97  *      and everywhere in each catch block of the try statement.
    98  *  </pre>
    99  *  <p>In addition,
   100  *  <pre>
   101  *      V is definitely assigned at the end of a constructor iff
   102  *      V is definitely assigned after the block that is the body
   103  *      of the constructor and V is definitely assigned at every
   104  *      return that can return from the constructor.
   105  *  </pre>
   106  *  <p>In addition, each continue statement with the loop as its target
   107  *  is treated as a jump to the end of the loop body, and "intervening"
   108  *  finally clauses are treated as follows: V is DA "due to the
   109  *  continue" iff V is DA before the continue statement or V is DA at
   110  *  the end of any intervening finally block.  V is DU "due to the
   111  *  continue" iff any intervening finally cannot complete normally or V
   112  *  is DU at the end of every intervening finally block.  This "due to
   113  *  the continue" concept is then used in the spec for the loops.
   114  *
   115  *  <p>Similarly, break statements must consider intervening finally
   116  *  blocks.  For liveness analysis, a break statement for which any
   117  *  intervening finally cannot complete normally is not considered to
   118  *  cause the target statement to be able to complete normally. Then
   119  *  we say V is DA "due to the break" iff V is DA before the break or
   120  *  V is DA at the end of any intervening finally block.  V is DU "due
   121  *  to the break" iff any intervening finally cannot complete normally
   122  *  or V is DU at the break and at the end of every intervening
   123  *  finally block.  (I suspect this latter condition can be
   124  *  simplified.)  This "due to the break" is then used in the spec for
   125  *  all statements that can be "broken".
   126  *
   127  *  <p>The return statement is treated similarly.  V is DA "due to a
   128  *  return statement" iff V is DA before the return statement or V is
   129  *  DA at the end of any intervening finally block.  Note that we
   130  *  don't have to worry about the return expression because this
   131  *  concept is only used for construcrors.
   132  *
   133  *  <p>There is no spec in the JLS for when a variable is definitely
   134  *  assigned at the end of a constructor, which is needed for final
   135  *  fields (8.3.1.2).  We implement the rule that V is DA at the end
   136  *  of the constructor iff it is DA and the end of the body of the
   137  *  constructor and V is DA "due to" every return of the constructor.
   138  *
   139  *  <p>Intervening finally blocks similarly affect exception analysis.  An
   140  *  intervening finally that cannot complete normally allows us to ignore
   141  *  an otherwise uncaught exception.
   142  *
   143  *  <p>To implement the semantics of intervening finally clauses, all
   144  *  nonlocal transfers (break, continue, return, throw, method call that
   145  *  can throw a checked exception, and a constructor invocation that can
   146  *  thrown a checked exception) are recorded in a queue, and removed
   147  *  from the queue when we complete processing the target of the
   148  *  nonlocal transfer.  This allows us to modify the queue in accordance
   149  *  with the above rules when we encounter a finally clause.  The only
   150  *  exception to this [no pun intended] is that checked exceptions that
   151  *  are known to be caught or declared to be caught in the enclosing
   152  *  method are not recorded in the queue, but instead are recorded in a
   153  *  global variable "{@code Set<Type> thrown}" that records the type of all
   154  *  exceptions that can be thrown.
   155  *
   156  *  <p>Other minor issues the treatment of members of other classes
   157  *  (always considered DA except that within an anonymous class
   158  *  constructor, where DA status from the enclosing scope is
   159  *  preserved), treatment of the case expression (V is DA before the
   160  *  case expression iff V is DA after the switch expression),
   161  *  treatment of variables declared in a switch block (the implied
   162  *  DA/DU status after the switch expression is DU and not DA for
   163  *  variables defined in a switch block), the treatment of boolean ?:
   164  *  expressions (The JLS rules only handle b and c non-boolean; the
   165  *  new rule is that if b and c are boolean valued, then V is
   166  *  (un)assigned after a?b:c when true/false iff V is (un)assigned
   167  *  after b when true/false and V is (un)assigned after c when
   168  *  true/false).
   169  *
   170  *  <p>There is the remaining question of what syntactic forms constitute a
   171  *  reference to a variable.  It is conventional to allow this.x on the
   172  *  left-hand-side to initialize a final instance field named x, yet
   173  *  this.x isn't considered a "use" when appearing on a right-hand-side
   174  *  in most implementations.  Should parentheses affect what is
   175  *  considered a variable reference?  The simplest rule would be to
   176  *  allow unqualified forms only, parentheses optional, and phase out
   177  *  support for assigning to a final field via this.x.
   178  *
   179  *  <p><b>This is NOT part of any supported API.
   180  *  If you write code that depends on this, you do so at your own risk.
   181  *  This code and its internal interfaces are subject to change or
   182  *  deletion without notice.</b>
   183  */
   184 public class Flow {
   185     protected static final Context.Key<Flow> flowKey =
   186         new Context.Key<Flow>();
   188     private final Names names;
   189     private final Log log;
   190     private final Symtab syms;
   191     private final Types types;
   192     private final Check chk;
   193     private       TreeMaker make;
   194     private final Resolve rs;
   195     private final JCDiagnostic.Factory diags;
   196     private Env<AttrContext> attrEnv;
   197     private       Lint lint;
   198     private final boolean allowImprovedRethrowAnalysis;
   199     private final boolean allowImprovedCatchAnalysis;
   200     private final boolean allowEffectivelyFinalInInnerClasses;
   202     public static Flow instance(Context context) {
   203         Flow instance = context.get(flowKey);
   204         if (instance == null)
   205             instance = new Flow(context);
   206         return instance;
   207     }
   209     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   210         new AliveAnalyzer().analyzeTree(env, make);
   211         new AssignAnalyzer().analyzeTree(env, make);
   212         new FlowAnalyzer().analyzeTree(env, make);
   213         new CaptureAnalyzer().analyzeTree(env, make);
   214     }
   216     public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
   217         Log.DiagnosticHandler diagHandler = null;
   218         //we need to disable diagnostics temporarily; the problem is that if
   219         //a lambda expression contains e.g. an unreachable statement, an error
   220         //message will be reported and will cause compilation to skip the flow analyis
   221         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
   222         //related errors, which will allow for more errors to be detected
   223         if (!speculative) {
   224             diagHandler = new Log.DiscardDiagnosticHandler(log);
   225         }
   226         try {
   227             new AliveAnalyzer().analyzeTree(env, that, make);
   228             new FlowAnalyzer().analyzeTree(env, that, make);
   229         } finally {
   230             if (!speculative) {
   231                 log.popDiagnosticHandler(diagHandler);
   232             }
   233         }
   234     }
   236     /**
   237      * Definite assignment scan mode
   238      */
   239     enum FlowKind {
   240         /**
   241          * This is the normal DA/DU analysis mode
   242          */
   243         NORMAL("var.might.already.be.assigned", false),
   244         /**
   245          * This is the speculative DA/DU analysis mode used to speculatively
   246          * derive assertions within loop bodies
   247          */
   248         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
   250         final String errKey;
   251         final boolean isFinal;
   253         FlowKind(String errKey, boolean isFinal) {
   254             this.errKey = errKey;
   255             this.isFinal = isFinal;
   256         }
   258         boolean isFinal() {
   259             return isFinal;
   260         }
   261     }
   263     protected Flow(Context context) {
   264         context.put(flowKey, this);
   265         names = Names.instance(context);
   266         log = Log.instance(context);
   267         syms = Symtab.instance(context);
   268         types = Types.instance(context);
   269         chk = Check.instance(context);
   270         lint = Lint.instance(context);
   271         rs = Resolve.instance(context);
   272         diags = JCDiagnostic.Factory.instance(context);
   273         Source source = Source.instance(context);
   274         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   275         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   276         allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
   277     }
   279     /**
   280      * Base visitor class for all visitors implementing dataflow analysis logic.
   281      * This class define the shared logic for handling jumps (break/continue statements).
   282      */
   283     static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
   285         enum JumpKind {
   286             BREAK(JCTree.Tag.BREAK) {
   287                 @Override
   288                 JCTree getTarget(JCTree tree) {
   289                     return ((JCBreak)tree).target;
   290                 }
   291             },
   292             CONTINUE(JCTree.Tag.CONTINUE) {
   293                 @Override
   294                 JCTree getTarget(JCTree tree) {
   295                     return ((JCContinue)tree).target;
   296                 }
   297             };
   299             final JCTree.Tag treeTag;
   301             private JumpKind(Tag treeTag) {
   302                 this.treeTag = treeTag;
   303             }
   305             abstract JCTree getTarget(JCTree tree);
   306         }
   308         /** The currently pending exits that go from current inner blocks
   309          *  to an enclosing block, in source order.
   310          */
   311         ListBuffer<P> pendingExits;
   313         /** A pending exit.  These are the statements return, break, and
   314          *  continue.  In addition, exception-throwing expressions or
   315          *  statements are put here when not known to be caught.  This
   316          *  will typically result in an error unless it is within a
   317          *  try-finally whose finally block cannot complete normally.
   318          */
   319         static class PendingExit {
   320             JCTree tree;
   322             PendingExit(JCTree tree) {
   323                 this.tree = tree;
   324             }
   326             void resolveJump() {
   327                 //do nothing
   328             }
   329         }
   331         abstract void markDead();
   333         /** Record an outward transfer of control. */
   334         void recordExit(JCTree tree, P pe) {
   335             pendingExits.append(pe);
   336             markDead();
   337         }
   339         /** Resolve all jumps of this statement. */
   340         private boolean resolveJump(JCTree tree,
   341                         ListBuffer<P> oldPendingExits,
   342                         JumpKind jk) {
   343             boolean resolved = false;
   344             List<P> exits = pendingExits.toList();
   345             pendingExits = oldPendingExits;
   346             for (; exits.nonEmpty(); exits = exits.tail) {
   347                 P exit = exits.head;
   348                 if (exit.tree.hasTag(jk.treeTag) &&
   349                         jk.getTarget(exit.tree) == tree) {
   350                     exit.resolveJump();
   351                     resolved = true;
   352                 } else {
   353                     pendingExits.append(exit);
   354                 }
   355             }
   356             return resolved;
   357         }
   359         /** Resolve all breaks of this statement. */
   360         boolean resolveContinues(JCTree tree) {
   361             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
   362         }
   364         /** Resolve all continues of this statement. */
   365         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
   366             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   367         }
   368     }
   370     /**
   371      * This pass implements the first step of the dataflow analysis, namely
   372      * the liveness analysis check. This checks that every statement is reachable.
   373      * The output of this analysis pass are used by other analyzers. This analyzer
   374      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   375      */
   376     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
   378         /** A flag that indicates whether the last statement could
   379          *  complete normally.
   380          */
   381         private boolean alive;
   383         @Override
   384         void markDead() {
   385             alive = false;
   386         }
   388     /*************************************************************************
   389      * Visitor methods for statements and definitions
   390      *************************************************************************/
   392         /** Analyze a definition.
   393          */
   394         void scanDef(JCTree tree) {
   395             scanStat(tree);
   396             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
   397                 log.error(tree.pos(),
   398                           "initializer.must.be.able.to.complete.normally");
   399             }
   400         }
   402         /** Analyze a statement. Check that statement is reachable.
   403          */
   404         void scanStat(JCTree tree) {
   405             if (!alive && tree != null) {
   406                 log.error(tree.pos(), "unreachable.stmt");
   407                 if (!tree.hasTag(SKIP)) alive = true;
   408             }
   409             scan(tree);
   410         }
   412         /** Analyze list of statements.
   413          */
   414         void scanStats(List<? extends JCStatement> trees) {
   415             if (trees != null)
   416                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
   417                     scanStat(l.head);
   418         }
   420         /* ------------ Visitor methods for various sorts of trees -------------*/
   422         public void visitClassDef(JCClassDecl tree) {
   423             if (tree.sym == null) return;
   424             boolean alivePrev = alive;
   425             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   426             Lint lintPrev = lint;
   428             pendingExits = new ListBuffer<PendingExit>();
   429             lint = lint.augment(tree.sym.annotations);
   431             try {
   432                 // process all the static initializers
   433                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   434                     if (!l.head.hasTag(METHODDEF) &&
   435                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   436                         scanDef(l.head);
   437                     }
   438                 }
   440                 // process all the instance initializers
   441                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   442                     if (!l.head.hasTag(METHODDEF) &&
   443                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   444                         scanDef(l.head);
   445                     }
   446                 }
   448                 // process all the methods
   449                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   450                     if (l.head.hasTag(METHODDEF)) {
   451                         scan(l.head);
   452                     }
   453                 }
   454             } finally {
   455                 pendingExits = pendingExitsPrev;
   456                 alive = alivePrev;
   457                 lint = lintPrev;
   458             }
   459         }
   461         public void visitMethodDef(JCMethodDecl tree) {
   462             if (tree.body == null) return;
   463             Lint lintPrev = lint;
   465             lint = lint.augment(tree.sym.annotations);
   467             Assert.check(pendingExits.isEmpty());
   469             try {
   470                 alive = true;
   471                 scanStat(tree.body);
   473                 if (alive && !tree.sym.type.getReturnType().hasTag(VOID))
   474                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   476                 List<PendingExit> exits = pendingExits.toList();
   477                 pendingExits = new ListBuffer<PendingExit>();
   478                 while (exits.nonEmpty()) {
   479                     PendingExit exit = exits.head;
   480                     exits = exits.tail;
   481                     Assert.check(exit.tree.hasTag(RETURN));
   482                 }
   483             } finally {
   484                 lint = lintPrev;
   485             }
   486         }
   488         public void visitVarDef(JCVariableDecl tree) {
   489             if (tree.init != null) {
   490                 Lint lintPrev = lint;
   491                 lint = lint.augment(tree.sym.annotations);
   492                 try{
   493                     scan(tree.init);
   494                 } finally {
   495                     lint = lintPrev;
   496                 }
   497             }
   498         }
   500         public void visitBlock(JCBlock tree) {
   501             scanStats(tree.stats);
   502         }
   504         public void visitDoLoop(JCDoWhileLoop tree) {
   505             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   506             pendingExits = new ListBuffer<PendingExit>();
   507             scanStat(tree.body);
   508             alive |= resolveContinues(tree);
   509             scan(tree.cond);
   510             alive = alive && !tree.cond.type.isTrue();
   511             alive |= resolveBreaks(tree, prevPendingExits);
   512         }
   514         public void visitWhileLoop(JCWhileLoop tree) {
   515             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   516             pendingExits = new ListBuffer<PendingExit>();
   517             scan(tree.cond);
   518             alive = !tree.cond.type.isFalse();
   519             scanStat(tree.body);
   520             alive |= resolveContinues(tree);
   521             alive = resolveBreaks(tree, prevPendingExits) ||
   522                 !tree.cond.type.isTrue();
   523         }
   525         public void visitForLoop(JCForLoop tree) {
   526             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   527             scanStats(tree.init);
   528             pendingExits = new ListBuffer<PendingExit>();
   529             if (tree.cond != null) {
   530                 scan(tree.cond);
   531                 alive = !tree.cond.type.isFalse();
   532             } else {
   533                 alive = true;
   534             }
   535             scanStat(tree.body);
   536             alive |= resolveContinues(tree);
   537             scan(tree.step);
   538             alive = resolveBreaks(tree, prevPendingExits) ||
   539                 tree.cond != null && !tree.cond.type.isTrue();
   540         }
   542         public void visitForeachLoop(JCEnhancedForLoop tree) {
   543             visitVarDef(tree.var);
   544             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   545             scan(tree.expr);
   546             pendingExits = new ListBuffer<PendingExit>();
   547             scanStat(tree.body);
   548             alive |= resolveContinues(tree);
   549             resolveBreaks(tree, prevPendingExits);
   550             alive = true;
   551         }
   553         public void visitLabelled(JCLabeledStatement tree) {
   554             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   555             pendingExits = new ListBuffer<PendingExit>();
   556             scanStat(tree.body);
   557             alive |= resolveBreaks(tree, prevPendingExits);
   558         }
   560         public void visitSwitch(JCSwitch tree) {
   561             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   562             pendingExits = new ListBuffer<PendingExit>();
   563             scan(tree.selector);
   564             boolean hasDefault = false;
   565             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   566                 alive = true;
   567                 JCCase c = l.head;
   568                 if (c.pat == null)
   569                     hasDefault = true;
   570                 else
   571                     scan(c.pat);
   572                 scanStats(c.stats);
   573                 // Warn about fall-through if lint switch fallthrough enabled.
   574                 if (alive &&
   575                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   576                     c.stats.nonEmpty() && l.tail.nonEmpty())
   577                     log.warning(Lint.LintCategory.FALLTHROUGH,
   578                                 l.tail.head.pos(),
   579                                 "possible.fall-through.into.case");
   580             }
   581             if (!hasDefault) {
   582                 alive = true;
   583             }
   584             alive |= resolveBreaks(tree, prevPendingExits);
   585         }
   587         public void visitTry(JCTry tree) {
   588             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   589             pendingExits = new ListBuffer<PendingExit>();
   590             for (JCTree resource : tree.resources) {
   591                 if (resource instanceof JCVariableDecl) {
   592                     JCVariableDecl vdecl = (JCVariableDecl) resource;
   593                     visitVarDef(vdecl);
   594                 } else if (resource instanceof JCExpression) {
   595                     scan((JCExpression) resource);
   596                 } else {
   597                     throw new AssertionError(tree);  // parser error
   598                 }
   599             }
   601             scanStat(tree.body);
   602             boolean aliveEnd = alive;
   604             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   605                 alive = true;
   606                 JCVariableDecl param = l.head.param;
   607                 scan(param);
   608                 scanStat(l.head.body);
   609                 aliveEnd |= alive;
   610             }
   611             if (tree.finalizer != null) {
   612                 ListBuffer<PendingExit> exits = pendingExits;
   613                 pendingExits = prevPendingExits;
   614                 alive = true;
   615                 scanStat(tree.finalizer);
   616                 tree.finallyCanCompleteNormally = alive;
   617                 if (!alive) {
   618                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
   619                         log.warning(Lint.LintCategory.FINALLY,
   620                                 TreeInfo.diagEndPos(tree.finalizer),
   621                                 "finally.cannot.complete");
   622                     }
   623                 } else {
   624                     while (exits.nonEmpty()) {
   625                         pendingExits.append(exits.next());
   626                     }
   627                     alive = aliveEnd;
   628                 }
   629             } else {
   630                 alive = aliveEnd;
   631                 ListBuffer<PendingExit> exits = pendingExits;
   632                 pendingExits = prevPendingExits;
   633                 while (exits.nonEmpty()) pendingExits.append(exits.next());
   634             }
   635         }
   637         @Override
   638         public void visitIf(JCIf tree) {
   639             scan(tree.cond);
   640             scanStat(tree.thenpart);
   641             if (tree.elsepart != null) {
   642                 boolean aliveAfterThen = alive;
   643                 alive = true;
   644                 scanStat(tree.elsepart);
   645                 alive = alive | aliveAfterThen;
   646             } else {
   647                 alive = true;
   648             }
   649         }
   651         public void visitBreak(JCBreak tree) {
   652             recordExit(tree, new PendingExit(tree));
   653         }
   655         public void visitContinue(JCContinue tree) {
   656             recordExit(tree, new PendingExit(tree));
   657         }
   659         public void visitReturn(JCReturn tree) {
   660             scan(tree.expr);
   661             recordExit(tree, new PendingExit(tree));
   662         }
   664         public void visitThrow(JCThrow tree) {
   665             scan(tree.expr);
   666             markDead();
   667         }
   669         public void visitApply(JCMethodInvocation tree) {
   670             scan(tree.meth);
   671             scan(tree.args);
   672         }
   674         public void visitNewClass(JCNewClass tree) {
   675             scan(tree.encl);
   676             scan(tree.args);
   677             if (tree.def != null) {
   678                 scan(tree.def);
   679             }
   680         }
   682         @Override
   683         public void visitLambda(JCLambda tree) {
   684             if (tree.type != null &&
   685                     tree.type.isErroneous()) {
   686                 return;
   687             }
   689             ListBuffer<PendingExit> prevPending = pendingExits;
   690             boolean prevAlive = alive;
   691             try {
   692                 pendingExits = ListBuffer.lb();
   693                 alive = true;
   694                 scanStat(tree.body);
   695                 tree.canCompleteNormally = alive;
   696             }
   697             finally {
   698                 pendingExits = prevPending;
   699                 alive = prevAlive;
   700             }
   701         }
   703         public void visitTopLevel(JCCompilationUnit tree) {
   704             // Do nothing for TopLevel since each class is visited individually
   705         }
   707     /**************************************************************************
   708      * main method
   709      *************************************************************************/
   711         /** Perform definite assignment/unassignment analysis on a tree.
   712          */
   713         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   714             analyzeTree(env, env.tree, make);
   715         }
   716         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
   717             try {
   718                 attrEnv = env;
   719                 Flow.this.make = make;
   720                 pendingExits = new ListBuffer<PendingExit>();
   721                 alive = true;
   722                 scan(env.tree);
   723             } finally {
   724                 pendingExits = null;
   725                 Flow.this.make = null;
   726             }
   727         }
   728     }
   730     /**
   731      * This pass implements the second step of the dataflow analysis, namely
   732      * the exception analysis. This is to ensure that every checked exception that is
   733      * thrown is declared or caught. The analyzer uses some info that has been set by
   734      * the liveliness analyzer.
   735      */
   736     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   738         /** A flag that indicates whether the last statement could
   739          *  complete normally.
   740          */
   741         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   743         /** The current class being defined.
   744          */
   745         JCClassDecl classDef;
   747         /** The list of possibly thrown declarable exceptions.
   748          */
   749         List<Type> thrown;
   751         /** The list of exceptions that are either caught or declared to be
   752          *  thrown.
   753          */
   754         List<Type> caught;
   756         class FlowPendingExit extends BaseAnalyzer.PendingExit {
   758             Type thrown;
   760             FlowPendingExit(JCTree tree, Type thrown) {
   761                 super(tree);
   762                 this.thrown = thrown;
   763             }
   764         }
   766         @Override
   767         void markDead() {
   768             //do nothing
   769         }
   771         /*-------------------- Exceptions ----------------------*/
   773         /** Complain that pending exceptions are not caught.
   774          */
   775         void errorUncaught() {
   776             for (FlowPendingExit exit = pendingExits.next();
   777                  exit != null;
   778                  exit = pendingExits.next()) {
   779                 if (classDef != null &&
   780                     classDef.pos == exit.tree.pos) {
   781                     log.error(exit.tree.pos(),
   782                             "unreported.exception.default.constructor",
   783                             exit.thrown);
   784                 } else if (exit.tree.hasTag(VARDEF) &&
   785                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   786                     log.error(exit.tree.pos(),
   787                             "unreported.exception.implicit.close",
   788                             exit.thrown,
   789                             ((JCVariableDecl)exit.tree).sym.name);
   790                 } else {
   791                     log.error(exit.tree.pos(),
   792                             "unreported.exception.need.to.catch.or.throw",
   793                             exit.thrown);
   794                 }
   795             }
   796         }
   798         /** Record that exception is potentially thrown and check that it
   799          *  is caught.
   800          */
   801         void markThrown(JCTree tree, Type exc) {
   802             if (!chk.isUnchecked(tree.pos(), exc)) {
   803                 if (!chk.isHandled(exc, caught))
   804                     pendingExits.append(new FlowPendingExit(tree, exc));
   805                     thrown = chk.incl(exc, thrown);
   806             }
   807         }
   809     /*************************************************************************
   810      * Visitor methods for statements and definitions
   811      *************************************************************************/
   813         /* ------------ Visitor methods for various sorts of trees -------------*/
   815         public void visitClassDef(JCClassDecl tree) {
   816             if (tree.sym == null) return;
   818             JCClassDecl classDefPrev = classDef;
   819             List<Type> thrownPrev = thrown;
   820             List<Type> caughtPrev = caught;
   821             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   822             Lint lintPrev = lint;
   824             pendingExits = new ListBuffer<FlowPendingExit>();
   825             if (tree.name != names.empty) {
   826                 caught = List.nil();
   827             }
   828             classDef = tree;
   829             thrown = List.nil();
   830             lint = lint.augment(tree.sym.annotations);
   832             try {
   833                 // process all the static initializers
   834                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   835                     if (!l.head.hasTag(METHODDEF) &&
   836                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   837                         scan(l.head);
   838                         errorUncaught();
   839                     }
   840                 }
   842                 // add intersection of all thrown clauses of initial constructors
   843                 // to set of caught exceptions, unless class is anonymous.
   844                 if (tree.name != names.empty) {
   845                     boolean firstConstructor = true;
   846                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   847                         if (TreeInfo.isInitialConstructor(l.head)) {
   848                             List<Type> mthrown =
   849                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
   850                             if (firstConstructor) {
   851                                 caught = mthrown;
   852                                 firstConstructor = false;
   853                             } else {
   854                                 caught = chk.intersect(mthrown, caught);
   855                             }
   856                         }
   857                     }
   858                 }
   860                 // process all the instance initializers
   861                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   862                     if (!l.head.hasTag(METHODDEF) &&
   863                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   864                         scan(l.head);
   865                         errorUncaught();
   866                     }
   867                 }
   869                 // in an anonymous class, add the set of thrown exceptions to
   870                 // the throws clause of the synthetic constructor and propagate
   871                 // outwards.
   872                 // Changing the throws clause on the fly is okay here because
   873                 // the anonymous constructor can't be invoked anywhere else,
   874                 // and its type hasn't been cached.
   875                 if (tree.name == names.empty) {
   876                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   877                         if (TreeInfo.isInitialConstructor(l.head)) {
   878                             JCMethodDecl mdef = (JCMethodDecl)l.head;
   879                             mdef.thrown = make.Types(thrown);
   880                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
   881                         }
   882                     }
   883                     thrownPrev = chk.union(thrown, thrownPrev);
   884                 }
   886                 // process all the methods
   887                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   888                     if (l.head.hasTag(METHODDEF)) {
   889                         scan(l.head);
   890                         errorUncaught();
   891                     }
   892                 }
   894                 thrown = thrownPrev;
   895             } finally {
   896                 pendingExits = pendingExitsPrev;
   897                 caught = caughtPrev;
   898                 classDef = classDefPrev;
   899                 lint = lintPrev;
   900             }
   901         }
   903         public void visitMethodDef(JCMethodDecl tree) {
   904             if (tree.body == null) return;
   906             List<Type> caughtPrev = caught;
   907             List<Type> mthrown = tree.sym.type.getThrownTypes();
   908             Lint lintPrev = lint;
   910             lint = lint.augment(tree.sym.annotations);
   912             Assert.check(pendingExits.isEmpty());
   914             try {
   915                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   916                     JCVariableDecl def = l.head;
   917                     scan(def);
   918                 }
   919                 if (TreeInfo.isInitialConstructor(tree))
   920                     caught = chk.union(caught, mthrown);
   921                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   922                     caught = mthrown;
   923                 // else we are in an instance initializer block;
   924                 // leave caught unchanged.
   926                 scan(tree.body);
   928                 List<FlowPendingExit> exits = pendingExits.toList();
   929                 pendingExits = new ListBuffer<FlowPendingExit>();
   930                 while (exits.nonEmpty()) {
   931                     FlowPendingExit exit = exits.head;
   932                     exits = exits.tail;
   933                     if (exit.thrown == null) {
   934                         Assert.check(exit.tree.hasTag(RETURN));
   935                     } else {
   936                         // uncaught throws will be reported later
   937                         pendingExits.append(exit);
   938                     }
   939                 }
   940             } finally {
   941                 caught = caughtPrev;
   942                 lint = lintPrev;
   943             }
   944         }
   946         public void visitVarDef(JCVariableDecl tree) {
   947             if (tree.init != null) {
   948                 Lint lintPrev = lint;
   949                 lint = lint.augment(tree.sym.annotations);
   950                 try{
   951                     scan(tree.init);
   952                 } finally {
   953                     lint = lintPrev;
   954                 }
   955             }
   956         }
   958         public void visitBlock(JCBlock tree) {
   959             scan(tree.stats);
   960         }
   962         public void visitDoLoop(JCDoWhileLoop tree) {
   963             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   964             pendingExits = new ListBuffer<FlowPendingExit>();
   965             scan(tree.body);
   966             resolveContinues(tree);
   967             scan(tree.cond);
   968             resolveBreaks(tree, prevPendingExits);
   969         }
   971         public void visitWhileLoop(JCWhileLoop tree) {
   972             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   973             pendingExits = new ListBuffer<FlowPendingExit>();
   974             scan(tree.cond);
   975             scan(tree.body);
   976             resolveContinues(tree);
   977             resolveBreaks(tree, prevPendingExits);
   978         }
   980         public void visitForLoop(JCForLoop tree) {
   981             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   982             scan(tree.init);
   983             pendingExits = new ListBuffer<FlowPendingExit>();
   984             if (tree.cond != null) {
   985                 scan(tree.cond);
   986             }
   987             scan(tree.body);
   988             resolveContinues(tree);
   989             scan(tree.step);
   990             resolveBreaks(tree, prevPendingExits);
   991         }
   993         public void visitForeachLoop(JCEnhancedForLoop tree) {
   994             visitVarDef(tree.var);
   995             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   996             scan(tree.expr);
   997             pendingExits = new ListBuffer<FlowPendingExit>();
   998             scan(tree.body);
   999             resolveContinues(tree);
  1000             resolveBreaks(tree, prevPendingExits);
  1003         public void visitLabelled(JCLabeledStatement tree) {
  1004             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1005             pendingExits = new ListBuffer<FlowPendingExit>();
  1006             scan(tree.body);
  1007             resolveBreaks(tree, prevPendingExits);
  1010         public void visitSwitch(JCSwitch tree) {
  1011             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1012             pendingExits = new ListBuffer<FlowPendingExit>();
  1013             scan(tree.selector);
  1014             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1015                 JCCase c = l.head;
  1016                 if (c.pat != null) {
  1017                     scan(c.pat);
  1019                 scan(c.stats);
  1021             resolveBreaks(tree, prevPendingExits);
  1024         public void visitTry(JCTry tree) {
  1025             List<Type> caughtPrev = caught;
  1026             List<Type> thrownPrev = thrown;
  1027             thrown = List.nil();
  1028             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1029                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1030                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1031                         List.of(l.head.param.vartype);
  1032                 for (JCExpression ct : subClauses) {
  1033                     caught = chk.incl(ct.type, caught);
  1037             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1038             pendingExits = new ListBuffer<FlowPendingExit>();
  1039             for (JCTree resource : tree.resources) {
  1040                 if (resource instanceof JCVariableDecl) {
  1041                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1042                     visitVarDef(vdecl);
  1043                 } else if (resource instanceof JCExpression) {
  1044                     scan((JCExpression) resource);
  1045                 } else {
  1046                     throw new AssertionError(tree);  // parser error
  1049             for (JCTree resource : tree.resources) {
  1050                 List<Type> closeableSupertypes = resource.type.isCompound() ?
  1051                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
  1052                     List.of(resource.type);
  1053                 for (Type sup : closeableSupertypes) {
  1054                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
  1055                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
  1056                                 attrEnv,
  1057                                 sup,
  1058                                 names.close,
  1059                                 List.<Type>nil(),
  1060                                 List.<Type>nil());
  1061                         if (closeMethod.kind == MTH) {
  1062                             for (Type t : ((MethodSymbol)closeMethod).getThrownTypes()) {
  1063                                 markThrown(resource, t);
  1069             scan(tree.body);
  1070             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1071                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1072                 thrown;
  1073             thrown = thrownPrev;
  1074             caught = caughtPrev;
  1076             List<Type> caughtInTry = List.nil();
  1077             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1078                 JCVariableDecl param = l.head.param;
  1079                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1080                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1081                         List.of(l.head.param.vartype);
  1082                 List<Type> ctypes = List.nil();
  1083                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
  1084                 for (JCExpression ct : subClauses) {
  1085                     Type exc = ct.type;
  1086                     if (exc != syms.unknownType) {
  1087                         ctypes = ctypes.append(exc);
  1088                         if (types.isSameType(exc, syms.objectType))
  1089                             continue;
  1090                         checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
  1091                         caughtInTry = chk.incl(exc, caughtInTry);
  1094                 scan(param);
  1095                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1096                 scan(l.head.body);
  1097                 preciseRethrowTypes.remove(param.sym);
  1099             if (tree.finalizer != null) {
  1100                 List<Type> savedThrown = thrown;
  1101                 thrown = List.nil();
  1102                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1103                 pendingExits = prevPendingExits;
  1104                 scan(tree.finalizer);
  1105                 if (!tree.finallyCanCompleteNormally) {
  1106                     // discard exits and exceptions from try and finally
  1107                     thrown = chk.union(thrown, thrownPrev);
  1108                 } else {
  1109                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1110                     thrown = chk.union(thrown, savedThrown);
  1111                     // FIX: this doesn't preserve source order of exits in catch
  1112                     // versus finally!
  1113                     while (exits.nonEmpty()) {
  1114                         pendingExits.append(exits.next());
  1117             } else {
  1118                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1119                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1120                 pendingExits = prevPendingExits;
  1121                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1125         @Override
  1126         public void visitIf(JCIf tree) {
  1127             scan(tree.cond);
  1128             scan(tree.thenpart);
  1129             if (tree.elsepart != null) {
  1130                 scan(tree.elsepart);
  1134         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1135             if (chk.subset(exc, caughtInTry)) {
  1136                 log.error(pos, "except.already.caught", exc);
  1137             } else if (!chk.isUnchecked(pos, exc) &&
  1138                     !isExceptionOrThrowable(exc) &&
  1139                     !chk.intersects(exc, thrownInTry)) {
  1140                 log.error(pos, "except.never.thrown.in.try", exc);
  1141             } else if (allowImprovedCatchAnalysis) {
  1142                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
  1143                 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
  1144                 // unchecked exception, the result list would not be empty, as the augmented
  1145                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
  1146                 // exception, that would have been covered in the branch above
  1147                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
  1148                         !isExceptionOrThrowable(exc)) {
  1149                     String key = catchableThrownTypes.length() == 1 ?
  1150                             "unreachable.catch" :
  1151                             "unreachable.catch.1";
  1152                     log.warning(pos, key, catchableThrownTypes);
  1156         //where
  1157             private boolean isExceptionOrThrowable(Type exc) {
  1158                 return exc.tsym == syms.throwableType.tsym ||
  1159                     exc.tsym == syms.exceptionType.tsym;
  1162         public void visitBreak(JCBreak tree) {
  1163             recordExit(tree, new FlowPendingExit(tree, null));
  1166         public void visitContinue(JCContinue tree) {
  1167             recordExit(tree, new FlowPendingExit(tree, null));
  1170         public void visitReturn(JCReturn tree) {
  1171             scan(tree.expr);
  1172             recordExit(tree, new FlowPendingExit(tree, null));
  1175         public void visitThrow(JCThrow tree) {
  1176             scan(tree.expr);
  1177             Symbol sym = TreeInfo.symbol(tree.expr);
  1178             if (sym != null &&
  1179                 sym.kind == VAR &&
  1180                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
  1181                 preciseRethrowTypes.get(sym) != null &&
  1182                 allowImprovedRethrowAnalysis) {
  1183                 for (Type t : preciseRethrowTypes.get(sym)) {
  1184                     markThrown(tree, t);
  1187             else {
  1188                 markThrown(tree, tree.expr.type);
  1190             markDead();
  1193         public void visitApply(JCMethodInvocation tree) {
  1194             scan(tree.meth);
  1195             scan(tree.args);
  1196             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
  1197                 markThrown(tree, l.head);
  1200         public void visitNewClass(JCNewClass tree) {
  1201             scan(tree.encl);
  1202             scan(tree.args);
  1203            // scan(tree.def);
  1204             for (List<Type> l = tree.constructorType.getThrownTypes();
  1205                  l.nonEmpty();
  1206                  l = l.tail) {
  1207                 markThrown(tree, l.head);
  1209             List<Type> caughtPrev = caught;
  1210             try {
  1211                 // If the new class expression defines an anonymous class,
  1212                 // analysis of the anonymous constructor may encounter thrown
  1213                 // types which are unsubstituted type variables.
  1214                 // However, since the constructor's actual thrown types have
  1215                 // already been marked as thrown, it is safe to simply include
  1216                 // each of the constructor's formal thrown types in the set of
  1217                 // 'caught/declared to be thrown' types, for the duration of
  1218                 // the class def analysis.
  1219                 if (tree.def != null)
  1220                     for (List<Type> l = tree.constructor.type.getThrownTypes();
  1221                          l.nonEmpty();
  1222                          l = l.tail) {
  1223                         caught = chk.incl(l.head, caught);
  1225                 scan(tree.def);
  1227             finally {
  1228                 caught = caughtPrev;
  1232         @Override
  1233         public void visitLambda(JCLambda tree) {
  1234             if (tree.type != null &&
  1235                     tree.type.isErroneous()) {
  1236                 return;
  1238             List<Type> prevCaught = caught;
  1239             List<Type> prevThrown = thrown;
  1240             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1241             try {
  1242                 pendingExits = ListBuffer.lb();
  1243                 caught = List.of(syms.throwableType); //inhibit exception checking
  1244                 thrown = List.nil();
  1245                 scan(tree.body);
  1246                 tree.inferredThrownTypes = thrown;
  1248             finally {
  1249                 pendingExits = prevPending;
  1250                 caught = prevCaught;
  1251                 thrown = prevThrown;
  1255         public void visitTopLevel(JCCompilationUnit tree) {
  1256             // Do nothing for TopLevel since each class is visited individually
  1259     /**************************************************************************
  1260      * main method
  1261      *************************************************************************/
  1263         /** Perform definite assignment/unassignment analysis on a tree.
  1264          */
  1265         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1266             analyzeTree(env, env.tree, make);
  1268         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  1269             try {
  1270                 attrEnv = env;
  1271                 Flow.this.make = make;
  1272                 pendingExits = new ListBuffer<FlowPendingExit>();
  1273                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1274                 this.thrown = this.caught = null;
  1275                 this.classDef = null;
  1276                 scan(tree);
  1277             } finally {
  1278                 pendingExits = null;
  1279                 Flow.this.make = null;
  1280                 this.thrown = this.caught = null;
  1281                 this.classDef = null;
  1286     /**
  1287      * This pass implements (i) definite assignment analysis, which ensures that
  1288      * each variable is assigned when used and (ii) definite unassignment analysis,
  1289      * which ensures that no final variable is assigned more than once. This visitor
  1290      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1291      * effectively-final local variables/parameters.
  1292      */
  1293     class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
  1295         /** The set of definitely assigned variables.
  1296          */
  1297         Bits inits;
  1299         /** The set of definitely unassigned variables.
  1300          */
  1301         Bits uninits;
  1303         /** The set of variables that are definitely unassigned everywhere
  1304          *  in current try block. This variable is maintained lazily; it is
  1305          *  updated only when something gets removed from uninits,
  1306          *  typically by being assigned in reachable code.  To obtain the
  1307          *  correct set of variables which are definitely unassigned
  1308          *  anywhere in current try block, intersect uninitsTry and
  1309          *  uninits.
  1310          */
  1311         Bits uninitsTry;
  1313         /** When analyzing a condition, inits and uninits are null.
  1314          *  Instead we have:
  1315          */
  1316         Bits initsWhenTrue;
  1317         Bits initsWhenFalse;
  1318         Bits uninitsWhenTrue;
  1319         Bits uninitsWhenFalse;
  1321         /** A mapping from addresses to variable symbols.
  1322          */
  1323         VarSymbol[] vars;
  1325         /** The current class being defined.
  1326          */
  1327         JCClassDecl classDef;
  1329         /** The first variable sequence number in this class definition.
  1330          */
  1331         int firstadr;
  1333         /** The next available variable sequence number.
  1334          */
  1335         int nextadr;
  1337         /** The first variable sequence number in a block that can return.
  1338          */
  1339         int returnadr;
  1341         /** The list of unreferenced automatic resources.
  1342          */
  1343         Scope unrefdResources;
  1345         /** Set when processing a loop body the second time for DU analysis. */
  1346         FlowKind flowKind = FlowKind.NORMAL;
  1348         /** The starting position of the analysed tree */
  1349         int startPos;
  1351         class AssignPendingExit extends BaseAnalyzer.PendingExit {
  1353             Bits exit_inits;
  1354             Bits exit_uninits;
  1356             AssignPendingExit(JCTree tree, Bits inits, Bits uninits) {
  1357                 super(tree);
  1358                 this.exit_inits = inits.dup();
  1359                 this.exit_uninits = uninits.dup();
  1362             void resolveJump() {
  1363                 inits.andSet(exit_inits);
  1364                 uninits.andSet(exit_uninits);
  1368         @Override
  1369         void markDead() {
  1370             inits.inclRange(returnadr, nextadr);
  1371             uninits.inclRange(returnadr, nextadr);
  1374         /*-------------- Processing variables ----------------------*/
  1376         /** Do we need to track init/uninit state of this symbol?
  1377          *  I.e. is symbol either a local or a blank final variable?
  1378          */
  1379         boolean trackable(VarSymbol sym) {
  1380             return
  1381                 sym.pos >= startPos &&
  1382                 ((sym.owner.kind == MTH ||
  1383                  ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1384                   classDef.sym.isEnclosedBy((ClassSymbol)sym.owner))));
  1387         /** Initialize new trackable variable by setting its address field
  1388          *  to the next available sequence number and entering it under that
  1389          *  index into the vars array.
  1390          */
  1391         void newVar(VarSymbol sym) {
  1392             vars = ArrayUtils.ensureCapacity(vars, nextadr);
  1393             if ((sym.flags() & FINAL) == 0) {
  1394                 sym.flags_field |= EFFECTIVELY_FINAL;
  1396             sym.adr = nextadr;
  1397             vars[nextadr] = sym;
  1398             inits.excl(nextadr);
  1399             uninits.incl(nextadr);
  1400             nextadr++;
  1403         /** Record an initialization of a trackable variable.
  1404          */
  1405         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1406             if (sym.adr >= firstadr && trackable(sym)) {
  1407                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
  1408                     if (!uninits.isMember(sym.adr)) {
  1409                         //assignment targeting an effectively final variable
  1410                         //makes the variable lose its status of effectively final
  1411                         //if the variable is _not_ definitively unassigned
  1412                         sym.flags_field &= ~EFFECTIVELY_FINAL;
  1413                     } else {
  1414                         uninit(sym);
  1417                 else if ((sym.flags() & FINAL) != 0) {
  1418                     if ((sym.flags() & PARAMETER) != 0) {
  1419                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  1420                             log.error(pos, "multicatch.parameter.may.not.be.assigned",
  1421                                       sym);
  1423                         else {
  1424                             log.error(pos, "final.parameter.may.not.be.assigned",
  1425                                   sym);
  1427                     } else if (!uninits.isMember(sym.adr)) {
  1428                         log.error(pos, flowKind.errKey, sym);
  1429                     } else {
  1430                         uninit(sym);
  1433                 inits.incl(sym.adr);
  1434             } else if ((sym.flags() & FINAL) != 0) {
  1435                 log.error(pos, "var.might.already.be.assigned", sym);
  1438         //where
  1439             void uninit(VarSymbol sym) {
  1440                 if (!inits.isMember(sym.adr)) {
  1441                     // reachable assignment
  1442                     uninits.excl(sym.adr);
  1443                     uninitsTry.excl(sym.adr);
  1444                 } else {
  1445                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
  1446                     uninits.excl(sym.adr);
  1450         /** If tree is either a simple name or of the form this.name or
  1451          *  C.this.name, and tree represents a trackable variable,
  1452          *  record an initialization of the variable.
  1453          */
  1454         void letInit(JCTree tree) {
  1455             tree = TreeInfo.skipParens(tree);
  1456             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  1457                 Symbol sym = TreeInfo.symbol(tree);
  1458                 if (sym.kind == VAR) {
  1459                     letInit(tree.pos(), (VarSymbol)sym);
  1464         /** Check that trackable variable is initialized.
  1465          */
  1466         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
  1467             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  1468                 trackable(sym) &&
  1469                 !inits.isMember(sym.adr)) {
  1470                 log.error(pos, "var.might.not.have.been.initialized",
  1471                           sym);
  1472                 inits.incl(sym.adr);
  1476         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
  1477          */
  1478         void split(boolean setToNull) {
  1479             initsWhenFalse = inits.dup();
  1480             uninitsWhenFalse = uninits.dup();
  1481             initsWhenTrue = inits;
  1482             uninitsWhenTrue = uninits;
  1483             if (setToNull)
  1484                 inits = uninits = null;
  1487         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
  1488          */
  1489         void merge() {
  1490             inits = initsWhenFalse.andSet(initsWhenTrue);
  1491             uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
  1494     /* ************************************************************************
  1495      * Visitor methods for statements and definitions
  1496      *************************************************************************/
  1498         /** Analyze an expression. Make sure to set (un)inits rather than
  1499          *  (un)initsWhenTrue(WhenFalse) on exit.
  1500          */
  1501         void scanExpr(JCTree tree) {
  1502             if (tree != null) {
  1503                 scan(tree);
  1504                 if (inits == null) merge();
  1508         /** Analyze a list of expressions.
  1509          */
  1510         void scanExprs(List<? extends JCExpression> trees) {
  1511             if (trees != null)
  1512                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
  1513                     scanExpr(l.head);
  1516         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
  1517          *  rather than (un)inits on exit.
  1518          */
  1519         void scanCond(JCTree tree) {
  1520             if (tree.type.isFalse()) {
  1521                 if (inits == null) merge();
  1522                 initsWhenTrue = inits.dup();
  1523                 initsWhenTrue.inclRange(firstadr, nextadr);
  1524                 uninitsWhenTrue = uninits.dup();
  1525                 uninitsWhenTrue.inclRange(firstadr, nextadr);
  1526                 initsWhenFalse = inits;
  1527                 uninitsWhenFalse = uninits;
  1528             } else if (tree.type.isTrue()) {
  1529                 if (inits == null) merge();
  1530                 initsWhenFalse = inits.dup();
  1531                 initsWhenFalse.inclRange(firstadr, nextadr);
  1532                 uninitsWhenFalse = uninits.dup();
  1533                 uninitsWhenFalse.inclRange(firstadr, nextadr);
  1534                 initsWhenTrue = inits;
  1535                 uninitsWhenTrue = uninits;
  1536             } else {
  1537                 scan(tree);
  1538                 if (inits != null)
  1539                     split(tree.type != syms.unknownType);
  1541             if (tree.type != syms.unknownType)
  1542                 inits = uninits = null;
  1545         /* ------------ Visitor methods for various sorts of trees -------------*/
  1547         public void visitClassDef(JCClassDecl tree) {
  1548             if (tree.sym == null) return;
  1550             JCClassDecl classDefPrev = classDef;
  1551             int firstadrPrev = firstadr;
  1552             int nextadrPrev = nextadr;
  1553             ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
  1554             Lint lintPrev = lint;
  1556             pendingExits = new ListBuffer<AssignPendingExit>();
  1557             if (tree.name != names.empty) {
  1558                 firstadr = nextadr;
  1560             classDef = tree;
  1561             lint = lint.augment(tree.sym.annotations);
  1563             try {
  1564                 // define all the static fields
  1565                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1566                     if (l.head.hasTag(VARDEF)) {
  1567                         JCVariableDecl def = (JCVariableDecl)l.head;
  1568                         if ((def.mods.flags & STATIC) != 0) {
  1569                             VarSymbol sym = def.sym;
  1570                             if (trackable(sym))
  1571                                 newVar(sym);
  1576                 // process all the static initializers
  1577                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1578                     if (!l.head.hasTag(METHODDEF) &&
  1579                         (TreeInfo.flags(l.head) & STATIC) != 0) {
  1580                         scan(l.head);
  1584                 // define all the instance fields
  1585                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1586                     if (l.head.hasTag(VARDEF)) {
  1587                         JCVariableDecl def = (JCVariableDecl)l.head;
  1588                         if ((def.mods.flags & STATIC) == 0) {
  1589                             VarSymbol sym = def.sym;
  1590                             if (trackable(sym))
  1591                                 newVar(sym);
  1596                 // process all the instance initializers
  1597                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1598                     if (!l.head.hasTag(METHODDEF) &&
  1599                         (TreeInfo.flags(l.head) & STATIC) == 0) {
  1600                         scan(l.head);
  1604                 // process all the methods
  1605                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1606                     if (l.head.hasTag(METHODDEF)) {
  1607                         scan(l.head);
  1610             } finally {
  1611                 pendingExits = pendingExitsPrev;
  1612                 nextadr = nextadrPrev;
  1613                 firstadr = firstadrPrev;
  1614                 classDef = classDefPrev;
  1615                 lint = lintPrev;
  1619         public void visitMethodDef(JCMethodDecl tree) {
  1620             if (tree.body == null) return;
  1622             Bits initsPrev = inits.dup();
  1623             Bits uninitsPrev = uninits.dup();
  1624             int nextadrPrev = nextadr;
  1625             int firstadrPrev = firstadr;
  1626             int returnadrPrev = returnadr;
  1627             Lint lintPrev = lint;
  1629             lint = lint.augment(tree.sym.annotations);
  1631             Assert.check(pendingExits.isEmpty());
  1633             try {
  1634                 boolean isInitialConstructor =
  1635                     TreeInfo.isInitialConstructor(tree);
  1637                 if (!isInitialConstructor)
  1638                     firstadr = nextadr;
  1639                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  1640                     JCVariableDecl def = l.head;
  1641                     scan(def);
  1642                     inits.incl(def.sym.adr);
  1643                     uninits.excl(def.sym.adr);
  1645                 // else we are in an instance initializer block;
  1646                 // leave caught unchanged.
  1647                 scan(tree.body);
  1649                 if (isInitialConstructor) {
  1650                     for (int i = firstadr; i < nextadr; i++)
  1651                         if (vars[i].owner == classDef.sym)
  1652                             checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
  1654                 List<AssignPendingExit> exits = pendingExits.toList();
  1655                 pendingExits = new ListBuffer<AssignPendingExit>();
  1656                 while (exits.nonEmpty()) {
  1657                     AssignPendingExit exit = exits.head;
  1658                     exits = exits.tail;
  1659                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1660                     if (isInitialConstructor) {
  1661                         inits = exit.exit_inits;
  1662                         for (int i = firstadr; i < nextadr; i++)
  1663                             checkInit(exit.tree.pos(), vars[i]);
  1666             } finally {
  1667                 inits = initsPrev;
  1668                 uninits = uninitsPrev;
  1669                 nextadr = nextadrPrev;
  1670                 firstadr = firstadrPrev;
  1671                 returnadr = returnadrPrev;
  1672                 lint = lintPrev;
  1676         public void visitVarDef(JCVariableDecl tree) {
  1677             boolean track = trackable(tree.sym);
  1678             if (track && tree.sym.owner.kind == MTH) newVar(tree.sym);
  1679             if (tree.init != null) {
  1680                 Lint lintPrev = lint;
  1681                 lint = lint.augment(tree.sym.annotations);
  1682                 try{
  1683                     scanExpr(tree.init);
  1684                     if (track) letInit(tree.pos(), tree.sym);
  1685                 } finally {
  1686                     lint = lintPrev;
  1691         public void visitBlock(JCBlock tree) {
  1692             int nextadrPrev = nextadr;
  1693             scan(tree.stats);
  1694             nextadr = nextadrPrev;
  1697         public void visitDoLoop(JCDoWhileLoop tree) {
  1698             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1699             FlowKind prevFlowKind = flowKind;
  1700             flowKind = FlowKind.NORMAL;
  1701             Bits initsSkip = null;
  1702             Bits uninitsSkip = null;
  1703             pendingExits = new ListBuffer<AssignPendingExit>();
  1704             int prevErrors = log.nerrors;
  1705             do {
  1706                 Bits uninitsEntry = uninits.dup();
  1707                 uninitsEntry.excludeFrom(nextadr);
  1708                 scan(tree.body);
  1709                 resolveContinues(tree);
  1710                 scanCond(tree.cond);
  1711                 if (!flowKind.isFinal()) {
  1712                     initsSkip = initsWhenFalse;
  1713                     uninitsSkip = uninitsWhenFalse;
  1715                 if (log.nerrors !=  prevErrors ||
  1716                     flowKind.isFinal() ||
  1717                     uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1718                     break;
  1719                 inits = initsWhenTrue;
  1720                 uninits = uninitsEntry.andSet(uninitsWhenTrue);
  1721                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1722             } while (true);
  1723             flowKind = prevFlowKind;
  1724             inits = initsSkip;
  1725             uninits = uninitsSkip;
  1726             resolveBreaks(tree, prevPendingExits);
  1729         public void visitWhileLoop(JCWhileLoop tree) {
  1730             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1731             FlowKind prevFlowKind = flowKind;
  1732             flowKind = FlowKind.NORMAL;
  1733             Bits initsSkip = null;
  1734             Bits uninitsSkip = null;
  1735             pendingExits = new ListBuffer<AssignPendingExit>();
  1736             int prevErrors = log.nerrors;
  1737             Bits uninitsEntry = uninits.dup();
  1738             uninitsEntry.excludeFrom(nextadr);
  1739             do {
  1740                 scanCond(tree.cond);
  1741                 if (!flowKind.isFinal()) {
  1742                     initsSkip = initsWhenFalse;
  1743                     uninitsSkip = uninitsWhenFalse;
  1745                 inits = initsWhenTrue;
  1746                 uninits = uninitsWhenTrue;
  1747                 scan(tree.body);
  1748                 resolveContinues(tree);
  1749                 if (log.nerrors != prevErrors ||
  1750                     flowKind.isFinal() ||
  1751                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1752                     break;
  1753                 uninits = uninitsEntry.andSet(uninits);
  1754                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1755             } while (true);
  1756             flowKind = prevFlowKind;
  1757             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
  1758             //branch is not taken AND if it's DA/DU before any break statement
  1759             inits = initsSkip;
  1760             uninits = uninitsSkip;
  1761             resolveBreaks(tree, prevPendingExits);
  1764         public void visitForLoop(JCForLoop tree) {
  1765             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1766             FlowKind prevFlowKind = flowKind;
  1767             flowKind = FlowKind.NORMAL;
  1768             int nextadrPrev = nextadr;
  1769             scan(tree.init);
  1770             Bits initsSkip = null;
  1771             Bits uninitsSkip = null;
  1772             pendingExits = new ListBuffer<AssignPendingExit>();
  1773             int prevErrors = log.nerrors;
  1774             do {
  1775                 Bits uninitsEntry = uninits.dup();
  1776                 uninitsEntry.excludeFrom(nextadr);
  1777                 if (tree.cond != null) {
  1778                     scanCond(tree.cond);
  1779                     if (!flowKind.isFinal()) {
  1780                         initsSkip = initsWhenFalse;
  1781                         uninitsSkip = uninitsWhenFalse;
  1783                     inits = initsWhenTrue;
  1784                     uninits = uninitsWhenTrue;
  1785                 } else if (!flowKind.isFinal()) {
  1786                     initsSkip = inits.dup();
  1787                     initsSkip.inclRange(firstadr, nextadr);
  1788                     uninitsSkip = uninits.dup();
  1789                     uninitsSkip.inclRange(firstadr, nextadr);
  1791                 scan(tree.body);
  1792                 resolveContinues(tree);
  1793                 scan(tree.step);
  1794                 if (log.nerrors != prevErrors ||
  1795                     flowKind.isFinal() ||
  1796                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1797                     break;
  1798                 uninits = uninitsEntry.andSet(uninits);
  1799                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1800             } while (true);
  1801             flowKind = prevFlowKind;
  1802             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
  1803             //branch is not taken AND if it's DA/DU before any break statement
  1804             inits = initsSkip;
  1805             uninits = uninitsSkip;
  1806             resolveBreaks(tree, prevPendingExits);
  1807             nextadr = nextadrPrev;
  1810         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1811             visitVarDef(tree.var);
  1813             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1814             FlowKind prevFlowKind = flowKind;
  1815             flowKind = FlowKind.NORMAL;
  1816             int nextadrPrev = nextadr;
  1817             scan(tree.expr);
  1818             Bits initsStart = inits.dup();
  1819             Bits uninitsStart = uninits.dup();
  1821             letInit(tree.pos(), tree.var.sym);
  1822             pendingExits = new ListBuffer<AssignPendingExit>();
  1823             int prevErrors = log.nerrors;
  1824             do {
  1825                 Bits uninitsEntry = uninits.dup();
  1826                 uninitsEntry.excludeFrom(nextadr);
  1827                 scan(tree.body);
  1828                 resolveContinues(tree);
  1829                 if (log.nerrors != prevErrors ||
  1830                     flowKind.isFinal() ||
  1831                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1832                     break;
  1833                 uninits = uninitsEntry.andSet(uninits);
  1834                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1835             } while (true);
  1836             flowKind = prevFlowKind;
  1837             inits = initsStart;
  1838             uninits = uninitsStart.andSet(uninits);
  1839             resolveBreaks(tree, prevPendingExits);
  1840             nextadr = nextadrPrev;
  1843         public void visitLabelled(JCLabeledStatement tree) {
  1844             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1845             pendingExits = new ListBuffer<AssignPendingExit>();
  1846             scan(tree.body);
  1847             resolveBreaks(tree, prevPendingExits);
  1850         public void visitSwitch(JCSwitch tree) {
  1851             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1852             pendingExits = new ListBuffer<AssignPendingExit>();
  1853             int nextadrPrev = nextadr;
  1854             scanExpr(tree.selector);
  1855             Bits initsSwitch = inits;
  1856             Bits uninitsSwitch = uninits.dup();
  1857             boolean hasDefault = false;
  1858             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1859                 inits = initsSwitch.dup();
  1860                 uninits = uninits.andSet(uninitsSwitch);
  1861                 JCCase c = l.head;
  1862                 if (c.pat == null)
  1863                     hasDefault = true;
  1864                 else
  1865                     scanExpr(c.pat);
  1866                 scan(c.stats);
  1867                 addVars(c.stats, initsSwitch, uninitsSwitch);
  1868                 // Warn about fall-through if lint switch fallthrough enabled.
  1870             if (!hasDefault) {
  1871                 inits.andSet(initsSwitch);
  1873             resolveBreaks(tree, prevPendingExits);
  1874             nextadr = nextadrPrev;
  1876         // where
  1877             /** Add any variables defined in stats to inits and uninits. */
  1878             private void addVars(List<JCStatement> stats, Bits inits,
  1879                                         Bits uninits) {
  1880                 for (;stats.nonEmpty(); stats = stats.tail) {
  1881                     JCTree stat = stats.head;
  1882                     if (stat.hasTag(VARDEF)) {
  1883                         int adr = ((JCVariableDecl) stat).sym.adr;
  1884                         inits.excl(adr);
  1885                         uninits.incl(adr);
  1890         public void visitTry(JCTry tree) {
  1891             ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
  1892             Bits uninitsTryPrev = uninitsTry;
  1893             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1894             pendingExits = new ListBuffer<AssignPendingExit>();
  1895             Bits initsTry = inits.dup();
  1896             uninitsTry = uninits.dup();
  1897             for (JCTree resource : tree.resources) {
  1898                 if (resource instanceof JCVariableDecl) {
  1899                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1900                     visitVarDef(vdecl);
  1901                     unrefdResources.enter(vdecl.sym);
  1902                     resourceVarDecls.append(vdecl);
  1903                 } else if (resource instanceof JCExpression) {
  1904                     scanExpr((JCExpression) resource);
  1905                 } else {
  1906                     throw new AssertionError(tree);  // parser error
  1909             scan(tree.body);
  1910             uninitsTry.andSet(uninits);
  1911             Bits initsEnd = inits;
  1912             Bits uninitsEnd = uninits;
  1913             int nextadrCatch = nextadr;
  1915             if (!resourceVarDecls.isEmpty() &&
  1916                     lint.isEnabled(Lint.LintCategory.TRY)) {
  1917                 for (JCVariableDecl resVar : resourceVarDecls) {
  1918                     if (unrefdResources.includes(resVar.sym)) {
  1919                         log.warning(Lint.LintCategory.TRY, resVar.pos(),
  1920                                     "try.resource.not.referenced", resVar.sym);
  1921                         unrefdResources.remove(resVar.sym);
  1926             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1927                 JCVariableDecl param = l.head.param;
  1928                 inits = initsTry.dup();
  1929                 uninits = uninitsTry.dup();
  1930                 scan(param);
  1931                 inits.incl(param.sym.adr);
  1932                 uninits.excl(param.sym.adr);
  1933                 scan(l.head.body);
  1934                 initsEnd.andSet(inits);
  1935                 uninitsEnd.andSet(uninits);
  1936                 nextadr = nextadrCatch;
  1938             if (tree.finalizer != null) {
  1939                 inits = initsTry.dup();
  1940                 uninits = uninitsTry.dup();
  1941                 ListBuffer<AssignPendingExit> exits = pendingExits;
  1942                 pendingExits = prevPendingExits;
  1943                 scan(tree.finalizer);
  1944                 if (!tree.finallyCanCompleteNormally) {
  1945                     // discard exits and exceptions from try and finally
  1946                 } else {
  1947                     uninits.andSet(uninitsEnd);
  1948                     // FIX: this doesn't preserve source order of exits in catch
  1949                     // versus finally!
  1950                     while (exits.nonEmpty()) {
  1951                         AssignPendingExit exit = exits.next();
  1952                         if (exit.exit_inits != null) {
  1953                             exit.exit_inits.orSet(inits);
  1954                             exit.exit_uninits.andSet(uninits);
  1956                         pendingExits.append(exit);
  1958                     inits.orSet(initsEnd);
  1960             } else {
  1961                 inits = initsEnd;
  1962                 uninits = uninitsEnd;
  1963                 ListBuffer<AssignPendingExit> exits = pendingExits;
  1964                 pendingExits = prevPendingExits;
  1965                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1967             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  1970         public void visitConditional(JCConditional tree) {
  1971             scanCond(tree.cond);
  1972             Bits initsBeforeElse = initsWhenFalse;
  1973             Bits uninitsBeforeElse = uninitsWhenFalse;
  1974             inits = initsWhenTrue;
  1975             uninits = uninitsWhenTrue;
  1976             if (tree.truepart.type.hasTag(BOOLEAN) &&
  1977                 tree.falsepart.type.hasTag(BOOLEAN)) {
  1978                 // if b and c are boolean valued, then
  1979                 // v is (un)assigned after a?b:c when true iff
  1980                 //    v is (un)assigned after b when true and
  1981                 //    v is (un)assigned after c when true
  1982                 scanCond(tree.truepart);
  1983                 Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
  1984                 Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
  1985                 Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
  1986                 Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
  1987                 inits = initsBeforeElse;
  1988                 uninits = uninitsBeforeElse;
  1989                 scanCond(tree.falsepart);
  1990                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
  1991                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
  1992                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
  1993                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
  1994             } else {
  1995                 scanExpr(tree.truepart);
  1996                 Bits initsAfterThen = inits.dup();
  1997                 Bits uninitsAfterThen = uninits.dup();
  1998                 inits = initsBeforeElse;
  1999                 uninits = uninitsBeforeElse;
  2000                 scanExpr(tree.falsepart);
  2001                 inits.andSet(initsAfterThen);
  2002                 uninits.andSet(uninitsAfterThen);
  2006         public void visitIf(JCIf tree) {
  2007             scanCond(tree.cond);
  2008             Bits initsBeforeElse = initsWhenFalse;
  2009             Bits uninitsBeforeElse = uninitsWhenFalse;
  2010             inits = initsWhenTrue;
  2011             uninits = uninitsWhenTrue;
  2012             scan(tree.thenpart);
  2013             if (tree.elsepart != null) {
  2014                 Bits initsAfterThen = inits.dup();
  2015                 Bits uninitsAfterThen = uninits.dup();
  2016                 inits = initsBeforeElse;
  2017                 uninits = uninitsBeforeElse;
  2018                 scan(tree.elsepart);
  2019                 inits.andSet(initsAfterThen);
  2020                 uninits.andSet(uninitsAfterThen);
  2021             } else {
  2022                 inits.andSet(initsBeforeElse);
  2023                 uninits.andSet(uninitsBeforeElse);
  2027         public void visitBreak(JCBreak tree) {
  2028             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2031         public void visitContinue(JCContinue tree) {
  2032             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2035         public void visitReturn(JCReturn tree) {
  2036             scanExpr(tree.expr);
  2037             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2040         public void visitThrow(JCThrow tree) {
  2041             scanExpr(tree.expr);
  2042             markDead();
  2045         public void visitApply(JCMethodInvocation tree) {
  2046             scanExpr(tree.meth);
  2047             scanExprs(tree.args);
  2050         public void visitNewClass(JCNewClass tree) {
  2051             scanExpr(tree.encl);
  2052             scanExprs(tree.args);
  2053             scan(tree.def);
  2056         @Override
  2057         public void visitLambda(JCLambda tree) {
  2058             Bits prevUninits = uninits;
  2059             Bits prevInits = inits;
  2060             int returnadrPrev = returnadr;
  2061             ListBuffer<AssignPendingExit> prevPending = pendingExits;
  2062             try {
  2063                 returnadr = nextadr;
  2064                 pendingExits = new ListBuffer<AssignPendingExit>();
  2065                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  2066                     JCVariableDecl def = l.head;
  2067                     scan(def);
  2068                     inits.incl(def.sym.adr);
  2069                     uninits.excl(def.sym.adr);
  2071                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
  2072                     scanExpr(tree.body);
  2073                 } else {
  2074                     scan(tree.body);
  2077             finally {
  2078                 returnadr = returnadrPrev;
  2079                 uninits = prevUninits;
  2080                 inits = prevInits;
  2081                 pendingExits = prevPending;
  2085         public void visitNewArray(JCNewArray tree) {
  2086             scanExprs(tree.dims);
  2087             scanExprs(tree.elems);
  2090         public void visitAssert(JCAssert tree) {
  2091             Bits initsExit = inits.dup();
  2092             Bits uninitsExit = uninits.dup();
  2093             scanCond(tree.cond);
  2094             uninitsExit.andSet(uninitsWhenTrue);
  2095             if (tree.detail != null) {
  2096                 inits = initsWhenFalse;
  2097                 uninits = uninitsWhenFalse;
  2098                 scanExpr(tree.detail);
  2100             inits = initsExit;
  2101             uninits = uninitsExit;
  2104         public void visitAssign(JCAssign tree) {
  2105             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2106             if (!(lhs instanceof JCIdent)) {
  2107                 scanExpr(lhs);
  2109             scanExpr(tree.rhs);
  2110             letInit(lhs);
  2113         public void visitAssignop(JCAssignOp tree) {
  2114             scanExpr(tree.lhs);
  2115             scanExpr(tree.rhs);
  2116             letInit(tree.lhs);
  2119         public void visitUnary(JCUnary tree) {
  2120             switch (tree.getTag()) {
  2121             case NOT:
  2122                 scanCond(tree.arg);
  2123                 Bits t = initsWhenFalse;
  2124                 initsWhenFalse = initsWhenTrue;
  2125                 initsWhenTrue = t;
  2126                 t = uninitsWhenFalse;
  2127                 uninitsWhenFalse = uninitsWhenTrue;
  2128                 uninitsWhenTrue = t;
  2129                 break;
  2130             case PREINC: case POSTINC:
  2131             case PREDEC: case POSTDEC:
  2132                 scanExpr(tree.arg);
  2133                 letInit(tree.arg);
  2134                 break;
  2135             default:
  2136                 scanExpr(tree.arg);
  2140         public void visitBinary(JCBinary tree) {
  2141             switch (tree.getTag()) {
  2142             case AND:
  2143                 scanCond(tree.lhs);
  2144                 Bits initsWhenFalseLeft = initsWhenFalse;
  2145                 Bits uninitsWhenFalseLeft = uninitsWhenFalse;
  2146                 inits = initsWhenTrue;
  2147                 uninits = uninitsWhenTrue;
  2148                 scanCond(tree.rhs);
  2149                 initsWhenFalse.andSet(initsWhenFalseLeft);
  2150                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
  2151                 break;
  2152             case OR:
  2153                 scanCond(tree.lhs);
  2154                 Bits initsWhenTrueLeft = initsWhenTrue;
  2155                 Bits uninitsWhenTrueLeft = uninitsWhenTrue;
  2156                 inits = initsWhenFalse;
  2157                 uninits = uninitsWhenFalse;
  2158                 scanCond(tree.rhs);
  2159                 initsWhenTrue.andSet(initsWhenTrueLeft);
  2160                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
  2161                 break;
  2162             default:
  2163                 scanExpr(tree.lhs);
  2164                 scanExpr(tree.rhs);
  2168         public void visitIdent(JCIdent tree) {
  2169             if (tree.sym.kind == VAR) {
  2170                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2171                 referenced(tree.sym);
  2175         void referenced(Symbol sym) {
  2176             unrefdResources.remove(sym);
  2179         public void visitAnnotatedType(JCAnnotatedType tree) {
  2180             // annotations don't get scanned
  2181             tree.underlyingType.accept(this);
  2184         public void visitTopLevel(JCCompilationUnit tree) {
  2185             // Do nothing for TopLevel since each class is visited individually
  2188     /**************************************************************************
  2189      * main method
  2190      *************************************************************************/
  2192         /** Perform definite assignment/unassignment analysis on a tree.
  2193          */
  2194         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2195             analyzeTree(env, env.tree, make);
  2198         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2199             try {
  2200                 attrEnv = env;
  2201                 Flow.this.make = make;
  2202                 startPos = tree.pos().getStartPosition();
  2203                 inits = new Bits();
  2204                 uninits = new Bits();
  2205                 uninitsTry = new Bits();
  2206                 initsWhenTrue = initsWhenFalse =
  2207                     uninitsWhenTrue = uninitsWhenFalse = null;
  2208                 if (vars == null)
  2209                     vars = new VarSymbol[32];
  2210                 else
  2211                     for (int i=0; i<vars.length; i++)
  2212                         vars[i] = null;
  2213                 firstadr = 0;
  2214                 nextadr = 0;
  2215                 pendingExits = new ListBuffer<AssignPendingExit>();
  2216                 this.classDef = null;
  2217                 unrefdResources = new Scope(env.enclClass.sym);
  2218                 scan(tree);
  2219             } finally {
  2220                 // note that recursive invocations of this method fail hard
  2221                 startPos = -1;
  2222                 inits = uninits = uninitsTry = null;
  2223                 initsWhenTrue = initsWhenFalse =
  2224                     uninitsWhenTrue = uninitsWhenFalse = null;
  2225                 if (vars != null) for (int i=0; i<vars.length; i++)
  2226                     vars[i] = null;
  2227                 firstadr = 0;
  2228                 nextadr = 0;
  2229                 pendingExits = null;
  2230                 Flow.this.make = null;
  2231                 this.classDef = null;
  2232                 unrefdResources = null;
  2237     /**
  2238      * This pass implements the last step of the dataflow analysis, namely
  2239      * the effectively-final analysis check. This checks that every local variable
  2240      * reference from a lambda body/local inner class is either final or effectively final.
  2241      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2242      * AssignAnalyzer.
  2243      */
  2244     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
  2246         JCTree currentTree; //local class or lambda
  2248         @Override
  2249         void markDead() {
  2250             //do nothing
  2253         @SuppressWarnings("fallthrough")
  2254         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
  2255             if (currentTree != null &&
  2256                     sym.owner.kind == MTH &&
  2257                     sym.pos < currentTree.getStartPosition()) {
  2258                 switch (currentTree.getTag()) {
  2259                     case CLASSDEF:
  2260                         if (!allowEffectivelyFinalInInnerClasses) {
  2261                             if ((sym.flags() & FINAL) == 0) {
  2262                                 reportInnerClsNeedsFinalError(pos, sym);
  2264                             break;
  2266                     case LAMBDA:
  2267                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
  2268                            reportEffectivelyFinalError(pos, sym);
  2274         @SuppressWarnings("fallthrough")
  2275         void letInit(JCTree tree) {
  2276             tree = TreeInfo.skipParens(tree);
  2277             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  2278                 Symbol sym = TreeInfo.symbol(tree);
  2279                 if (currentTree != null &&
  2280                         sym.kind == VAR &&
  2281                         sym.owner.kind == MTH &&
  2282                         ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
  2283                     switch (currentTree.getTag()) {
  2284                         case CLASSDEF:
  2285                             if (!allowEffectivelyFinalInInnerClasses) {
  2286                                 reportInnerClsNeedsFinalError(tree, sym);
  2287                                 break;
  2289                         case LAMBDA:
  2290                             reportEffectivelyFinalError(tree, sym);
  2296         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
  2297             String subKey = currentTree.hasTag(LAMBDA) ?
  2298                   "lambda"  : "inner.cls";
  2299             log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
  2302         void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
  2303             log.error(pos,
  2304                     "local.var.accessed.from.icls.needs.final",
  2305                     sym);
  2308     /*************************************************************************
  2309      * Visitor methods for statements and definitions
  2310      *************************************************************************/
  2312         /* ------------ Visitor methods for various sorts of trees -------------*/
  2314         public void visitClassDef(JCClassDecl tree) {
  2315             JCTree prevTree = currentTree;
  2316             try {
  2317                 currentTree = tree.sym.isLocal() ? tree : null;
  2318                 super.visitClassDef(tree);
  2319             } finally {
  2320                 currentTree = prevTree;
  2324         @Override
  2325         public void visitLambda(JCLambda tree) {
  2326             JCTree prevTree = currentTree;
  2327             try {
  2328                 currentTree = tree;
  2329                 super.visitLambda(tree);
  2330             } finally {
  2331                 currentTree = prevTree;
  2335         @Override
  2336         public void visitIdent(JCIdent tree) {
  2337             if (tree.sym.kind == VAR) {
  2338                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
  2342         public void visitAssign(JCAssign tree) {
  2343             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2344             if (!(lhs instanceof JCIdent)) {
  2345                 scan(lhs);
  2347             scan(tree.rhs);
  2348             letInit(lhs);
  2351         public void visitAssignop(JCAssignOp tree) {
  2352             scan(tree.lhs);
  2353             scan(tree.rhs);
  2354             letInit(tree.lhs);
  2357         public void visitUnary(JCUnary tree) {
  2358             switch (tree.getTag()) {
  2359                 case PREINC: case POSTINC:
  2360                 case PREDEC: case POSTDEC:
  2361                     scan(tree.arg);
  2362                     letInit(tree.arg);
  2363                     break;
  2364                 default:
  2365                     scan(tree.arg);
  2369         public void visitTopLevel(JCCompilationUnit tree) {
  2370             // Do nothing for TopLevel since each class is visited individually
  2373     /**************************************************************************
  2374      * main method
  2375      *************************************************************************/
  2377         /** Perform definite assignment/unassignment analysis on a tree.
  2378          */
  2379         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2380             analyzeTree(env, env.tree, make);
  2382         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2383             try {
  2384                 attrEnv = env;
  2385                 Flow.this.make = make;
  2386                 pendingExits = new ListBuffer<PendingExit>();
  2387                 scan(tree);
  2388             } finally {
  2389                 pendingExits = null;
  2390                 Flow.this.make = null;

mercurial