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

Fri, 05 Oct 2012 14:35:24 +0100

author
mcimadamore
date
Fri, 05 Oct 2012 14:35:24 +0100
changeset 1348
573ceb23beeb
parent 1339
0e5899f09dab
child 1358
fc123bdeddb8
permissions
-rw-r--r--

7177385: Add attribution support for lambda expressions
Summary: Add support for function descriptor lookup, functional interface inference and lambda expression type-checking
Reviewed-by: jjg, dlsmith

     1 /*
     2  * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 //todo: one might eliminate uninits.andSets when monotonic
    28 package com.sun.tools.javac.comp;
    30 import java.util.HashMap;
    32 import com.sun.tools.javac.code.*;
    33 import com.sun.tools.javac.tree.*;
    34 import com.sun.tools.javac.util.*;
    35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    37 import com.sun.tools.javac.code.Symbol.*;
    38 import com.sun.tools.javac.tree.JCTree.*;
    40 import static com.sun.tools.javac.code.Flags.*;
    41 import static com.sun.tools.javac.code.Flags.BLOCK;
    42 import static com.sun.tools.javac.code.Kinds.*;
    43 import static com.sun.tools.javac.code.TypeTags.*;
    44 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    46 /** This pass implements dataflow analysis for Java programs though
    47  *  different AST visitor steps. Liveness analysis (see AliveAlanyzer) checks that
    48  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
    49  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
    50  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
    51  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
    52  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
    53  *  determines that local variables accessed within the scope of an inner class/lambda
    54  *  are either final or effectively-final.
    55  *
    56  *  <p>The JLS has a number of problems in the
    57  *  specification of these flow analysis problems. This implementation
    58  *  attempts to address those issues.
    59  *
    60  *  <p>First, there is no accommodation for a finally clause that cannot
    61  *  complete normally. For liveness analysis, an intervening finally
    62  *  clause can cause a break, continue, or return not to reach its
    63  *  target.  For exception analysis, an intervening finally clause can
    64  *  cause any exception to be "caught".  For DA/DU analysis, the finally
    65  *  clause can prevent a transfer of control from propagating DA/DU
    66  *  state to the target.  In addition, code in the finally clause can
    67  *  affect the DA/DU status of variables.
    68  *
    69  *  <p>For try statements, we introduce the idea of a variable being
    70  *  definitely unassigned "everywhere" in a block.  A variable V is
    71  *  "unassigned everywhere" in a block iff it is unassigned at the
    72  *  beginning of the block and there is no reachable assignment to V
    73  *  in the block.  An assignment V=e is reachable iff V is not DA
    74  *  after e.  Then we can say that V is DU at the beginning of the
    75  *  catch block iff V is DU everywhere in the try block.  Similarly, V
    76  *  is DU at the beginning of the finally block iff V is DU everywhere
    77  *  in the try block and in every catch block.  Specifically, the
    78  *  following bullet is added to 16.2.2
    79  *  <pre>
    80  *      V is <em>unassigned everywhere</em> in a block if it is
    81  *      unassigned before the block and there is no reachable
    82  *      assignment to V within the block.
    83  *  </pre>
    84  *  <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all
    85  *  try blocks is changed to
    86  *  <pre>
    87  *      V is definitely unassigned before a catch block iff V is
    88  *      definitely unassigned everywhere in the try block.
    89  *  </pre>
    90  *  <p>The last bullet (and all of its sub-bullets) for try blocks that
    91  *  have a finally block is changed to
    92  *  <pre>
    93  *      V is definitely unassigned before the finally block iff
    94  *      V is definitely unassigned everywhere in the try block
    95  *      and everywhere in each catch block of the try statement.
    96  *  </pre>
    97  *  <p>In addition,
    98  *  <pre>
    99  *      V is definitely assigned at the end of a constructor iff
   100  *      V is definitely assigned after the block that is the body
   101  *      of the constructor and V is definitely assigned at every
   102  *      return that can return from the constructor.
   103  *  </pre>
   104  *  <p>In addition, each continue statement with the loop as its target
   105  *  is treated as a jump to the end of the loop body, and "intervening"
   106  *  finally clauses are treated as follows: V is DA "due to the
   107  *  continue" iff V is DA before the continue statement or V is DA at
   108  *  the end of any intervening finally block.  V is DU "due to the
   109  *  continue" iff any intervening finally cannot complete normally or V
   110  *  is DU at the end of every intervening finally block.  This "due to
   111  *  the continue" concept is then used in the spec for the loops.
   112  *
   113  *  <p>Similarly, break statements must consider intervening finally
   114  *  blocks.  For liveness analysis, a break statement for which any
   115  *  intervening finally cannot complete normally is not considered to
   116  *  cause the target statement to be able to complete normally. Then
   117  *  we say V is DA "due to the break" iff V is DA before the break or
   118  *  V is DA at the end of any intervening finally block.  V is DU "due
   119  *  to the break" iff any intervening finally cannot complete normally
   120  *  or V is DU at the break and at the end of every intervening
   121  *  finally block.  (I suspect this latter condition can be
   122  *  simplified.)  This "due to the break" is then used in the spec for
   123  *  all statements that can be "broken".
   124  *
   125  *  <p>The return statement is treated similarly.  V is DA "due to a
   126  *  return statement" iff V is DA before the return statement or V is
   127  *  DA at the end of any intervening finally block.  Note that we
   128  *  don't have to worry about the return expression because this
   129  *  concept is only used for construcrors.
   130  *
   131  *  <p>There is no spec in the JLS for when a variable is definitely
   132  *  assigned at the end of a constructor, which is needed for final
   133  *  fields (8.3.1.2).  We implement the rule that V is DA at the end
   134  *  of the constructor iff it is DA and the end of the body of the
   135  *  constructor and V is DA "due to" every return of the constructor.
   136  *
   137  *  <p>Intervening finally blocks similarly affect exception analysis.  An
   138  *  intervening finally that cannot complete normally allows us to ignore
   139  *  an otherwise uncaught exception.
   140  *
   141  *  <p>To implement the semantics of intervening finally clauses, all
   142  *  nonlocal transfers (break, continue, return, throw, method call that
   143  *  can throw a checked exception, and a constructor invocation that can
   144  *  thrown a checked exception) are recorded in a queue, and removed
   145  *  from the queue when we complete processing the target of the
   146  *  nonlocal transfer.  This allows us to modify the queue in accordance
   147  *  with the above rules when we encounter a finally clause.  The only
   148  *  exception to this [no pun intended] is that checked exceptions that
   149  *  are known to be caught or declared to be caught in the enclosing
   150  *  method are not recorded in the queue, but instead are recorded in a
   151  *  global variable "Set<Type> thrown" that records the type of all
   152  *  exceptions that can be thrown.
   153  *
   154  *  <p>Other minor issues the treatment of members of other classes
   155  *  (always considered DA except that within an anonymous class
   156  *  constructor, where DA status from the enclosing scope is
   157  *  preserved), treatment of the case expression (V is DA before the
   158  *  case expression iff V is DA after the switch expression),
   159  *  treatment of variables declared in a switch block (the implied
   160  *  DA/DU status after the switch expression is DU and not DA for
   161  *  variables defined in a switch block), the treatment of boolean ?:
   162  *  expressions (The JLS rules only handle b and c non-boolean; the
   163  *  new rule is that if b and c are boolean valued, then V is
   164  *  (un)assigned after a?b:c when true/false iff V is (un)assigned
   165  *  after b when true/false and V is (un)assigned after c when
   166  *  true/false).
   167  *
   168  *  <p>There is the remaining question of what syntactic forms constitute a
   169  *  reference to a variable.  It is conventional to allow this.x on the
   170  *  left-hand-side to initialize a final instance field named x, yet
   171  *  this.x isn't considered a "use" when appearing on a right-hand-side
   172  *  in most implementations.  Should parentheses affect what is
   173  *  considered a variable reference?  The simplest rule would be to
   174  *  allow unqualified forms only, parentheses optional, and phase out
   175  *  support for assigning to a final field via this.x.
   176  *
   177  *  <p><b>This is NOT part of any supported API.
   178  *  If you write code that depends on this, you do so at your own risk.
   179  *  This code and its internal interfaces are subject to change or
   180  *  deletion without notice.</b>
   181  */
   182 public class Flow {
   183     protected static final Context.Key<Flow> flowKey =
   184         new Context.Key<Flow>();
   186     private final Names names;
   187     private final Log log;
   188     private final Symtab syms;
   189     private final Types types;
   190     private final Check chk;
   191     private       TreeMaker make;
   192     private final Resolve rs;
   193     private final JCDiagnostic.Factory diags;
   194     private Env<AttrContext> attrEnv;
   195     private       Lint lint;
   196     private final boolean allowImprovedRethrowAnalysis;
   197     private final boolean allowImprovedCatchAnalysis;
   198     private final boolean allowEffectivelyFinalInInnerClasses;
   200     public static Flow instance(Context context) {
   201         Flow instance = context.get(flowKey);
   202         if (instance == null)
   203             instance = new Flow(context);
   204         return instance;
   205     }
   207     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   208         new AliveAnalyzer().analyzeTree(env, make);
   209         new AssignAnalyzer().analyzeTree(env, make);
   210         new FlowAnalyzer().analyzeTree(env, make);
   211         new CaptureAnalyzer().analyzeTree(env, make);
   212     }
   214     public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
   215         java.util.Queue<JCDiagnostic> prevDeferredDiagnostics = log.deferredDiagnostics;
   216         Filter<JCDiagnostic> prevDeferDiagsFilter = log.deferredDiagFilter;
   217         //we need to disable diagnostics temporarily; the problem is that if
   218         //a lambda expression contains e.g. an unreachable statement, an error
   219         //message will be reported and will cause compilation to skip the flow analyis
   220         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
   221         //related errors, which will allow for more errors to be detected
   222         if (!speculative) {
   223             log.deferAll();
   224             log.deferredDiagnostics = ListBuffer.lb();
   225         }
   226         try {
   227             new AliveAnalyzer().analyzeTree(env, that, make);
   228             new FlowAnalyzer().analyzeTree(env, that, make);
   229         } finally {
   230             if (!speculative) {
   231                 log.deferredDiagFilter = prevDeferDiagsFilter;
   232                 log.deferredDiagnostics = prevDeferredDiagnostics;
   233             }
   234         }
   235     }
   237     /**
   238      * Definite assignment scan mode
   239      */
   240     enum FlowKind {
   241         /**
   242          * This is the normal DA/DU analysis mode
   243          */
   244         NORMAL("var.might.already.be.assigned", false),
   245         /**
   246          * This is the speculative DA/DU analysis mode used to speculatively
   247          * derive assertions within loop bodies
   248          */
   249         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
   251         String errKey;
   252         boolean isFinal;
   254         FlowKind(String errKey, boolean isFinal) {
   255             this.errKey = errKey;
   256             this.isFinal = isFinal;
   257         }
   259         boolean isFinal() {
   260             return isFinal;
   261         }
   262     }
   264     protected Flow(Context context) {
   265         context.put(flowKey, this);
   266         names = Names.instance(context);
   267         log = Log.instance(context);
   268         syms = Symtab.instance(context);
   269         types = Types.instance(context);
   270         chk = Check.instance(context);
   271         lint = Lint.instance(context);
   272         rs = Resolve.instance(context);
   273         diags = JCDiagnostic.Factory.instance(context);
   274         Source source = Source.instance(context);
   275         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   276         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   277         Options options = Options.instance(context);
   278         allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses() &&
   279                 options.isSet("allowEffectivelyFinalInInnerClasses"); //pre-lambda guard
   280     }
   282     /**
   283      * Base visitor class for all visitors implementing dataflow analysis logic.
   284      * This class define the shared logic for handling jumps (break/continue statements).
   285      */
   286     static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
   288         enum JumpKind {
   289             BREAK(JCTree.Tag.BREAK) {
   290                 @Override
   291                 JCTree getTarget(JCTree tree) {
   292                     return ((JCBreak)tree).target;
   293                 }
   294             },
   295             CONTINUE(JCTree.Tag.CONTINUE) {
   296                 @Override
   297                 JCTree getTarget(JCTree tree) {
   298                     return ((JCContinue)tree).target;
   299                 }
   300             };
   302             JCTree.Tag treeTag;
   304             private JumpKind(Tag treeTag) {
   305                 this.treeTag = treeTag;
   306             }
   308             abstract JCTree getTarget(JCTree tree);
   309         }
   311         /** The currently pending exits that go from current inner blocks
   312          *  to an enclosing block, in source order.
   313          */
   314         ListBuffer<P> pendingExits;
   316         /** A pending exit.  These are the statements return, break, and
   317          *  continue.  In addition, exception-throwing expressions or
   318          *  statements are put here when not known to be caught.  This
   319          *  will typically result in an error unless it is within a
   320          *  try-finally whose finally block cannot complete normally.
   321          */
   322         static class PendingExit {
   323             JCTree tree;
   325             PendingExit(JCTree tree) {
   326                 this.tree = tree;
   327             }
   329             void resolveJump() {
   330                 //do nothing
   331             }
   332         }
   334         abstract void markDead();
   336         /** Record an outward transfer of control. */
   337         void recordExit(JCTree tree, P pe) {
   338             pendingExits.append(pe);
   339             markDead();
   340         }
   342         /** Resolve all jumps of this statement. */
   343         private boolean resolveJump(JCTree tree,
   344                         ListBuffer<P> oldPendingExits,
   345                         JumpKind jk) {
   346             boolean resolved = false;
   347             List<P> exits = pendingExits.toList();
   348             pendingExits = oldPendingExits;
   349             for (; exits.nonEmpty(); exits = exits.tail) {
   350                 P exit = exits.head;
   351                 if (exit.tree.hasTag(jk.treeTag) &&
   352                         jk.getTarget(exit.tree) == tree) {
   353                     exit.resolveJump();
   354                     resolved = true;
   355                 } else {
   356                     pendingExits.append(exit);
   357                 }
   358             }
   359             return resolved;
   360         }
   362         /** Resolve all breaks of this statement. */
   363         boolean resolveContinues(JCTree tree) {
   364             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
   365         }
   367         /** Resolve all continues of this statement. */
   368         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
   369             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   370         }
   371     }
   373     /**
   374      * This pass implements the first step of the dataflow analysis, namely
   375      * the liveness analysis check. This checks that every statement is reachable.
   376      * The output of this analysis pass are used by other analyzers. This analyzer
   377      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   378      */
   379     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
   381         /** A flag that indicates whether the last statement could
   382          *  complete normally.
   383          */
   384         private boolean alive;
   386         @Override
   387         void markDead() {
   388             alive = false;
   389         }
   391     /*************************************************************************
   392      * Visitor methods for statements and definitions
   393      *************************************************************************/
   395         /** Analyze a definition.
   396          */
   397         void scanDef(JCTree tree) {
   398             scanStat(tree);
   399             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
   400                 log.error(tree.pos(),
   401                           "initializer.must.be.able.to.complete.normally");
   402             }
   403         }
   405         /** Analyze a statement. Check that statement is reachable.
   406          */
   407         void scanStat(JCTree tree) {
   408             if (!alive && tree != null) {
   409                 log.error(tree.pos(), "unreachable.stmt");
   410                 if (!tree.hasTag(SKIP)) alive = true;
   411             }
   412             scan(tree);
   413         }
   415         /** Analyze list of statements.
   416          */
   417         void scanStats(List<? extends JCStatement> trees) {
   418             if (trees != null)
   419                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
   420                     scanStat(l.head);
   421         }
   423         /* ------------ Visitor methods for various sorts of trees -------------*/
   425         public void visitClassDef(JCClassDecl tree) {
   426             if (tree.sym == null) return;
   427             boolean alivePrev = alive;
   428             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   429             Lint lintPrev = lint;
   431             pendingExits = new ListBuffer<PendingExit>();
   432             lint = lint.augment(tree.sym.annotations);
   434             try {
   435                 // process all the static initializers
   436                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   437                     if (!l.head.hasTag(METHODDEF) &&
   438                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   439                         scanDef(l.head);
   440                     }
   441                 }
   443                 // process all the instance initializers
   444                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   445                     if (!l.head.hasTag(METHODDEF) &&
   446                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   447                         scanDef(l.head);
   448                     }
   449                 }
   451                 // process all the methods
   452                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   453                     if (l.head.hasTag(METHODDEF)) {
   454                         scan(l.head);
   455                     }
   456                 }
   457             } finally {
   458                 pendingExits = pendingExitsPrev;
   459                 alive = alivePrev;
   460                 lint = lintPrev;
   461             }
   462         }
   464         public void visitMethodDef(JCMethodDecl tree) {
   465             if (tree.body == null) return;
   466             Lint lintPrev = lint;
   468             lint = lint.augment(tree.sym.annotations);
   470             Assert.check(pendingExits.isEmpty());
   472             try {
   473                 alive = true;
   474                 scanStat(tree.body);
   476                 if (alive && tree.sym.type.getReturnType().tag != VOID)
   477                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   479                 List<PendingExit> exits = pendingExits.toList();
   480                 pendingExits = new ListBuffer<PendingExit>();
   481                 while (exits.nonEmpty()) {
   482                     PendingExit exit = exits.head;
   483                     exits = exits.tail;
   484                     Assert.check(exit.tree.hasTag(RETURN));
   485                 }
   486             } finally {
   487                 lint = lintPrev;
   488             }
   489         }
   491         public void visitVarDef(JCVariableDecl tree) {
   492             if (tree.init != null) {
   493                 Lint lintPrev = lint;
   494                 lint = lint.augment(tree.sym.annotations);
   495                 try{
   496                     scan(tree.init);
   497                 } finally {
   498                     lint = lintPrev;
   499                 }
   500             }
   501         }
   503         public void visitBlock(JCBlock tree) {
   504             scanStats(tree.stats);
   505         }
   507         public void visitDoLoop(JCDoWhileLoop tree) {
   508             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   509             pendingExits = new ListBuffer<PendingExit>();
   510             scanStat(tree.body);
   511             alive |= resolveContinues(tree);
   512             scan(tree.cond);
   513             alive = alive && !tree.cond.type.isTrue();
   514             alive |= resolveBreaks(tree, prevPendingExits);
   515         }
   517         public void visitWhileLoop(JCWhileLoop tree) {
   518             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   519             pendingExits = new ListBuffer<PendingExit>();
   520             scan(tree.cond);
   521             alive = !tree.cond.type.isFalse();
   522             scanStat(tree.body);
   523             alive |= resolveContinues(tree);
   524             alive = resolveBreaks(tree, prevPendingExits) ||
   525                 !tree.cond.type.isTrue();
   526         }
   528         public void visitForLoop(JCForLoop tree) {
   529             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   530             scanStats(tree.init);
   531             pendingExits = new ListBuffer<PendingExit>();
   532             if (tree.cond != null) {
   533                 scan(tree.cond);
   534                 alive = !tree.cond.type.isFalse();
   535             } else {
   536                 alive = true;
   537             }
   538             scanStat(tree.body);
   539             alive |= resolveContinues(tree);
   540             scan(tree.step);
   541             alive = resolveBreaks(tree, prevPendingExits) ||
   542                 tree.cond != null && !tree.cond.type.isTrue();
   543         }
   545         public void visitForeachLoop(JCEnhancedForLoop tree) {
   546             visitVarDef(tree.var);
   547             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   548             scan(tree.expr);
   549             pendingExits = new ListBuffer<PendingExit>();
   550             scanStat(tree.body);
   551             alive |= resolveContinues(tree);
   552             resolveBreaks(tree, prevPendingExits);
   553             alive = true;
   554         }
   556         public void visitLabelled(JCLabeledStatement tree) {
   557             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   558             pendingExits = new ListBuffer<PendingExit>();
   559             scanStat(tree.body);
   560             alive |= resolveBreaks(tree, prevPendingExits);
   561         }
   563         public void visitSwitch(JCSwitch tree) {
   564             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   565             pendingExits = new ListBuffer<PendingExit>();
   566             scan(tree.selector);
   567             boolean hasDefault = false;
   568             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   569                 alive = true;
   570                 JCCase c = l.head;
   571                 if (c.pat == null)
   572                     hasDefault = true;
   573                 else
   574                     scan(c.pat);
   575                 scanStats(c.stats);
   576                 // Warn about fall-through if lint switch fallthrough enabled.
   577                 if (alive &&
   578                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   579                     c.stats.nonEmpty() && l.tail.nonEmpty())
   580                     log.warning(Lint.LintCategory.FALLTHROUGH,
   581                                 l.tail.head.pos(),
   582                                 "possible.fall-through.into.case");
   583             }
   584             if (!hasDefault) {
   585                 alive = true;
   586             }
   587             alive |= resolveBreaks(tree, prevPendingExits);
   588         }
   590         public void visitTry(JCTry tree) {
   591             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   592             pendingExits = new ListBuffer<PendingExit>();
   593             for (JCTree resource : tree.resources) {
   594                 if (resource instanceof JCVariableDecl) {
   595                     JCVariableDecl vdecl = (JCVariableDecl) resource;
   596                     visitVarDef(vdecl);
   597                 } else if (resource instanceof JCExpression) {
   598                     scan((JCExpression) resource);
   599                 } else {
   600                     throw new AssertionError(tree);  // parser error
   601                 }
   602             }
   604             scanStat(tree.body);
   605             boolean aliveEnd = alive;
   607             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   608                 alive = true;
   609                 JCVariableDecl param = l.head.param;
   610                 scan(param);
   611                 scanStat(l.head.body);
   612                 aliveEnd |= alive;
   613             }
   614             if (tree.finalizer != null) {
   615                 ListBuffer<PendingExit> exits = pendingExits;
   616                 pendingExits = prevPendingExits;
   617                 alive = true;
   618                 scanStat(tree.finalizer);
   619                 tree.finallyCanCompleteNormally = alive;
   620                 if (!alive) {
   621                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
   622                         log.warning(Lint.LintCategory.FINALLY,
   623                                 TreeInfo.diagEndPos(tree.finalizer),
   624                                 "finally.cannot.complete");
   625                     }
   626                 } else {
   627                     while (exits.nonEmpty()) {
   628                         pendingExits.append(exits.next());
   629                     }
   630                     alive = aliveEnd;
   631                 }
   632             } else {
   633                 alive = aliveEnd;
   634                 ListBuffer<PendingExit> exits = pendingExits;
   635                 pendingExits = prevPendingExits;
   636                 while (exits.nonEmpty()) pendingExits.append(exits.next());
   637             }
   638         }
   640         @Override
   641         public void visitIf(JCIf tree) {
   642             scan(tree.cond);
   643             scanStat(tree.thenpart);
   644             if (tree.elsepart != null) {
   645                 boolean aliveAfterThen = alive;
   646                 alive = true;
   647                 scanStat(tree.elsepart);
   648                 alive = alive | aliveAfterThen;
   649             } else {
   650                 alive = true;
   651             }
   652         }
   654         public void visitBreak(JCBreak tree) {
   655             recordExit(tree, new PendingExit(tree));
   656         }
   658         public void visitContinue(JCContinue tree) {
   659             recordExit(tree, new PendingExit(tree));
   660         }
   662         public void visitReturn(JCReturn tree) {
   663             scan(tree.expr);
   664             recordExit(tree, new PendingExit(tree));
   665         }
   667         public void visitThrow(JCThrow tree) {
   668             scan(tree.expr);
   669             markDead();
   670         }
   672         public void visitApply(JCMethodInvocation tree) {
   673             scan(tree.meth);
   674             scan(tree.args);
   675         }
   677         public void visitNewClass(JCNewClass tree) {
   678             scan(tree.encl);
   679             scan(tree.args);
   680             if (tree.def != null) {
   681                 scan(tree.def);
   682             }
   683         }
   685         @Override
   686         public void visitLambda(JCLambda tree) {
   687             if (tree.type != null &&
   688                     tree.type.isErroneous()) {
   689                 return;
   690             }
   692             ListBuffer<PendingExit> prevPending = pendingExits;
   693             boolean prevAlive = alive;
   694             try {
   695                 pendingExits = ListBuffer.lb();
   696                 alive = true;
   697                 scanStat(tree.body);
   698                 tree.canCompleteNormally = alive;
   699             }
   700             finally {
   701                 pendingExits = prevPending;
   702                 alive = prevAlive;
   703             }
   704         }
   706         public void visitTopLevel(JCCompilationUnit tree) {
   707             // Do nothing for TopLevel since each class is visited individually
   708         }
   710     /**************************************************************************
   711      * main method
   712      *************************************************************************/
   714         /** Perform definite assignment/unassignment analysis on a tree.
   715          */
   716         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   717             analyzeTree(env, env.tree, make);
   718         }
   719         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
   720             try {
   721                 attrEnv = env;
   722                 Flow.this.make = make;
   723                 pendingExits = new ListBuffer<PendingExit>();
   724                 alive = true;
   725                 scan(env.tree);
   726             } finally {
   727                 pendingExits = null;
   728                 Flow.this.make = null;
   729             }
   730         }
   731     }
   733     /**
   734      * This pass implements the second step of the dataflow analysis, namely
   735      * the exception analysis. This is to ensure that every checked exception that is
   736      * thrown is declared or caught. The analyzer uses some info that has been set by
   737      * the liveliness analyzer.
   738      */
   739     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   741         /** A flag that indicates whether the last statement could
   742          *  complete normally.
   743          */
   744         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   746         /** The current class being defined.
   747          */
   748         JCClassDecl classDef;
   750         /** The list of possibly thrown declarable exceptions.
   751          */
   752         List<Type> thrown;
   754         /** The list of exceptions that are either caught or declared to be
   755          *  thrown.
   756          */
   757         List<Type> caught;
   759         class FlowPendingExit extends BaseAnalyzer.PendingExit {
   761             Type thrown;
   763             FlowPendingExit(JCTree tree, Type thrown) {
   764                 super(tree);
   765                 this.thrown = thrown;
   766             }
   767         }
   769         @Override
   770         void markDead() {
   771             //do nothing
   772         }
   774         /*-------------------- Exceptions ----------------------*/
   776         /** Complain that pending exceptions are not caught.
   777          */
   778         void errorUncaught() {
   779             for (FlowPendingExit exit = pendingExits.next();
   780                  exit != null;
   781                  exit = pendingExits.next()) {
   782                 if (classDef != null &&
   783                     classDef.pos == exit.tree.pos) {
   784                     log.error(exit.tree.pos(),
   785                             "unreported.exception.default.constructor",
   786                             exit.thrown);
   787                 } else if (exit.tree.hasTag(VARDEF) &&
   788                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   789                     log.error(exit.tree.pos(),
   790                             "unreported.exception.implicit.close",
   791                             exit.thrown,
   792                             ((JCVariableDecl)exit.tree).sym.name);
   793                 } else {
   794                     log.error(exit.tree.pos(),
   795                             "unreported.exception.need.to.catch.or.throw",
   796                             exit.thrown);
   797                 }
   798             }
   799         }
   801         /** Record that exception is potentially thrown and check that it
   802          *  is caught.
   803          */
   804         void markThrown(JCTree tree, Type exc) {
   805             if (!chk.isUnchecked(tree.pos(), exc)) {
   806                 if (!chk.isHandled(exc, caught))
   807                     pendingExits.append(new FlowPendingExit(tree, exc));
   808                     thrown = chk.incl(exc, thrown);
   809             }
   810         }
   812     /*************************************************************************
   813      * Visitor methods for statements and definitions
   814      *************************************************************************/
   816         /* ------------ Visitor methods for various sorts of trees -------------*/
   818         public void visitClassDef(JCClassDecl tree) {
   819             if (tree.sym == null) return;
   821             JCClassDecl classDefPrev = classDef;
   822             List<Type> thrownPrev = thrown;
   823             List<Type> caughtPrev = caught;
   824             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   825             Lint lintPrev = lint;
   827             pendingExits = new ListBuffer<FlowPendingExit>();
   828             if (tree.name != names.empty) {
   829                 caught = List.nil();
   830             }
   831             classDef = tree;
   832             thrown = List.nil();
   833             lint = lint.augment(tree.sym.annotations);
   835             try {
   836                 // process all the static initializers
   837                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   838                     if (!l.head.hasTag(METHODDEF) &&
   839                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   840                         scan(l.head);
   841                         errorUncaught();
   842                     }
   843                 }
   845                 // add intersection of all thrown clauses of initial constructors
   846                 // to set of caught exceptions, unless class is anonymous.
   847                 if (tree.name != names.empty) {
   848                     boolean firstConstructor = true;
   849                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   850                         if (TreeInfo.isInitialConstructor(l.head)) {
   851                             List<Type> mthrown =
   852                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
   853                             if (firstConstructor) {
   854                                 caught = mthrown;
   855                                 firstConstructor = false;
   856                             } else {
   857                                 caught = chk.intersect(mthrown, caught);
   858                             }
   859                         }
   860                     }
   861                 }
   863                 // process all the instance initializers
   864                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   865                     if (!l.head.hasTag(METHODDEF) &&
   866                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   867                         scan(l.head);
   868                         errorUncaught();
   869                     }
   870                 }
   872                 // in an anonymous class, add the set of thrown exceptions to
   873                 // the throws clause of the synthetic constructor and propagate
   874                 // outwards.
   875                 // Changing the throws clause on the fly is okay here because
   876                 // the anonymous constructor can't be invoked anywhere else,
   877                 // and its type hasn't been cached.
   878                 if (tree.name == names.empty) {
   879                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   880                         if (TreeInfo.isInitialConstructor(l.head)) {
   881                             JCMethodDecl mdef = (JCMethodDecl)l.head;
   882                             mdef.thrown = make.Types(thrown);
   883                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
   884                         }
   885                     }
   886                     thrownPrev = chk.union(thrown, thrownPrev);
   887                 }
   889                 // process all the methods
   890                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   891                     if (l.head.hasTag(METHODDEF)) {
   892                         scan(l.head);
   893                         errorUncaught();
   894                     }
   895                 }
   897                 thrown = thrownPrev;
   898             } finally {
   899                 pendingExits = pendingExitsPrev;
   900                 caught = caughtPrev;
   901                 classDef = classDefPrev;
   902                 lint = lintPrev;
   903             }
   904         }
   906         public void visitMethodDef(JCMethodDecl tree) {
   907             if (tree.body == null) return;
   909             List<Type> caughtPrev = caught;
   910             List<Type> mthrown = tree.sym.type.getThrownTypes();
   911             Lint lintPrev = lint;
   913             lint = lint.augment(tree.sym.annotations);
   915             Assert.check(pendingExits.isEmpty());
   917             try {
   918                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   919                     JCVariableDecl def = l.head;
   920                     scan(def);
   921                 }
   922                 if (TreeInfo.isInitialConstructor(tree))
   923                     caught = chk.union(caught, mthrown);
   924                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   925                     caught = mthrown;
   926                 // else we are in an instance initializer block;
   927                 // leave caught unchanged.
   929                 scan(tree.body);
   931                 List<FlowPendingExit> exits = pendingExits.toList();
   932                 pendingExits = new ListBuffer<FlowPendingExit>();
   933                 while (exits.nonEmpty()) {
   934                     FlowPendingExit exit = exits.head;
   935                     exits = exits.tail;
   936                     if (exit.thrown == null) {
   937                         Assert.check(exit.tree.hasTag(RETURN));
   938                     } else {
   939                         // uncaught throws will be reported later
   940                         pendingExits.append(exit);
   941                     }
   942                 }
   943             } finally {
   944                 caught = caughtPrev;
   945                 lint = lintPrev;
   946             }
   947         }
   949         public void visitVarDef(JCVariableDecl tree) {
   950             if (tree.init != null) {
   951                 Lint lintPrev = lint;
   952                 lint = lint.augment(tree.sym.annotations);
   953                 try{
   954                     scan(tree.init);
   955                 } finally {
   956                     lint = lintPrev;
   957                 }
   958             }
   959         }
   961         public void visitBlock(JCBlock tree) {
   962             scan(tree.stats);
   963         }
   965         public void visitDoLoop(JCDoWhileLoop tree) {
   966             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   967             pendingExits = new ListBuffer<FlowPendingExit>();
   968             scan(tree.body);
   969             resolveContinues(tree);
   970             scan(tree.cond);
   971             resolveBreaks(tree, prevPendingExits);
   972         }
   974         public void visitWhileLoop(JCWhileLoop tree) {
   975             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   976             pendingExits = new ListBuffer<FlowPendingExit>();
   977             scan(tree.cond);
   978             scan(tree.body);
   979             resolveContinues(tree);
   980             resolveBreaks(tree, prevPendingExits);
   981         }
   983         public void visitForLoop(JCForLoop tree) {
   984             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   985             scan(tree.init);
   986             pendingExits = new ListBuffer<FlowPendingExit>();
   987             if (tree.cond != null) {
   988                 scan(tree.cond);
   989             }
   990             scan(tree.body);
   991             resolveContinues(tree);
   992             scan(tree.step);
   993             resolveBreaks(tree, prevPendingExits);
   994         }
   996         public void visitForeachLoop(JCEnhancedForLoop tree) {
   997             visitVarDef(tree.var);
   998             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   999             scan(tree.expr);
  1000             pendingExits = new ListBuffer<FlowPendingExit>();
  1001             scan(tree.body);
  1002             resolveContinues(tree);
  1003             resolveBreaks(tree, prevPendingExits);
  1006         public void visitLabelled(JCLabeledStatement tree) {
  1007             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1008             pendingExits = new ListBuffer<FlowPendingExit>();
  1009             scan(tree.body);
  1010             resolveBreaks(tree, prevPendingExits);
  1013         public void visitSwitch(JCSwitch tree) {
  1014             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1015             pendingExits = new ListBuffer<FlowPendingExit>();
  1016             scan(tree.selector);
  1017             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1018                 JCCase c = l.head;
  1019                 if (c.pat != null) {
  1020                     scan(c.pat);
  1022                 scan(c.stats);
  1024             resolveBreaks(tree, prevPendingExits);
  1027         public void visitTry(JCTry tree) {
  1028             List<Type> caughtPrev = caught;
  1029             List<Type> thrownPrev = thrown;
  1030             thrown = List.nil();
  1031             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1032                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1033                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1034                         List.of(l.head.param.vartype);
  1035                 for (JCExpression ct : subClauses) {
  1036                     caught = chk.incl(ct.type, caught);
  1040             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1041             pendingExits = new ListBuffer<FlowPendingExit>();
  1042             for (JCTree resource : tree.resources) {
  1043                 if (resource instanceof JCVariableDecl) {
  1044                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1045                     visitVarDef(vdecl);
  1046                 } else if (resource instanceof JCExpression) {
  1047                     scan((JCExpression) resource);
  1048                 } else {
  1049                     throw new AssertionError(tree);  // parser error
  1052             for (JCTree resource : tree.resources) {
  1053                 List<Type> closeableSupertypes = resource.type.isCompound() ?
  1054                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
  1055                     List.of(resource.type);
  1056                 for (Type sup : closeableSupertypes) {
  1057                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
  1058                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
  1059                                 attrEnv,
  1060                                 sup,
  1061                                 names.close,
  1062                                 List.<Type>nil(),
  1063                                 List.<Type>nil());
  1064                         if (closeMethod.kind == MTH) {
  1065                             for (Type t : ((MethodSymbol)closeMethod).getThrownTypes()) {
  1066                                 markThrown(resource, t);
  1072             scan(tree.body);
  1073             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1074                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1075                 thrown;
  1076             thrown = thrownPrev;
  1077             caught = caughtPrev;
  1079             List<Type> caughtInTry = List.nil();
  1080             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1081                 JCVariableDecl param = l.head.param;
  1082                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1083                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1084                         List.of(l.head.param.vartype);
  1085                 List<Type> ctypes = List.nil();
  1086                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
  1087                 for (JCExpression ct : subClauses) {
  1088                     Type exc = ct.type;
  1089                     if (exc != syms.unknownType) {
  1090                         ctypes = ctypes.append(exc);
  1091                         if (types.isSameType(exc, syms.objectType))
  1092                             continue;
  1093                         checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
  1094                         caughtInTry = chk.incl(exc, caughtInTry);
  1097                 scan(param);
  1098                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1099                 scan(l.head.body);
  1100                 preciseRethrowTypes.remove(param.sym);
  1102             if (tree.finalizer != null) {
  1103                 List<Type> savedThrown = thrown;
  1104                 thrown = List.nil();
  1105                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1106                 pendingExits = prevPendingExits;
  1107                 scan(tree.finalizer);
  1108                 if (!tree.finallyCanCompleteNormally) {
  1109                     // discard exits and exceptions from try and finally
  1110                     thrown = chk.union(thrown, thrownPrev);
  1111                 } else {
  1112                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1113                     thrown = chk.union(thrown, savedThrown);
  1114                     // FIX: this doesn't preserve source order of exits in catch
  1115                     // versus finally!
  1116                     while (exits.nonEmpty()) {
  1117                         pendingExits.append(exits.next());
  1120             } else {
  1121                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1122                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1123                 pendingExits = prevPendingExits;
  1124                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1128         @Override
  1129         public void visitIf(JCIf tree) {
  1130             scan(tree.cond);
  1131             scan(tree.thenpart);
  1132             if (tree.elsepart != null) {
  1133                 scan(tree.elsepart);
  1137         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1138             if (chk.subset(exc, caughtInTry)) {
  1139                 log.error(pos, "except.already.caught", exc);
  1140             } else if (!chk.isUnchecked(pos, exc) &&
  1141                     !isExceptionOrThrowable(exc) &&
  1142                     !chk.intersects(exc, thrownInTry)) {
  1143                 log.error(pos, "except.never.thrown.in.try", exc);
  1144             } else if (allowImprovedCatchAnalysis) {
  1145                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
  1146                 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
  1147                 // unchecked exception, the result list would not be empty, as the augmented
  1148                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
  1149                 // exception, that would have been covered in the branch above
  1150                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
  1151                         !isExceptionOrThrowable(exc)) {
  1152                     String key = catchableThrownTypes.length() == 1 ?
  1153                             "unreachable.catch" :
  1154                             "unreachable.catch.1";
  1155                     log.warning(pos, key, catchableThrownTypes);
  1159         //where
  1160             private boolean isExceptionOrThrowable(Type exc) {
  1161                 return exc.tsym == syms.throwableType.tsym ||
  1162                     exc.tsym == syms.exceptionType.tsym;
  1165         public void visitBreak(JCBreak tree) {
  1166             recordExit(tree, new FlowPendingExit(tree, null));
  1169         public void visitContinue(JCContinue tree) {
  1170             recordExit(tree, new FlowPendingExit(tree, null));
  1173         public void visitReturn(JCReturn tree) {
  1174             scan(tree.expr);
  1175             recordExit(tree, new FlowPendingExit(tree, null));
  1178         public void visitThrow(JCThrow tree) {
  1179             scan(tree.expr);
  1180             Symbol sym = TreeInfo.symbol(tree.expr);
  1181             if (sym != null &&
  1182                 sym.kind == VAR &&
  1183                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
  1184                 preciseRethrowTypes.get(sym) != null &&
  1185                 allowImprovedRethrowAnalysis) {
  1186                 for (Type t : preciseRethrowTypes.get(sym)) {
  1187                     markThrown(tree, t);
  1190             else {
  1191                 markThrown(tree, tree.expr.type);
  1193             markDead();
  1196         public void visitApply(JCMethodInvocation tree) {
  1197             scan(tree.meth);
  1198             scan(tree.args);
  1199             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
  1200                 markThrown(tree, l.head);
  1203         public void visitNewClass(JCNewClass tree) {
  1204             scan(tree.encl);
  1205             scan(tree.args);
  1206            // scan(tree.def);
  1207             for (List<Type> l = tree.constructorType.getThrownTypes();
  1208                  l.nonEmpty();
  1209                  l = l.tail) {
  1210                 markThrown(tree, l.head);
  1212             List<Type> caughtPrev = caught;
  1213             try {
  1214                 // If the new class expression defines an anonymous class,
  1215                 // analysis of the anonymous constructor may encounter thrown
  1216                 // types which are unsubstituted type variables.
  1217                 // However, since the constructor's actual thrown types have
  1218                 // already been marked as thrown, it is safe to simply include
  1219                 // each of the constructor's formal thrown types in the set of
  1220                 // 'caught/declared to be thrown' types, for the duration of
  1221                 // the class def analysis.
  1222                 if (tree.def != null)
  1223                     for (List<Type> l = tree.constructor.type.getThrownTypes();
  1224                          l.nonEmpty();
  1225                          l = l.tail) {
  1226                         caught = chk.incl(l.head, caught);
  1228                 scan(tree.def);
  1230             finally {
  1231                 caught = caughtPrev;
  1235         @Override
  1236         public void visitLambda(JCLambda tree) {
  1237             if (tree.type != null &&
  1238                     tree.type.isErroneous()) {
  1239                 return;
  1241             List<Type> prevCaught = caught;
  1242             List<Type> prevThrown = thrown;
  1243             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1244             try {
  1245                 pendingExits = ListBuffer.lb();
  1246                 caught = List.of(syms.throwableType); //inhibit exception checking
  1247                 thrown = List.nil();
  1248                 scan(tree.body);
  1249                 tree.inferredThrownTypes = thrown;
  1251             finally {
  1252                 pendingExits = prevPending;
  1253                 caught = prevCaught;
  1254                 thrown = prevThrown;
  1258         public void visitTopLevel(JCCompilationUnit tree) {
  1259             // Do nothing for TopLevel since each class is visited individually
  1262     /**************************************************************************
  1263      * main method
  1264      *************************************************************************/
  1266         /** Perform definite assignment/unassignment analysis on a tree.
  1267          */
  1268         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1269             analyzeTree(env, env.tree, make);
  1271         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  1272             try {
  1273                 attrEnv = env;
  1274                 Flow.this.make = make;
  1275                 pendingExits = new ListBuffer<FlowPendingExit>();
  1276                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1277                 this.thrown = this.caught = null;
  1278                 this.classDef = null;
  1279                 scan(tree);
  1280             } finally {
  1281                 pendingExits = null;
  1282                 Flow.this.make = null;
  1283                 this.thrown = this.caught = null;
  1284                 this.classDef = null;
  1289     /**
  1290      * This pass implements (i) definite assignment analysis, which ensures that
  1291      * each variable is assigned when used and (ii) definite unassignment analysis,
  1292      * which ensures that no final variable is assigned more than once. This visitor
  1293      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1294      * effectively-final local variables/parameters.
  1295      */
  1296     class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
  1298         /** The set of definitely assigned variables.
  1299          */
  1300         Bits inits;
  1302         /** The set of definitely unassigned variables.
  1303          */
  1304         Bits uninits;
  1306         /** The set of variables that are definitely unassigned everywhere
  1307          *  in current try block. This variable is maintained lazily; it is
  1308          *  updated only when something gets removed from uninits,
  1309          *  typically by being assigned in reachable code.  To obtain the
  1310          *  correct set of variables which are definitely unassigned
  1311          *  anywhere in current try block, intersect uninitsTry and
  1312          *  uninits.
  1313          */
  1314         Bits uninitsTry;
  1316         /** When analyzing a condition, inits and uninits are null.
  1317          *  Instead we have:
  1318          */
  1319         Bits initsWhenTrue;
  1320         Bits initsWhenFalse;
  1321         Bits uninitsWhenTrue;
  1322         Bits uninitsWhenFalse;
  1324         /** A mapping from addresses to variable symbols.
  1325          */
  1326         VarSymbol[] vars;
  1328         /** The current class being defined.
  1329          */
  1330         JCClassDecl classDef;
  1332         /** The first variable sequence number in this class definition.
  1333          */
  1334         int firstadr;
  1336         /** The next available variable sequence number.
  1337          */
  1338         int nextadr;
  1340         /** The first variable sequence number in a block that can return.
  1341          */
  1342         int returnadr;
  1344         /** The list of unreferenced automatic resources.
  1345          */
  1346         Scope unrefdResources;
  1348         /** Set when processing a loop body the second time for DU analysis. */
  1349         FlowKind flowKind = FlowKind.NORMAL;
  1351         /** The starting position of the analysed tree */
  1352         int startPos;
  1354         class AssignPendingExit extends BaseAnalyzer.PendingExit {
  1356             Bits exit_inits;
  1357             Bits exit_uninits;
  1359             AssignPendingExit(JCTree tree, Bits inits, Bits uninits) {
  1360                 super(tree);
  1361                 this.exit_inits = inits.dup();
  1362                 this.exit_uninits = uninits.dup();
  1365             void resolveJump() {
  1366                 inits.andSet(exit_inits);
  1367                 uninits.andSet(exit_uninits);
  1371         @Override
  1372         void markDead() {
  1373             inits.inclRange(returnadr, nextadr);
  1374             uninits.inclRange(returnadr, nextadr);
  1377         /*-------------- Processing variables ----------------------*/
  1379         /** Do we need to track init/uninit state of this symbol?
  1380          *  I.e. is symbol either a local or a blank final variable?
  1381          */
  1382         boolean trackable(VarSymbol sym) {
  1383             return
  1384                 sym.pos >= startPos &&
  1385                 ((sym.owner.kind == MTH ||
  1386                  ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1387                   classDef.sym.isEnclosedBy((ClassSymbol)sym.owner))));
  1390         /** Initialize new trackable variable by setting its address field
  1391          *  to the next available sequence number and entering it under that
  1392          *  index into the vars array.
  1393          */
  1394         void newVar(VarSymbol sym) {
  1395             vars = ArrayUtils.ensureCapacity(vars, nextadr);
  1396             if ((sym.flags() & FINAL) == 0) {
  1397                 sym.flags_field |= EFFECTIVELY_FINAL;
  1399             sym.adr = nextadr;
  1400             vars[nextadr] = sym;
  1401             inits.excl(nextadr);
  1402             uninits.incl(nextadr);
  1403             nextadr++;
  1406         /** Record an initialization of a trackable variable.
  1407          */
  1408         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1409             if (sym.adr >= firstadr && trackable(sym)) {
  1410                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
  1411                     if (!uninits.isMember(sym.adr)) {
  1412                         //assignment targeting an effectively final variable
  1413                         //makes the variable lose its status of effectively final
  1414                         //if the variable is _not_ definitively unassigned
  1415                         sym.flags_field &= ~EFFECTIVELY_FINAL;
  1416                     } else {
  1417                         uninit(sym);
  1420                 else if ((sym.flags() & FINAL) != 0) {
  1421                     if ((sym.flags() & PARAMETER) != 0) {
  1422                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  1423                             log.error(pos, "multicatch.parameter.may.not.be.assigned",
  1424                                       sym);
  1426                         else {
  1427                             log.error(pos, "final.parameter.may.not.be.assigned",
  1428                                   sym);
  1430                     } else if (!uninits.isMember(sym.adr)) {
  1431                         log.error(pos, flowKind.errKey, sym);
  1432                     } else {
  1433                         uninit(sym);
  1436                 inits.incl(sym.adr);
  1437             } else if ((sym.flags() & FINAL) != 0) {
  1438                 log.error(pos, "var.might.already.be.assigned", sym);
  1441         //where
  1442             void uninit(VarSymbol sym) {
  1443                 if (!inits.isMember(sym.adr)) {
  1444                     // reachable assignment
  1445                     uninits.excl(sym.adr);
  1446                     uninitsTry.excl(sym.adr);
  1447                 } else {
  1448                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
  1449                     uninits.excl(sym.adr);
  1453         /** If tree is either a simple name or of the form this.name or
  1454          *  C.this.name, and tree represents a trackable variable,
  1455          *  record an initialization of the variable.
  1456          */
  1457         void letInit(JCTree tree) {
  1458             tree = TreeInfo.skipParens(tree);
  1459             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  1460                 Symbol sym = TreeInfo.symbol(tree);
  1461                 if (sym.kind == VAR) {
  1462                     letInit(tree.pos(), (VarSymbol)sym);
  1467         /** Check that trackable variable is initialized.
  1468          */
  1469         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
  1470             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  1471                 trackable(sym) &&
  1472                 !inits.isMember(sym.adr)) {
  1473                 log.error(pos, "var.might.not.have.been.initialized",
  1474                           sym);
  1475                 inits.incl(sym.adr);
  1479         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
  1480          */
  1481         void split(boolean setToNull) {
  1482             initsWhenFalse = inits.dup();
  1483             uninitsWhenFalse = uninits.dup();
  1484             initsWhenTrue = inits;
  1485             uninitsWhenTrue = uninits;
  1486             if (setToNull)
  1487                 inits = uninits = null;
  1490         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
  1491          */
  1492         void merge() {
  1493             inits = initsWhenFalse.andSet(initsWhenTrue);
  1494             uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
  1497     /* ************************************************************************
  1498      * Visitor methods for statements and definitions
  1499      *************************************************************************/
  1501         /** Analyze an expression. Make sure to set (un)inits rather than
  1502          *  (un)initsWhenTrue(WhenFalse) on exit.
  1503          */
  1504         void scanExpr(JCTree tree) {
  1505             if (tree != null) {
  1506                 scan(tree);
  1507                 if (inits == null) merge();
  1511         /** Analyze a list of expressions.
  1512          */
  1513         void scanExprs(List<? extends JCExpression> trees) {
  1514             if (trees != null)
  1515                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
  1516                     scanExpr(l.head);
  1519         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
  1520          *  rather than (un)inits on exit.
  1521          */
  1522         void scanCond(JCTree tree) {
  1523             if (tree.type.isFalse()) {
  1524                 if (inits == null) merge();
  1525                 initsWhenTrue = inits.dup();
  1526                 initsWhenTrue.inclRange(firstadr, nextadr);
  1527                 uninitsWhenTrue = uninits.dup();
  1528                 uninitsWhenTrue.inclRange(firstadr, nextadr);
  1529                 initsWhenFalse = inits;
  1530                 uninitsWhenFalse = uninits;
  1531             } else if (tree.type.isTrue()) {
  1532                 if (inits == null) merge();
  1533                 initsWhenFalse = inits.dup();
  1534                 initsWhenFalse.inclRange(firstadr, nextadr);
  1535                 uninitsWhenFalse = uninits.dup();
  1536                 uninitsWhenFalse.inclRange(firstadr, nextadr);
  1537                 initsWhenTrue = inits;
  1538                 uninitsWhenTrue = uninits;
  1539             } else {
  1540                 scan(tree);
  1541                 if (inits != null)
  1542                     split(tree.type != syms.unknownType);
  1544             if (tree.type != syms.unknownType)
  1545                 inits = uninits = null;
  1548         /* ------------ Visitor methods for various sorts of trees -------------*/
  1550         public void visitClassDef(JCClassDecl tree) {
  1551             if (tree.sym == null) return;
  1553             JCClassDecl classDefPrev = classDef;
  1554             int firstadrPrev = firstadr;
  1555             int nextadrPrev = nextadr;
  1556             ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
  1557             Lint lintPrev = lint;
  1559             pendingExits = new ListBuffer<AssignPendingExit>();
  1560             if (tree.name != names.empty) {
  1561                 firstadr = nextadr;
  1563             classDef = tree;
  1564             lint = lint.augment(tree.sym.annotations);
  1566             try {
  1567                 // define all the static fields
  1568                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1569                     if (l.head.hasTag(VARDEF)) {
  1570                         JCVariableDecl def = (JCVariableDecl)l.head;
  1571                         if ((def.mods.flags & STATIC) != 0) {
  1572                             VarSymbol sym = def.sym;
  1573                             if (trackable(sym))
  1574                                 newVar(sym);
  1579                 // process all the static initializers
  1580                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1581                     if (!l.head.hasTag(METHODDEF) &&
  1582                         (TreeInfo.flags(l.head) & STATIC) != 0) {
  1583                         scan(l.head);
  1587                 // define all the instance fields
  1588                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1589                     if (l.head.hasTag(VARDEF)) {
  1590                         JCVariableDecl def = (JCVariableDecl)l.head;
  1591                         if ((def.mods.flags & STATIC) == 0) {
  1592                             VarSymbol sym = def.sym;
  1593                             if (trackable(sym))
  1594                                 newVar(sym);
  1599                 // process all the instance initializers
  1600                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1601                     if (!l.head.hasTag(METHODDEF) &&
  1602                         (TreeInfo.flags(l.head) & STATIC) == 0) {
  1603                         scan(l.head);
  1607                 // process all the methods
  1608                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1609                     if (l.head.hasTag(METHODDEF)) {
  1610                         scan(l.head);
  1613             } finally {
  1614                 pendingExits = pendingExitsPrev;
  1615                 nextadr = nextadrPrev;
  1616                 firstadr = firstadrPrev;
  1617                 classDef = classDefPrev;
  1618                 lint = lintPrev;
  1622         public void visitMethodDef(JCMethodDecl tree) {
  1623             if (tree.body == null) return;
  1625             Bits initsPrev = inits.dup();
  1626             Bits uninitsPrev = uninits.dup();
  1627             int nextadrPrev = nextadr;
  1628             int firstadrPrev = firstadr;
  1629             int returnadrPrev = returnadr;
  1630             Lint lintPrev = lint;
  1632             lint = lint.augment(tree.sym.annotations);
  1634             Assert.check(pendingExits.isEmpty());
  1636             try {
  1637                 boolean isInitialConstructor =
  1638                     TreeInfo.isInitialConstructor(tree);
  1640                 if (!isInitialConstructor)
  1641                     firstadr = nextadr;
  1642                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  1643                     JCVariableDecl def = l.head;
  1644                     scan(def);
  1645                     inits.incl(def.sym.adr);
  1646                     uninits.excl(def.sym.adr);
  1648                 // else we are in an instance initializer block;
  1649                 // leave caught unchanged.
  1650                 scan(tree.body);
  1652                 if (isInitialConstructor) {
  1653                     for (int i = firstadr; i < nextadr; i++)
  1654                         if (vars[i].owner == classDef.sym)
  1655                             checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
  1657                 List<AssignPendingExit> exits = pendingExits.toList();
  1658                 pendingExits = new ListBuffer<AssignPendingExit>();
  1659                 while (exits.nonEmpty()) {
  1660                     AssignPendingExit exit = exits.head;
  1661                     exits = exits.tail;
  1662                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1663                     if (isInitialConstructor) {
  1664                         inits = exit.exit_inits;
  1665                         for (int i = firstadr; i < nextadr; i++)
  1666                             checkInit(exit.tree.pos(), vars[i]);
  1669             } finally {
  1670                 inits = initsPrev;
  1671                 uninits = uninitsPrev;
  1672                 nextadr = nextadrPrev;
  1673                 firstadr = firstadrPrev;
  1674                 returnadr = returnadrPrev;
  1675                 lint = lintPrev;
  1679         public void visitVarDef(JCVariableDecl tree) {
  1680             boolean track = trackable(tree.sym);
  1681             if (track && tree.sym.owner.kind == MTH) newVar(tree.sym);
  1682             if (tree.init != null) {
  1683                 Lint lintPrev = lint;
  1684                 lint = lint.augment(tree.sym.annotations);
  1685                 try{
  1686                     scanExpr(tree.init);
  1687                     if (track) letInit(tree.pos(), tree.sym);
  1688                 } finally {
  1689                     lint = lintPrev;
  1694         public void visitBlock(JCBlock tree) {
  1695             int nextadrPrev = nextadr;
  1696             scan(tree.stats);
  1697             nextadr = nextadrPrev;
  1700         public void visitDoLoop(JCDoWhileLoop tree) {
  1701             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1702             FlowKind prevFlowKind = flowKind;
  1703             flowKind = FlowKind.NORMAL;
  1704             Bits initsSkip = null;
  1705             Bits uninitsSkip = null;
  1706             pendingExits = new ListBuffer<AssignPendingExit>();
  1707             int prevErrors = log.nerrors;
  1708             do {
  1709                 Bits uninitsEntry = uninits.dup();
  1710                 uninitsEntry.excludeFrom(nextadr);
  1711                 scan(tree.body);
  1712                 resolveContinues(tree);
  1713                 scanCond(tree.cond);
  1714                 if (!flowKind.isFinal()) {
  1715                     initsSkip = initsWhenFalse;
  1716                     uninitsSkip = uninitsWhenFalse;
  1718                 if (log.nerrors !=  prevErrors ||
  1719                     flowKind.isFinal() ||
  1720                     uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1721                     break;
  1722                 inits = initsWhenTrue;
  1723                 uninits = uninitsEntry.andSet(uninitsWhenTrue);
  1724                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1725             } while (true);
  1726             flowKind = prevFlowKind;
  1727             inits = initsSkip;
  1728             uninits = uninitsSkip;
  1729             resolveBreaks(tree, prevPendingExits);
  1732         public void visitWhileLoop(JCWhileLoop tree) {
  1733             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1734             FlowKind prevFlowKind = flowKind;
  1735             flowKind = FlowKind.NORMAL;
  1736             Bits initsSkip = null;
  1737             Bits uninitsSkip = null;
  1738             pendingExits = new ListBuffer<AssignPendingExit>();
  1739             int prevErrors = log.nerrors;
  1740             Bits uninitsEntry = uninits.dup();
  1741             uninitsEntry.excludeFrom(nextadr);
  1742             do {
  1743                 scanCond(tree.cond);
  1744                 if (!flowKind.isFinal()) {
  1745                     initsSkip = initsWhenFalse;
  1746                     uninitsSkip = uninitsWhenFalse;
  1748                 inits = initsWhenTrue;
  1749                 uninits = uninitsWhenTrue;
  1750                 scan(tree.body);
  1751                 resolveContinues(tree);
  1752                 if (log.nerrors != prevErrors ||
  1753                     flowKind.isFinal() ||
  1754                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1755                     break;
  1756                 uninits = uninitsEntry.andSet(uninits);
  1757                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1758             } while (true);
  1759             flowKind = prevFlowKind;
  1760             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
  1761             //branch is not taken AND if it's DA/DU before any break statement
  1762             inits = initsSkip;
  1763             uninits = uninitsSkip;
  1764             resolveBreaks(tree, prevPendingExits);
  1767         public void visitForLoop(JCForLoop tree) {
  1768             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1769             FlowKind prevFlowKind = flowKind;
  1770             flowKind = FlowKind.NORMAL;
  1771             int nextadrPrev = nextadr;
  1772             scan(tree.init);
  1773             Bits initsSkip = null;
  1774             Bits uninitsSkip = null;
  1775             pendingExits = new ListBuffer<AssignPendingExit>();
  1776             int prevErrors = log.nerrors;
  1777             do {
  1778                 Bits uninitsEntry = uninits.dup();
  1779                 uninitsEntry.excludeFrom(nextadr);
  1780                 if (tree.cond != null) {
  1781                     scanCond(tree.cond);
  1782                     if (!flowKind.isFinal()) {
  1783                         initsSkip = initsWhenFalse;
  1784                         uninitsSkip = uninitsWhenFalse;
  1786                     inits = initsWhenTrue;
  1787                     uninits = uninitsWhenTrue;
  1788                 } else if (!flowKind.isFinal()) {
  1789                     initsSkip = inits.dup();
  1790                     initsSkip.inclRange(firstadr, nextadr);
  1791                     uninitsSkip = uninits.dup();
  1792                     uninitsSkip.inclRange(firstadr, nextadr);
  1794                 scan(tree.body);
  1795                 resolveContinues(tree);
  1796                 scan(tree.step);
  1797                 if (log.nerrors != prevErrors ||
  1798                     flowKind.isFinal() ||
  1799                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1800                     break;
  1801                 uninits = uninitsEntry.andSet(uninits);
  1802                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1803             } while (true);
  1804             flowKind = prevFlowKind;
  1805             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
  1806             //branch is not taken AND if it's DA/DU before any break statement
  1807             inits = initsSkip;
  1808             uninits = uninitsSkip;
  1809             resolveBreaks(tree, prevPendingExits);
  1810             nextadr = nextadrPrev;
  1813         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1814             visitVarDef(tree.var);
  1816             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1817             FlowKind prevFlowKind = flowKind;
  1818             flowKind = FlowKind.NORMAL;
  1819             int nextadrPrev = nextadr;
  1820             scan(tree.expr);
  1821             Bits initsStart = inits.dup();
  1822             Bits uninitsStart = uninits.dup();
  1824             letInit(tree.pos(), tree.var.sym);
  1825             pendingExits = new ListBuffer<AssignPendingExit>();
  1826             int prevErrors = log.nerrors;
  1827             do {
  1828                 Bits uninitsEntry = uninits.dup();
  1829                 uninitsEntry.excludeFrom(nextadr);
  1830                 scan(tree.body);
  1831                 resolveContinues(tree);
  1832                 if (log.nerrors != prevErrors ||
  1833                     flowKind.isFinal() ||
  1834                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1835                     break;
  1836                 uninits = uninitsEntry.andSet(uninits);
  1837                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1838             } while (true);
  1839             flowKind = prevFlowKind;
  1840             inits = initsStart;
  1841             uninits = uninitsStart.andSet(uninits);
  1842             resolveBreaks(tree, prevPendingExits);
  1843             nextadr = nextadrPrev;
  1846         public void visitLabelled(JCLabeledStatement tree) {
  1847             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1848             pendingExits = new ListBuffer<AssignPendingExit>();
  1849             scan(tree.body);
  1850             resolveBreaks(tree, prevPendingExits);
  1853         public void visitSwitch(JCSwitch tree) {
  1854             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1855             pendingExits = new ListBuffer<AssignPendingExit>();
  1856             int nextadrPrev = nextadr;
  1857             scanExpr(tree.selector);
  1858             Bits initsSwitch = inits;
  1859             Bits uninitsSwitch = uninits.dup();
  1860             boolean hasDefault = false;
  1861             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1862                 inits = initsSwitch.dup();
  1863                 uninits = uninits.andSet(uninitsSwitch);
  1864                 JCCase c = l.head;
  1865                 if (c.pat == null)
  1866                     hasDefault = true;
  1867                 else
  1868                     scanExpr(c.pat);
  1869                 scan(c.stats);
  1870                 addVars(c.stats, initsSwitch, uninitsSwitch);
  1871                 // Warn about fall-through if lint switch fallthrough enabled.
  1873             if (!hasDefault) {
  1874                 inits.andSet(initsSwitch);
  1876             resolveBreaks(tree, prevPendingExits);
  1877             nextadr = nextadrPrev;
  1879         // where
  1880             /** Add any variables defined in stats to inits and uninits. */
  1881             private void addVars(List<JCStatement> stats, Bits inits,
  1882                                         Bits uninits) {
  1883                 for (;stats.nonEmpty(); stats = stats.tail) {
  1884                     JCTree stat = stats.head;
  1885                     if (stat.hasTag(VARDEF)) {
  1886                         int adr = ((JCVariableDecl) stat).sym.adr;
  1887                         inits.excl(adr);
  1888                         uninits.incl(adr);
  1893         public void visitTry(JCTry tree) {
  1894             ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
  1895             Bits uninitsTryPrev = uninitsTry;
  1896             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1897             pendingExits = new ListBuffer<AssignPendingExit>();
  1898             Bits initsTry = inits.dup();
  1899             uninitsTry = uninits.dup();
  1900             for (JCTree resource : tree.resources) {
  1901                 if (resource instanceof JCVariableDecl) {
  1902                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1903                     visitVarDef(vdecl);
  1904                     unrefdResources.enter(vdecl.sym);
  1905                     resourceVarDecls.append(vdecl);
  1906                 } else if (resource instanceof JCExpression) {
  1907                     scanExpr((JCExpression) resource);
  1908                 } else {
  1909                     throw new AssertionError(tree);  // parser error
  1912             scan(tree.body);
  1913             uninitsTry.andSet(uninits);
  1914             Bits initsEnd = inits;
  1915             Bits uninitsEnd = uninits;
  1916             int nextadrCatch = nextadr;
  1918             if (!resourceVarDecls.isEmpty() &&
  1919                     lint.isEnabled(Lint.LintCategory.TRY)) {
  1920                 for (JCVariableDecl resVar : resourceVarDecls) {
  1921                     if (unrefdResources.includes(resVar.sym)) {
  1922                         log.warning(Lint.LintCategory.TRY, resVar.pos(),
  1923                                     "try.resource.not.referenced", resVar.sym);
  1924                         unrefdResources.remove(resVar.sym);
  1929             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1930                 JCVariableDecl param = l.head.param;
  1931                 inits = initsTry.dup();
  1932                 uninits = uninitsTry.dup();
  1933                 scan(param);
  1934                 inits.incl(param.sym.adr);
  1935                 uninits.excl(param.sym.adr);
  1936                 scan(l.head.body);
  1937                 initsEnd.andSet(inits);
  1938                 uninitsEnd.andSet(uninits);
  1939                 nextadr = nextadrCatch;
  1941             if (tree.finalizer != null) {
  1942                 inits = initsTry.dup();
  1943                 uninits = uninitsTry.dup();
  1944                 ListBuffer<AssignPendingExit> exits = pendingExits;
  1945                 pendingExits = prevPendingExits;
  1946                 scan(tree.finalizer);
  1947                 if (!tree.finallyCanCompleteNormally) {
  1948                     // discard exits and exceptions from try and finally
  1949                 } else {
  1950                     uninits.andSet(uninitsEnd);
  1951                     // FIX: this doesn't preserve source order of exits in catch
  1952                     // versus finally!
  1953                     while (exits.nonEmpty()) {
  1954                         AssignPendingExit exit = exits.next();
  1955                         if (exit.exit_inits != null) {
  1956                             exit.exit_inits.orSet(inits);
  1957                             exit.exit_uninits.andSet(uninits);
  1959                         pendingExits.append(exit);
  1961                     inits.orSet(initsEnd);
  1963             } else {
  1964                 inits = initsEnd;
  1965                 uninits = uninitsEnd;
  1966                 ListBuffer<AssignPendingExit> exits = pendingExits;
  1967                 pendingExits = prevPendingExits;
  1968                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1970             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  1973         public void visitConditional(JCConditional tree) {
  1974             scanCond(tree.cond);
  1975             Bits initsBeforeElse = initsWhenFalse;
  1976             Bits uninitsBeforeElse = uninitsWhenFalse;
  1977             inits = initsWhenTrue;
  1978             uninits = uninitsWhenTrue;
  1979             if (tree.truepart.type.tag == BOOLEAN &&
  1980                 tree.falsepart.type.tag == BOOLEAN) {
  1981                 // if b and c are boolean valued, then
  1982                 // v is (un)assigned after a?b:c when true iff
  1983                 //    v is (un)assigned after b when true and
  1984                 //    v is (un)assigned after c when true
  1985                 scanCond(tree.truepart);
  1986                 Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
  1987                 Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
  1988                 Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
  1989                 Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
  1990                 inits = initsBeforeElse;
  1991                 uninits = uninitsBeforeElse;
  1992                 scanCond(tree.falsepart);
  1993                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
  1994                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
  1995                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
  1996                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
  1997             } else {
  1998                 scanExpr(tree.truepart);
  1999                 Bits initsAfterThen = inits.dup();
  2000                 Bits uninitsAfterThen = uninits.dup();
  2001                 inits = initsBeforeElse;
  2002                 uninits = uninitsBeforeElse;
  2003                 scanExpr(tree.falsepart);
  2004                 inits.andSet(initsAfterThen);
  2005                 uninits.andSet(uninitsAfterThen);
  2009         public void visitIf(JCIf tree) {
  2010             scanCond(tree.cond);
  2011             Bits initsBeforeElse = initsWhenFalse;
  2012             Bits uninitsBeforeElse = uninitsWhenFalse;
  2013             inits = initsWhenTrue;
  2014             uninits = uninitsWhenTrue;
  2015             scan(tree.thenpart);
  2016             if (tree.elsepart != null) {
  2017                 Bits initsAfterThen = inits.dup();
  2018                 Bits uninitsAfterThen = uninits.dup();
  2019                 inits = initsBeforeElse;
  2020                 uninits = uninitsBeforeElse;
  2021                 scan(tree.elsepart);
  2022                 inits.andSet(initsAfterThen);
  2023                 uninits.andSet(uninitsAfterThen);
  2024             } else {
  2025                 inits.andSet(initsBeforeElse);
  2026                 uninits.andSet(uninitsBeforeElse);
  2030         public void visitBreak(JCBreak tree) {
  2031             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2034         public void visitContinue(JCContinue tree) {
  2035             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2038         public void visitReturn(JCReturn tree) {
  2039             scanExpr(tree.expr);
  2040             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  2043         public void visitThrow(JCThrow tree) {
  2044             scanExpr(tree.expr);
  2045             markDead();
  2048         public void visitApply(JCMethodInvocation tree) {
  2049             scanExpr(tree.meth);
  2050             scanExprs(tree.args);
  2053         public void visitNewClass(JCNewClass tree) {
  2054             scanExpr(tree.encl);
  2055             scanExprs(tree.args);
  2056             scan(tree.def);
  2059         @Override
  2060         public void visitLambda(JCLambda tree) {
  2061             Bits prevUninits = uninits;
  2062             Bits prevInits = inits;
  2063             int returnadrPrev = returnadr;
  2064             ListBuffer<AssignPendingExit> prevPending = pendingExits;
  2065             try {
  2066                 returnadr = nextadr;
  2067                 pendingExits = new ListBuffer<AssignPendingExit>();
  2068                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  2069                     JCVariableDecl def = l.head;
  2070                     scan(def);
  2071                     inits.incl(def.sym.adr);
  2072                     uninits.excl(def.sym.adr);
  2074                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
  2075                     scanExpr(tree.body);
  2076                 } else {
  2077                     scan(tree.body);
  2080             finally {
  2081                 returnadr = returnadrPrev;
  2082                 uninits = prevUninits;
  2083                 inits = prevInits;
  2084                 pendingExits = prevPending;
  2088         public void visitNewArray(JCNewArray tree) {
  2089             scanExprs(tree.dims);
  2090             scanExprs(tree.elems);
  2093         public void visitAssert(JCAssert tree) {
  2094             Bits initsExit = inits.dup();
  2095             Bits uninitsExit = uninits.dup();
  2096             scanCond(tree.cond);
  2097             uninitsExit.andSet(uninitsWhenTrue);
  2098             if (tree.detail != null) {
  2099                 inits = initsWhenFalse;
  2100                 uninits = uninitsWhenFalse;
  2101                 scanExpr(tree.detail);
  2103             inits = initsExit;
  2104             uninits = uninitsExit;
  2107         public void visitAssign(JCAssign tree) {
  2108             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2109             if (!(lhs instanceof JCIdent)) {
  2110                 scanExpr(lhs);
  2112             scanExpr(tree.rhs);
  2113             letInit(lhs);
  2116         public void visitAssignop(JCAssignOp tree) {
  2117             scanExpr(tree.lhs);
  2118             scanExpr(tree.rhs);
  2119             letInit(tree.lhs);
  2122         public void visitUnary(JCUnary tree) {
  2123             switch (tree.getTag()) {
  2124             case NOT:
  2125                 scanCond(tree.arg);
  2126                 Bits t = initsWhenFalse;
  2127                 initsWhenFalse = initsWhenTrue;
  2128                 initsWhenTrue = t;
  2129                 t = uninitsWhenFalse;
  2130                 uninitsWhenFalse = uninitsWhenTrue;
  2131                 uninitsWhenTrue = t;
  2132                 break;
  2133             case PREINC: case POSTINC:
  2134             case PREDEC: case POSTDEC:
  2135                 scanExpr(tree.arg);
  2136                 letInit(tree.arg);
  2137                 break;
  2138             default:
  2139                 scanExpr(tree.arg);
  2143         public void visitBinary(JCBinary tree) {
  2144             switch (tree.getTag()) {
  2145             case AND:
  2146                 scanCond(tree.lhs);
  2147                 Bits initsWhenFalseLeft = initsWhenFalse;
  2148                 Bits uninitsWhenFalseLeft = uninitsWhenFalse;
  2149                 inits = initsWhenTrue;
  2150                 uninits = uninitsWhenTrue;
  2151                 scanCond(tree.rhs);
  2152                 initsWhenFalse.andSet(initsWhenFalseLeft);
  2153                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
  2154                 break;
  2155             case OR:
  2156                 scanCond(tree.lhs);
  2157                 Bits initsWhenTrueLeft = initsWhenTrue;
  2158                 Bits uninitsWhenTrueLeft = uninitsWhenTrue;
  2159                 inits = initsWhenFalse;
  2160                 uninits = uninitsWhenFalse;
  2161                 scanCond(tree.rhs);
  2162                 initsWhenTrue.andSet(initsWhenTrueLeft);
  2163                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
  2164                 break;
  2165             default:
  2166                 scanExpr(tree.lhs);
  2167                 scanExpr(tree.rhs);
  2171         public void visitIdent(JCIdent tree) {
  2172             if (tree.sym.kind == VAR) {
  2173                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2174                 referenced(tree.sym);
  2178         void referenced(Symbol sym) {
  2179             unrefdResources.remove(sym);
  2182         public void visitTopLevel(JCCompilationUnit tree) {
  2183             // Do nothing for TopLevel since each class is visited individually
  2186     /**************************************************************************
  2187      * main method
  2188      *************************************************************************/
  2190         /** Perform definite assignment/unassignment analysis on a tree.
  2191          */
  2192         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2193             analyzeTree(env, env.tree, make);
  2196         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2197             try {
  2198                 attrEnv = env;
  2199                 Flow.this.make = make;
  2200                 startPos = tree.pos().getStartPosition();
  2201                 inits = new Bits();
  2202                 uninits = new Bits();
  2203                 uninitsTry = new Bits();
  2204                 initsWhenTrue = initsWhenFalse =
  2205                     uninitsWhenTrue = uninitsWhenFalse = null;
  2206                 if (vars == null)
  2207                     vars = new VarSymbol[32];
  2208                 else
  2209                     for (int i=0; i<vars.length; i++)
  2210                         vars[i] = null;
  2211                 firstadr = 0;
  2212                 nextadr = 0;
  2213                 pendingExits = new ListBuffer<AssignPendingExit>();
  2214                 this.classDef = null;
  2215                 unrefdResources = new Scope(env.enclClass.sym);
  2216                 scan(tree);
  2217             } finally {
  2218                 // note that recursive invocations of this method fail hard
  2219                 startPos = -1;
  2220                 inits = uninits = uninitsTry = null;
  2221                 initsWhenTrue = initsWhenFalse =
  2222                     uninitsWhenTrue = uninitsWhenFalse = null;
  2223                 if (vars != null) for (int i=0; i<vars.length; i++)
  2224                     vars[i] = null;
  2225                 firstadr = 0;
  2226                 nextadr = 0;
  2227                 pendingExits = null;
  2228                 Flow.this.make = null;
  2229                 this.classDef = null;
  2230                 unrefdResources = null;
  2235     /**
  2236      * This pass implements the last step of the dataflow analysis, namely
  2237      * the effectively-final analysis check. This checks that every local variable
  2238      * reference from a lambda body/local inner class is either final or effectively final.
  2239      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2240      * AssignAnalyzer.
  2241      */
  2242     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
  2244         JCTree currentTree; //local class or lambda
  2246         @Override
  2247         void markDead() {
  2248             //do nothing
  2251         @SuppressWarnings("fallthrough")
  2252         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
  2253             if (currentTree != null &&
  2254                     sym.owner.kind == MTH &&
  2255                     sym.pos < currentTree.getStartPosition()) {
  2256                 switch (currentTree.getTag()) {
  2257                     case CLASSDEF:
  2258                         if (!allowEffectivelyFinalInInnerClasses) {
  2259                             if ((sym.flags() & FINAL) == 0) {
  2260                                 reportInnerClsNeedsFinalError(pos, sym);
  2262                             break;
  2264                     case LAMBDA:
  2265                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
  2266                            reportEffectivelyFinalError(pos, sym);
  2272         @SuppressWarnings("fallthrough")
  2273         void letInit(JCTree tree) {
  2274             tree = TreeInfo.skipParens(tree);
  2275             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  2276                 Symbol sym = TreeInfo.symbol(tree);
  2277                 if (currentTree != null &&
  2278                         sym.kind == VAR &&
  2279                         sym.owner.kind == MTH &&
  2280                         ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
  2281                     switch (currentTree.getTag()) {
  2282                         case CLASSDEF:
  2283                             if (!allowEffectivelyFinalInInnerClasses) {
  2284                                 reportInnerClsNeedsFinalError(tree, sym);
  2285                                 break;
  2287                         case LAMBDA:
  2288                             reportEffectivelyFinalError(tree, sym);
  2294         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
  2295             String subKey = currentTree.hasTag(LAMBDA) ?
  2296                   "lambda"  : "inner.cls";
  2297             log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
  2300         void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
  2301             log.error(pos,
  2302                     "local.var.accessed.from.icls.needs.final",
  2303                     sym);
  2306     /*************************************************************************
  2307      * Visitor methods for statements and definitions
  2308      *************************************************************************/
  2310         /* ------------ Visitor methods for various sorts of trees -------------*/
  2312         public void visitClassDef(JCClassDecl tree) {
  2313             JCTree prevTree = currentTree;
  2314             try {
  2315                 currentTree = tree.sym.isLocal() ? tree : null;
  2316                 super.visitClassDef(tree);
  2317             } finally {
  2318                 currentTree = prevTree;
  2322         @Override
  2323         public void visitLambda(JCLambda tree) {
  2324             JCTree prevTree = currentTree;
  2325             try {
  2326                 currentTree = tree;
  2327                 super.visitLambda(tree);
  2328             } finally {
  2329                 currentTree = prevTree;
  2333         @Override
  2334         public void visitIdent(JCIdent tree) {
  2335             if (tree.sym.kind == VAR) {
  2336                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
  2340         public void visitAssign(JCAssign tree) {
  2341             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2342             if (!(lhs instanceof JCIdent)) {
  2343                 scan(lhs);
  2345             scan(tree.rhs);
  2346             letInit(lhs);
  2349         public void visitAssignop(JCAssignOp tree) {
  2350             scan(tree.lhs);
  2351             scan(tree.rhs);
  2352             letInit(tree.lhs);
  2355         public void visitUnary(JCUnary tree) {
  2356             switch (tree.getTag()) {
  2357                 case PREINC: case POSTINC:
  2358                 case PREDEC: case POSTDEC:
  2359                     scan(tree.arg);
  2360                     letInit(tree.arg);
  2361                     break;
  2362                 default:
  2363                     scan(tree.arg);
  2367         public void visitTopLevel(JCCompilationUnit tree) {
  2368             // Do nothing for TopLevel since each class is visited individually
  2371     /**************************************************************************
  2372      * main method
  2373      *************************************************************************/
  2375         /** Perform definite assignment/unassignment analysis on a tree.
  2376          */
  2377         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2378             analyzeTree(env, env.tree, make);
  2380         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2381             try {
  2382                 attrEnv = env;
  2383                 Flow.this.make = make;
  2384                 pendingExits = new ListBuffer<PendingExit>();
  2385                 scan(tree);
  2386             } finally {
  2387                 pendingExits = null;
  2388                 Flow.this.make = null;

mercurial