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

Tue, 13 Nov 2012 15:09:15 -0800

author
jjg
date
Tue, 13 Nov 2012 15:09:15 -0800
changeset 1406
2901c7b5339e
parent 1374
c002fdee76fd
child 1415
01c9d4161882
permissions
-rw-r--r--

8003299: Cleanup javac Log support for deferred diagnostics
Reviewed-by: mcimadamore, jfranck

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

mercurial