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

Thu, 02 Aug 2012 18:23:21 +0100

author
mcimadamore
date
Thu, 02 Aug 2012 18:23:21 +0100
changeset 1297
e5cf1569d3a4
parent 1290
934a89402f85
child 1313
873ddd9f4900
permissions
-rw-r--r--

7175538: Integrate efectively final check with DA/DU analysis
Summary: Allow generalized effectively-final analysis for all local variables
Reviewed-by: jjg, dlsmith

     1 /*
     2  * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle in the LICENSE file that accompanied this code.
    10  *
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    14  * version 2 for more details (a copy is included in the LICENSE file that
    15  * accompanied this code).
    16  *
    17  * You should have received a copy of the GNU General Public License version
    18  * 2 along with this work; if not, write to the Free Software Foundation,
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    20  *
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 //todo: one might eliminate uninits.andSets when monotonic
    28 package com.sun.tools.javac.comp;
    30 import java.util.HashMap;
    32 import com.sun.tools.javac.code.*;
    33 import com.sun.tools.javac.tree.*;
    34 import com.sun.tools.javac.util.*;
    35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    37 import com.sun.tools.javac.code.Symbol.*;
    38 import com.sun.tools.javac.tree.JCTree.*;
    40 import static com.sun.tools.javac.code.Flags.*;
    41 import static com.sun.tools.javac.code.Flags.BLOCK;
    42 import static com.sun.tools.javac.code.Kinds.*;
    43 import static com.sun.tools.javac.code.TypeTags.*;
    44 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    46 /** This pass implements dataflow analysis for Java programs though
    47  *  different AST visitor steps. Liveness analysis (see AliveAlanyzer) checks that
    48  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
    49  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
    50  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
    51  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
    52  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
    53  *  determines that local variables accessed within the scope of an inner class are
    54  *  either final or effectively-final.
    55  *
    56  *  <p>The JLS has a number of problems in the
    57  *  specification of these flow analysis problems. This implementation
    58  *  attempts to address those issues.
    59  *
    60  *  <p>First, there is no accommodation for a finally clause that cannot
    61  *  complete normally. For liveness analysis, an intervening finally
    62  *  clause can cause a break, continue, or return not to reach its
    63  *  target.  For exception analysis, an intervening finally clause can
    64  *  cause any exception to be "caught".  For DA/DU analysis, the finally
    65  *  clause can prevent a transfer of control from propagating DA/DU
    66  *  state to the target.  In addition, code in the finally clause can
    67  *  affect the DA/DU status of variables.
    68  *
    69  *  <p>For try statements, we introduce the idea of a variable being
    70  *  definitely unassigned "everywhere" in a block.  A variable V is
    71  *  "unassigned everywhere" in a block iff it is unassigned at the
    72  *  beginning of the block and there is no reachable assignment to V
    73  *  in the block.  An assignment V=e is reachable iff V is not DA
    74  *  after e.  Then we can say that V is DU at the beginning of the
    75  *  catch block iff V is DU everywhere in the try block.  Similarly, V
    76  *  is DU at the beginning of the finally block iff V is DU everywhere
    77  *  in the try block and in every catch block.  Specifically, the
    78  *  following bullet is added to 16.2.2
    79  *  <pre>
    80  *      V is <em>unassigned everywhere</em> in a block if it is
    81  *      unassigned before the block and there is no reachable
    82  *      assignment to V within the block.
    83  *  </pre>
    84  *  <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all
    85  *  try blocks is changed to
    86  *  <pre>
    87  *      V is definitely unassigned before a catch block iff V is
    88  *      definitely unassigned everywhere in the try block.
    89  *  </pre>
    90  *  <p>The last bullet (and all of its sub-bullets) for try blocks that
    91  *  have a finally block is changed to
    92  *  <pre>
    93  *      V is definitely unassigned before the finally block iff
    94  *      V is definitely unassigned everywhere in the try block
    95  *      and everywhere in each catch block of the try statement.
    96  *  </pre>
    97  *  <p>In addition,
    98  *  <pre>
    99  *      V is definitely assigned at the end of a constructor iff
   100  *      V is definitely assigned after the block that is the body
   101  *      of the constructor and V is definitely assigned at every
   102  *      return that can return from the constructor.
   103  *  </pre>
   104  *  <p>In addition, each continue statement with the loop as its target
   105  *  is treated as a jump to the end of the loop body, and "intervening"
   106  *  finally clauses are treated as follows: V is DA "due to the
   107  *  continue" iff V is DA before the continue statement or V is DA at
   108  *  the end of any intervening finally block.  V is DU "due to the
   109  *  continue" iff any intervening finally cannot complete normally or V
   110  *  is DU at the end of every intervening finally block.  This "due to
   111  *  the continue" concept is then used in the spec for the loops.
   112  *
   113  *  <p>Similarly, break statements must consider intervening finally
   114  *  blocks.  For liveness analysis, a break statement for which any
   115  *  intervening finally cannot complete normally is not considered to
   116  *  cause the target statement to be able to complete normally. Then
   117  *  we say V is DA "due to the break" iff V is DA before the break or
   118  *  V is DA at the end of any intervening finally block.  V is DU "due
   119  *  to the break" iff any intervening finally cannot complete normally
   120  *  or V is DU at the break and at the end of every intervening
   121  *  finally block.  (I suspect this latter condition can be
   122  *  simplified.)  This "due to the break" is then used in the spec for
   123  *  all statements that can be "broken".
   124  *
   125  *  <p>The return statement is treated similarly.  V is DA "due to a
   126  *  return statement" iff V is DA before the return statement or V is
   127  *  DA at the end of any intervening finally block.  Note that we
   128  *  don't have to worry about the return expression because this
   129  *  concept is only used for construcrors.
   130  *
   131  *  <p>There is no spec in the JLS for when a variable is definitely
   132  *  assigned at the end of a constructor, which is needed for final
   133  *  fields (8.3.1.2).  We implement the rule that V is DA at the end
   134  *  of the constructor iff it is DA and the end of the body of the
   135  *  constructor and V is DA "due to" every return of the constructor.
   136  *
   137  *  <p>Intervening finally blocks similarly affect exception analysis.  An
   138  *  intervening finally that cannot complete normally allows us to ignore
   139  *  an otherwise uncaught exception.
   140  *
   141  *  <p>To implement the semantics of intervening finally clauses, all
   142  *  nonlocal transfers (break, continue, return, throw, method call that
   143  *  can throw a checked exception, and a constructor invocation that can
   144  *  thrown a checked exception) are recorded in a queue, and removed
   145  *  from the queue when we complete processing the target of the
   146  *  nonlocal transfer.  This allows us to modify the queue in accordance
   147  *  with the above rules when we encounter a finally clause.  The only
   148  *  exception to this [no pun intended] is that checked exceptions that
   149  *  are known to be caught or declared to be caught in the enclosing
   150  *  method are not recorded in the queue, but instead are recorded in a
   151  *  global variable "Set<Type> thrown" that records the type of all
   152  *  exceptions that can be thrown.
   153  *
   154  *  <p>Other minor issues the treatment of members of other classes
   155  *  (always considered DA except that within an anonymous class
   156  *  constructor, where DA status from the enclosing scope is
   157  *  preserved), treatment of the case expression (V is DA before the
   158  *  case expression iff V is DA after the switch expression),
   159  *  treatment of variables declared in a switch block (the implied
   160  *  DA/DU status after the switch expression is DU and not DA for
   161  *  variables defined in a switch block), the treatment of boolean ?:
   162  *  expressions (The JLS rules only handle b and c non-boolean; the
   163  *  new rule is that if b and c are boolean valued, then V is
   164  *  (un)assigned after a?b:c when true/false iff V is (un)assigned
   165  *  after b when true/false and V is (un)assigned after c when
   166  *  true/false).
   167  *
   168  *  <p>There is the remaining question of what syntactic forms constitute a
   169  *  reference to a variable.  It is conventional to allow this.x on the
   170  *  left-hand-side to initialize a final instance field named x, yet
   171  *  this.x isn't considered a "use" when appearing on a right-hand-side
   172  *  in most implementations.  Should parentheses affect what is
   173  *  considered a variable reference?  The simplest rule would be to
   174  *  allow unqualified forms only, parentheses optional, and phase out
   175  *  support for assigning to a final field via this.x.
   176  *
   177  *  <p><b>This is NOT part of any supported API.
   178  *  If you write code that depends on this, you do so at your own risk.
   179  *  This code and its internal interfaces are subject to change or
   180  *  deletion without notice.</b>
   181  */
   182 public class Flow {
   183     protected static final Context.Key<Flow> flowKey =
   184         new Context.Key<Flow>();
   186     private final Names names;
   187     private final Log log;
   188     private final Symtab syms;
   189     private final Types types;
   190     private final Check chk;
   191     private       TreeMaker make;
   192     private final Resolve rs;
   193     private final JCDiagnostic.Factory diags;
   194     private Env<AttrContext> attrEnv;
   195     private       Lint lint;
   196     private final boolean allowImprovedRethrowAnalysis;
   197     private final boolean allowImprovedCatchAnalysis;
   198     private final boolean allowEffectivelyFinalInInnerClasses;
   200     public static Flow instance(Context context) {
   201         Flow instance = context.get(flowKey);
   202         if (instance == null)
   203             instance = new Flow(context);
   204         return instance;
   205     }
   207     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   208         new AliveAnalyzer().analyzeTree(env, make);
   209         new AssignAnalyzer().analyzeTree(env, make);
   210         new FlowAnalyzer().analyzeTree(env, make);
   211         new CaptureAnalyzer().analyzeTree(env, make);
   212     }
   214     /**
   215      * Definite assignment scan mode
   216      */
   217     enum FlowKind {
   218         /**
   219          * This is the normal DA/DU analysis mode
   220          */
   221         NORMAL("var.might.already.be.assigned", false),
   222         /**
   223          * This is the speculative DA/DU analysis mode used to speculatively
   224          * derive assertions within loop bodies
   225          */
   226         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
   228         String errKey;
   229         boolean isFinal;
   231         FlowKind(String errKey, boolean isFinal) {
   232             this.errKey = errKey;
   233             this.isFinal = isFinal;
   234         }
   236         boolean isFinal() {
   237             return isFinal;
   238         }
   239     }
   241     protected Flow(Context context) {
   242         context.put(flowKey, this);
   243         names = Names.instance(context);
   244         log = Log.instance(context);
   245         syms = Symtab.instance(context);
   246         types = Types.instance(context);
   247         chk = Check.instance(context);
   248         lint = Lint.instance(context);
   249         rs = Resolve.instance(context);
   250         diags = JCDiagnostic.Factory.instance(context);
   251         Source source = Source.instance(context);
   252         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   253         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   254         Options options = Options.instance(context);
   255         allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses() &&
   256                 options.isSet("allowEffectivelyFinalInInnerClasses"); //pre-lambda guard
   257     }
   259     /**
   260      * Base visitor class for all visitors implementing dataflow analysis logic.
   261      * This class define the shared logic for handling jumps (break/continue statements).
   262      */
   263     static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
   265         enum JumpKind {
   266             BREAK(JCTree.Tag.BREAK) {
   267                 @Override
   268                 JCTree getTarget(JCTree tree) {
   269                     return ((JCBreak)tree).target;
   270                 }
   271             },
   272             CONTINUE(JCTree.Tag.CONTINUE) {
   273                 @Override
   274                 JCTree getTarget(JCTree tree) {
   275                     return ((JCContinue)tree).target;
   276                 }
   277             };
   279             JCTree.Tag treeTag;
   281             private JumpKind(Tag treeTag) {
   282                 this.treeTag = treeTag;
   283             }
   285             abstract JCTree getTarget(JCTree tree);
   286         }
   288         /** The currently pending exits that go from current inner blocks
   289          *  to an enclosing block, in source order.
   290          */
   291         ListBuffer<P> pendingExits;
   293         /** A pending exit.  These are the statements return, break, and
   294          *  continue.  In addition, exception-throwing expressions or
   295          *  statements are put here when not known to be caught.  This
   296          *  will typically result in an error unless it is within a
   297          *  try-finally whose finally block cannot complete normally.
   298          */
   299         static class PendingExit {
   300             JCTree tree;
   302             PendingExit(JCTree tree) {
   303                 this.tree = tree;
   304             }
   306             void resolveJump() {
   307                 //do nothing
   308             }
   309         }
   311         abstract void markDead();
   313         /** Record an outward transfer of control. */
   314         void recordExit(JCTree tree, P pe) {
   315             pendingExits.append(pe);
   316             markDead();
   317         }
   319         /** Resolve all jumps of this statement. */
   320         private boolean resolveJump(JCTree tree,
   321                         ListBuffer<P> oldPendingExits,
   322                         JumpKind jk) {
   323             boolean resolved = false;
   324             List<P> exits = pendingExits.toList();
   325             pendingExits = oldPendingExits;
   326             for (; exits.nonEmpty(); exits = exits.tail) {
   327                 P exit = exits.head;
   328                 if (exit.tree.hasTag(jk.treeTag) &&
   329                         jk.getTarget(exit.tree) == tree) {
   330                     exit.resolveJump();
   331                     resolved = true;
   332                 } else {
   333                     pendingExits.append(exit);
   334                 }
   335             }
   336             return resolved;
   337         }
   339         /** Resolve all breaks of this statement. */
   340         boolean resolveContinues(JCTree tree) {
   341             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
   342         }
   344         /** Resolve all continues of this statement. */
   345         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
   346             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   347         }
   348     }
   350     /**
   351      * This pass implements the first step of the dataflow analysis, namely
   352      * the liveness analysis check. This checks that every statement is reachable.
   353      * The output of this analysis pass are used by other analyzers. This analyzer
   354      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   355      */
   356     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
   358         /** A flag that indicates whether the last statement could
   359          *  complete normally.
   360          */
   361         private boolean alive;
   363         @Override
   364         void markDead() {
   365             alive = false;
   366         }
   368     /*************************************************************************
   369      * Visitor methods for statements and definitions
   370      *************************************************************************/
   372         /** Analyze a definition.
   373          */
   374         void scanDef(JCTree tree) {
   375             scanStat(tree);
   376             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
   377                 log.error(tree.pos(),
   378                           "initializer.must.be.able.to.complete.normally");
   379             }
   380         }
   382         /** Analyze a statement. Check that statement is reachable.
   383          */
   384         void scanStat(JCTree tree) {
   385             if (!alive && tree != null) {
   386                 log.error(tree.pos(), "unreachable.stmt");
   387                 if (!tree.hasTag(SKIP)) alive = true;
   388             }
   389             scan(tree);
   390         }
   392         /** Analyze list of statements.
   393          */
   394         void scanStats(List<? extends JCStatement> trees) {
   395             if (trees != null)
   396                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
   397                     scanStat(l.head);
   398         }
   400         /* ------------ Visitor methods for various sorts of trees -------------*/
   402         public void visitClassDef(JCClassDecl tree) {
   403             if (tree.sym == null) return;
   404             boolean alivePrev = alive;
   405             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   406             Lint lintPrev = lint;
   408             pendingExits = new ListBuffer<PendingExit>();
   409             lint = lint.augment(tree.sym.attributes_field);
   411             try {
   412                 // process all the static initializers
   413                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   414                     if (!l.head.hasTag(METHODDEF) &&
   415                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   416                         scanDef(l.head);
   417                     }
   418                 }
   420                 // process all the instance initializers
   421                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   422                     if (!l.head.hasTag(METHODDEF) &&
   423                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   424                         scanDef(l.head);
   425                     }
   426                 }
   428                 // process all the methods
   429                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   430                     if (l.head.hasTag(METHODDEF)) {
   431                         scan(l.head);
   432                     }
   433                 }
   434             } finally {
   435                 pendingExits = pendingExitsPrev;
   436                 alive = alivePrev;
   437                 lint = lintPrev;
   438             }
   439         }
   441         public void visitMethodDef(JCMethodDecl tree) {
   442             if (tree.body == null) return;
   443             Lint lintPrev = lint;
   445             lint = lint.augment(tree.sym.attributes_field);
   447             Assert.check(pendingExits.isEmpty());
   449             try {
   450                 alive = true;
   451                 scanStat(tree.body);
   453                 if (alive && tree.sym.type.getReturnType().tag != VOID)
   454                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   456                 List<PendingExit> exits = pendingExits.toList();
   457                 pendingExits = new ListBuffer<PendingExit>();
   458                 while (exits.nonEmpty()) {
   459                     PendingExit exit = exits.head;
   460                     exits = exits.tail;
   461                     Assert.check(exit.tree.hasTag(RETURN));
   462                 }
   463             } finally {
   464                 lint = lintPrev;
   465             }
   466         }
   468         public void visitVarDef(JCVariableDecl tree) {
   469             if (tree.init != null) {
   470                 Lint lintPrev = lint;
   471                 lint = lint.augment(tree.sym.attributes_field);
   472                 try{
   473                     scan(tree.init);
   474                 } finally {
   475                     lint = lintPrev;
   476                 }
   477             }
   478         }
   480         public void visitBlock(JCBlock tree) {
   481             scanStats(tree.stats);
   482         }
   484         public void visitDoLoop(JCDoWhileLoop tree) {
   485             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   486             pendingExits = new ListBuffer<PendingExit>();
   487             scanStat(tree.body);
   488             alive |= resolveContinues(tree);
   489             scan(tree.cond);
   490             alive = alive && !tree.cond.type.isTrue();
   491             alive |= resolveBreaks(tree, prevPendingExits);
   492         }
   494         public void visitWhileLoop(JCWhileLoop tree) {
   495             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   496             pendingExits = new ListBuffer<PendingExit>();
   497             scan(tree.cond);
   498             alive = !tree.cond.type.isFalse();
   499             scanStat(tree.body);
   500             alive |= resolveContinues(tree);
   501             alive = resolveBreaks(tree, prevPendingExits) ||
   502                 !tree.cond.type.isTrue();
   503         }
   505         public void visitForLoop(JCForLoop tree) {
   506             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   507             scanStats(tree.init);
   508             pendingExits = new ListBuffer<PendingExit>();
   509             if (tree.cond != null) {
   510                 scan(tree.cond);
   511                 alive = !tree.cond.type.isFalse();
   512             } else {
   513                 alive = true;
   514             }
   515             scanStat(tree.body);
   516             alive |= resolveContinues(tree);
   517             scan(tree.step);
   518             alive = resolveBreaks(tree, prevPendingExits) ||
   519                 tree.cond != null && !tree.cond.type.isTrue();
   520         }
   522         public void visitForeachLoop(JCEnhancedForLoop tree) {
   523             visitVarDef(tree.var);
   524             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   525             scan(tree.expr);
   526             pendingExits = new ListBuffer<PendingExit>();
   527             scanStat(tree.body);
   528             alive |= resolveContinues(tree);
   529             resolveBreaks(tree, prevPendingExits);
   530             alive = true;
   531         }
   533         public void visitLabelled(JCLabeledStatement tree) {
   534             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   535             pendingExits = new ListBuffer<PendingExit>();
   536             scanStat(tree.body);
   537             alive |= resolveBreaks(tree, prevPendingExits);
   538         }
   540         public void visitSwitch(JCSwitch tree) {
   541             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   542             pendingExits = new ListBuffer<PendingExit>();
   543             scan(tree.selector);
   544             boolean hasDefault = false;
   545             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   546                 alive = true;
   547                 JCCase c = l.head;
   548                 if (c.pat == null)
   549                     hasDefault = true;
   550                 else
   551                     scan(c.pat);
   552                 scanStats(c.stats);
   553                 // Warn about fall-through if lint switch fallthrough enabled.
   554                 if (alive &&
   555                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   556                     c.stats.nonEmpty() && l.tail.nonEmpty())
   557                     log.warning(Lint.LintCategory.FALLTHROUGH,
   558                                 l.tail.head.pos(),
   559                                 "possible.fall-through.into.case");
   560             }
   561             if (!hasDefault) {
   562                 alive = true;
   563             }
   564             alive |= resolveBreaks(tree, prevPendingExits);
   565         }
   567         public void visitTry(JCTry tree) {
   568             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   569             pendingExits = new ListBuffer<PendingExit>();
   570             for (JCTree resource : tree.resources) {
   571                 if (resource instanceof JCVariableDecl) {
   572                     JCVariableDecl vdecl = (JCVariableDecl) resource;
   573                     visitVarDef(vdecl);
   574                 } else if (resource instanceof JCExpression) {
   575                     scan((JCExpression) resource);
   576                 } else {
   577                     throw new AssertionError(tree);  // parser error
   578                 }
   579             }
   581             scanStat(tree.body);
   582             boolean aliveEnd = alive;
   584             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   585                 alive = true;
   586                 JCVariableDecl param = l.head.param;
   587                 scan(param);
   588                 scanStat(l.head.body);
   589                 aliveEnd |= alive;
   590             }
   591             if (tree.finalizer != null) {
   592                 ListBuffer<PendingExit> exits = pendingExits;
   593                 pendingExits = prevPendingExits;
   594                 alive = true;
   595                 scanStat(tree.finalizer);
   596                 tree.finallyCanCompleteNormally = alive;
   597                 if (!alive) {
   598                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
   599                         log.warning(Lint.LintCategory.FINALLY,
   600                                 TreeInfo.diagEndPos(tree.finalizer),
   601                                 "finally.cannot.complete");
   602                     }
   603                 } else {
   604                     while (exits.nonEmpty()) {
   605                         pendingExits.append(exits.next());
   606                     }
   607                     alive = aliveEnd;
   608                 }
   609             } else {
   610                 alive = aliveEnd;
   611                 ListBuffer<PendingExit> exits = pendingExits;
   612                 pendingExits = prevPendingExits;
   613                 while (exits.nonEmpty()) pendingExits.append(exits.next());
   614             }
   615         }
   617         @Override
   618         public void visitIf(JCIf tree) {
   619             scan(tree.cond);
   620             scanStat(tree.thenpart);
   621             if (tree.elsepart != null) {
   622                 boolean aliveAfterThen = alive;
   623                 alive = true;
   624                 scanStat(tree.elsepart);
   625                 alive = alive | aliveAfterThen;
   626             } else {
   627                 alive = true;
   628             }
   629         }
   631         public void visitBreak(JCBreak tree) {
   632             recordExit(tree, new PendingExit(tree));
   633         }
   635         public void visitContinue(JCContinue tree) {
   636             recordExit(tree, new PendingExit(tree));
   637         }
   639         public void visitReturn(JCReturn tree) {
   640             scan(tree.expr);
   641             recordExit(tree, new PendingExit(tree));
   642         }
   644         public void visitThrow(JCThrow tree) {
   645             scan(tree.expr);
   646             markDead();
   647         }
   649         public void visitApply(JCMethodInvocation tree) {
   650             scan(tree.meth);
   651             scan(tree.args);
   652         }
   654         public void visitNewClass(JCNewClass tree) {
   655             scan(tree.encl);
   656             scan(tree.args);
   657             if (tree.def != null) {
   658                 scan(tree.def);
   659             }
   660         }
   662         public void visitTopLevel(JCCompilationUnit tree) {
   663             // Do nothing for TopLevel since each class is visited individually
   664         }
   666     /**************************************************************************
   667      * main method
   668      *************************************************************************/
   670         /** Perform definite assignment/unassignment analysis on a tree.
   671          */
   672         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   673             try {
   674                 attrEnv = env;
   675                 Flow.this.make = make;
   676                 pendingExits = new ListBuffer<PendingExit>();
   677                 alive = true;
   678                 scan(env.tree);
   679             } finally {
   680                 pendingExits = null;
   681                 Flow.this.make = null;
   682             }
   683         }
   684     }
   686     /**
   687      * This pass implements the second step of the dataflow analysis, namely
   688      * the exception analysis. This is to ensure that every checked exception that is
   689      * thrown is declared or caught. The analyzer uses some info that has been set by
   690      * the liveliness analyzer.
   691      */
   692     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   694         /** A flag that indicates whether the last statement could
   695          *  complete normally.
   696          */
   697         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   699         /** The current class being defined.
   700          */
   701         JCClassDecl classDef;
   703         /** The list of possibly thrown declarable exceptions.
   704          */
   705         List<Type> thrown;
   707         /** The list of exceptions that are either caught or declared to be
   708          *  thrown.
   709          */
   710         List<Type> caught;
   712         class FlowPendingExit extends BaseAnalyzer.PendingExit {
   714             Type thrown;
   716             FlowPendingExit(JCTree tree, Type thrown) {
   717                 super(tree);
   718                 this.thrown = thrown;
   719             }
   720         }
   722         @Override
   723         void markDead() {
   724             //do nothing
   725         }
   727         /*-------------------- Exceptions ----------------------*/
   729         /** Complain that pending exceptions are not caught.
   730          */
   731         void errorUncaught() {
   732             for (FlowPendingExit exit = pendingExits.next();
   733                  exit != null;
   734                  exit = pendingExits.next()) {
   735                 if (classDef != null &&
   736                     classDef.pos == exit.tree.pos) {
   737                     log.error(exit.tree.pos(),
   738                             "unreported.exception.default.constructor",
   739                             exit.thrown);
   740                 } else if (exit.tree.hasTag(VARDEF) &&
   741                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   742                     log.error(exit.tree.pos(),
   743                             "unreported.exception.implicit.close",
   744                             exit.thrown,
   745                             ((JCVariableDecl)exit.tree).sym.name);
   746                 } else {
   747                     log.error(exit.tree.pos(),
   748                             "unreported.exception.need.to.catch.or.throw",
   749                             exit.thrown);
   750                 }
   751             }
   752         }
   754         /** Record that exception is potentially thrown and check that it
   755          *  is caught.
   756          */
   757         void markThrown(JCTree tree, Type exc) {
   758             if (!chk.isUnchecked(tree.pos(), exc)) {
   759                 if (!chk.isHandled(exc, caught))
   760                     pendingExits.append(new FlowPendingExit(tree, exc));
   761                     thrown = chk.incl(exc, thrown);
   762             }
   763         }
   765     /*************************************************************************
   766      * Visitor methods for statements and definitions
   767      *************************************************************************/
   769         /* ------------ Visitor methods for various sorts of trees -------------*/
   771         public void visitClassDef(JCClassDecl tree) {
   772             if (tree.sym == null) return;
   774             JCClassDecl classDefPrev = classDef;
   775             List<Type> thrownPrev = thrown;
   776             List<Type> caughtPrev = caught;
   777             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   778             Lint lintPrev = lint;
   780             pendingExits = new ListBuffer<FlowPendingExit>();
   781             if (tree.name != names.empty) {
   782                 caught = List.nil();
   783             }
   784             classDef = tree;
   785             thrown = List.nil();
   786             lint = lint.augment(tree.sym.attributes_field);
   788             try {
   789                 // process all the static initializers
   790                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   791                     if (!l.head.hasTag(METHODDEF) &&
   792                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   793                         scan(l.head);
   794                         errorUncaught();
   795                     }
   796                 }
   798                 // add intersection of all thrown clauses of initial constructors
   799                 // to set of caught exceptions, unless class is anonymous.
   800                 if (tree.name != names.empty) {
   801                     boolean firstConstructor = true;
   802                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   803                         if (TreeInfo.isInitialConstructor(l.head)) {
   804                             List<Type> mthrown =
   805                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
   806                             if (firstConstructor) {
   807                                 caught = mthrown;
   808                                 firstConstructor = false;
   809                             } else {
   810                                 caught = chk.intersect(mthrown, caught);
   811                             }
   812                         }
   813                     }
   814                 }
   816                 // process all the instance initializers
   817                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   818                     if (!l.head.hasTag(METHODDEF) &&
   819                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   820                         scan(l.head);
   821                         errorUncaught();
   822                     }
   823                 }
   825                 // in an anonymous class, add the set of thrown exceptions to
   826                 // the throws clause of the synthetic constructor and propagate
   827                 // outwards.
   828                 // Changing the throws clause on the fly is okay here because
   829                 // the anonymous constructor can't be invoked anywhere else,
   830                 // and its type hasn't been cached.
   831                 if (tree.name == names.empty) {
   832                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   833                         if (TreeInfo.isInitialConstructor(l.head)) {
   834                             JCMethodDecl mdef = (JCMethodDecl)l.head;
   835                             mdef.thrown = make.Types(thrown);
   836                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
   837                         }
   838                     }
   839                     thrownPrev = chk.union(thrown, thrownPrev);
   840                 }
   842                 // process all the methods
   843                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   844                     if (l.head.hasTag(METHODDEF)) {
   845                         scan(l.head);
   846                         errorUncaught();
   847                     }
   848                 }
   850                 thrown = thrownPrev;
   851             } finally {
   852                 pendingExits = pendingExitsPrev;
   853                 caught = caughtPrev;
   854                 classDef = classDefPrev;
   855                 lint = lintPrev;
   856             }
   857         }
   859         public void visitMethodDef(JCMethodDecl tree) {
   860             if (tree.body == null) return;
   862             List<Type> caughtPrev = caught;
   863             List<Type> mthrown = tree.sym.type.getThrownTypes();
   864             Lint lintPrev = lint;
   866             lint = lint.augment(tree.sym.attributes_field);
   868             Assert.check(pendingExits.isEmpty());
   870             try {
   871                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   872                     JCVariableDecl def = l.head;
   873                     scan(def);
   874                 }
   875                 if (TreeInfo.isInitialConstructor(tree))
   876                     caught = chk.union(caught, mthrown);
   877                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   878                     caught = mthrown;
   879                 // else we are in an instance initializer block;
   880                 // leave caught unchanged.
   882                 scan(tree.body);
   884                 List<FlowPendingExit> exits = pendingExits.toList();
   885                 pendingExits = new ListBuffer<FlowPendingExit>();
   886                 while (exits.nonEmpty()) {
   887                     FlowPendingExit exit = exits.head;
   888                     exits = exits.tail;
   889                     if (exit.thrown == null) {
   890                         Assert.check(exit.tree.hasTag(RETURN));
   891                     } else {
   892                         // uncaught throws will be reported later
   893                         pendingExits.append(exit);
   894                     }
   895                 }
   896             } finally {
   897                 caught = caughtPrev;
   898                 lint = lintPrev;
   899             }
   900         }
   902         public void visitVarDef(JCVariableDecl tree) {
   903             if (tree.init != null) {
   904                 Lint lintPrev = lint;
   905                 lint = lint.augment(tree.sym.attributes_field);
   906                 try{
   907                     scan(tree.init);
   908                 } finally {
   909                     lint = lintPrev;
   910                 }
   911             }
   912         }
   914         public void visitBlock(JCBlock tree) {
   915             scan(tree.stats);
   916         }
   918         public void visitDoLoop(JCDoWhileLoop tree) {
   919             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   920             pendingExits = new ListBuffer<FlowPendingExit>();
   921             scan(tree.body);
   922             resolveContinues(tree);
   923             scan(tree.cond);
   924             resolveBreaks(tree, prevPendingExits);
   925         }
   927         public void visitWhileLoop(JCWhileLoop tree) {
   928             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   929             pendingExits = new ListBuffer<FlowPendingExit>();
   930             scan(tree.cond);
   931             scan(tree.body);
   932             resolveContinues(tree);
   933             resolveBreaks(tree, prevPendingExits);
   934         }
   936         public void visitForLoop(JCForLoop tree) {
   937             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   938             scan(tree.init);
   939             pendingExits = new ListBuffer<FlowPendingExit>();
   940             if (tree.cond != null) {
   941                 scan(tree.cond);
   942             }
   943             scan(tree.body);
   944             resolveContinues(tree);
   945             scan(tree.step);
   946             resolveBreaks(tree, prevPendingExits);
   947         }
   949         public void visitForeachLoop(JCEnhancedForLoop tree) {
   950             visitVarDef(tree.var);
   951             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   952             scan(tree.expr);
   953             pendingExits = new ListBuffer<FlowPendingExit>();
   954             scan(tree.body);
   955             resolveContinues(tree);
   956             resolveBreaks(tree, prevPendingExits);
   957         }
   959         public void visitLabelled(JCLabeledStatement tree) {
   960             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   961             pendingExits = new ListBuffer<FlowPendingExit>();
   962             scan(tree.body);
   963             resolveBreaks(tree, prevPendingExits);
   964         }
   966         public void visitSwitch(JCSwitch tree) {
   967             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   968             pendingExits = new ListBuffer<FlowPendingExit>();
   969             scan(tree.selector);
   970             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   971                 JCCase c = l.head;
   972                 if (c.pat != null) {
   973                     scan(c.pat);
   974                 }
   975                 scan(c.stats);
   976             }
   977             resolveBreaks(tree, prevPendingExits);
   978         }
   980         public void visitTry(JCTry tree) {
   981             List<Type> caughtPrev = caught;
   982             List<Type> thrownPrev = thrown;
   983             thrown = List.nil();
   984             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   985                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
   986                         ((JCTypeUnion)l.head.param.vartype).alternatives :
   987                         List.of(l.head.param.vartype);
   988                 for (JCExpression ct : subClauses) {
   989                     caught = chk.incl(ct.type, caught);
   990                 }
   991             }
   993             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   994             pendingExits = new ListBuffer<FlowPendingExit>();
   995             for (JCTree resource : tree.resources) {
   996                 if (resource instanceof JCVariableDecl) {
   997                     JCVariableDecl vdecl = (JCVariableDecl) resource;
   998                     visitVarDef(vdecl);
   999                 } else if (resource instanceof JCExpression) {
  1000                     scan((JCExpression) resource);
  1001                 } else {
  1002                     throw new AssertionError(tree);  // parser error
  1005             for (JCTree resource : tree.resources) {
  1006                 List<Type> closeableSupertypes = resource.type.isCompound() ?
  1007                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
  1008                     List.of(resource.type);
  1009                 for (Type sup : closeableSupertypes) {
  1010                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
  1011                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
  1012                                 attrEnv,
  1013                                 sup,
  1014                                 names.close,
  1015                                 List.<Type>nil(),
  1016                                 List.<Type>nil());
  1017                         if (closeMethod.kind == MTH) {
  1018                             for (Type t : ((MethodSymbol)closeMethod).getThrownTypes()) {
  1019                                 markThrown(resource, t);
  1025             scan(tree.body);
  1026             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1027                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1028                 thrown;
  1029             thrown = thrownPrev;
  1030             caught = caughtPrev;
  1032             List<Type> caughtInTry = List.nil();
  1033             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1034                 JCVariableDecl param = l.head.param;
  1035                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1036                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1037                         List.of(l.head.param.vartype);
  1038                 List<Type> ctypes = List.nil();
  1039                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
  1040                 for (JCExpression ct : subClauses) {
  1041                     Type exc = ct.type;
  1042                     if (exc != syms.unknownType) {
  1043                         ctypes = ctypes.append(exc);
  1044                         if (types.isSameType(exc, syms.objectType))
  1045                             continue;
  1046                         checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
  1047                         caughtInTry = chk.incl(exc, caughtInTry);
  1050                 scan(param);
  1051                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1052                 scan(l.head.body);
  1053                 preciseRethrowTypes.remove(param.sym);
  1055             if (tree.finalizer != null) {
  1056                 List<Type> savedThrown = thrown;
  1057                 thrown = List.nil();
  1058                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1059                 pendingExits = prevPendingExits;
  1060                 scan(tree.finalizer);
  1061                 if (!tree.finallyCanCompleteNormally) {
  1062                     // discard exits and exceptions from try and finally
  1063                     thrown = chk.union(thrown, thrownPrev);
  1064                 } else {
  1065                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1066                     thrown = chk.union(thrown, savedThrown);
  1067                     // FIX: this doesn't preserve source order of exits in catch
  1068                     // versus finally!
  1069                     while (exits.nonEmpty()) {
  1070                         pendingExits.append(exits.next());
  1073             } else {
  1074                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1075                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1076                 pendingExits = prevPendingExits;
  1077                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1081         @Override
  1082         public void visitIf(JCIf tree) {
  1083             scan(tree.cond);
  1084             scan(tree.thenpart);
  1085             if (tree.elsepart != null) {
  1086                 scan(tree.elsepart);
  1090         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1091             if (chk.subset(exc, caughtInTry)) {
  1092                 log.error(pos, "except.already.caught", exc);
  1093             } else if (!chk.isUnchecked(pos, exc) &&
  1094                     !isExceptionOrThrowable(exc) &&
  1095                     !chk.intersects(exc, thrownInTry)) {
  1096                 log.error(pos, "except.never.thrown.in.try", exc);
  1097             } else if (allowImprovedCatchAnalysis) {
  1098                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
  1099                 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
  1100                 // unchecked exception, the result list would not be empty, as the augmented
  1101                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
  1102                 // exception, that would have been covered in the branch above
  1103                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
  1104                         !isExceptionOrThrowable(exc)) {
  1105                     String key = catchableThrownTypes.length() == 1 ?
  1106                             "unreachable.catch" :
  1107                             "unreachable.catch.1";
  1108                     log.warning(pos, key, catchableThrownTypes);
  1112         //where
  1113             private boolean isExceptionOrThrowable(Type exc) {
  1114                 return exc.tsym == syms.throwableType.tsym ||
  1115                     exc.tsym == syms.exceptionType.tsym;
  1118         public void visitBreak(JCBreak tree) {
  1119             recordExit(tree, new FlowPendingExit(tree, null));
  1122         public void visitContinue(JCContinue tree) {
  1123             recordExit(tree, new FlowPendingExit(tree, null));
  1126         public void visitReturn(JCReturn tree) {
  1127             scan(tree.expr);
  1128             recordExit(tree, new FlowPendingExit(tree, null));
  1131         public void visitThrow(JCThrow tree) {
  1132             scan(tree.expr);
  1133             Symbol sym = TreeInfo.symbol(tree.expr);
  1134             if (sym != null &&
  1135                 sym.kind == VAR &&
  1136                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
  1137                 preciseRethrowTypes.get(sym) != null &&
  1138                 allowImprovedRethrowAnalysis) {
  1139                 for (Type t : preciseRethrowTypes.get(sym)) {
  1140                     markThrown(tree, t);
  1143             else {
  1144                 markThrown(tree, tree.expr.type);
  1146             markDead();
  1149         public void visitApply(JCMethodInvocation tree) {
  1150             scan(tree.meth);
  1151             scan(tree.args);
  1152             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
  1153                 markThrown(tree, l.head);
  1156         public void visitNewClass(JCNewClass tree) {
  1157             scan(tree.encl);
  1158             scan(tree.args);
  1159            // scan(tree.def);
  1160             for (List<Type> l = tree.constructorType.getThrownTypes();
  1161                  l.nonEmpty();
  1162                  l = l.tail) {
  1163                 markThrown(tree, l.head);
  1165             List<Type> caughtPrev = caught;
  1166             try {
  1167                 // If the new class expression defines an anonymous class,
  1168                 // analysis of the anonymous constructor may encounter thrown
  1169                 // types which are unsubstituted type variables.
  1170                 // However, since the constructor's actual thrown types have
  1171                 // already been marked as thrown, it is safe to simply include
  1172                 // each of the constructor's formal thrown types in the set of
  1173                 // 'caught/declared to be thrown' types, for the duration of
  1174                 // the class def analysis.
  1175                 if (tree.def != null)
  1176                     for (List<Type> l = tree.constructor.type.getThrownTypes();
  1177                          l.nonEmpty();
  1178                          l = l.tail) {
  1179                         caught = chk.incl(l.head, caught);
  1181                 scan(tree.def);
  1183             finally {
  1184                 caught = caughtPrev;
  1188         public void visitTopLevel(JCCompilationUnit tree) {
  1189             // Do nothing for TopLevel since each class is visited individually
  1192     /**************************************************************************
  1193      * main method
  1194      *************************************************************************/
  1196         /** Perform definite assignment/unassignment analysis on a tree.
  1197          */
  1198         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1199             analyzeTree(env, env.tree, make);
  1201         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  1202             try {
  1203                 attrEnv = env;
  1204                 Flow.this.make = make;
  1205                 pendingExits = new ListBuffer<FlowPendingExit>();
  1206                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1207                 this.thrown = this.caught = null;
  1208                 this.classDef = null;
  1209                 scan(tree);
  1210             } finally {
  1211                 pendingExits = null;
  1212                 Flow.this.make = null;
  1213                 this.thrown = this.caught = null;
  1214                 this.classDef = null;
  1219     /**
  1220      * This pass implements (i) definite assignment analysis, which ensures that
  1221      * each variable is assigned when used and (ii) definite unassignment analysis,
  1222      * which ensures that no final variable is assigned more than once. This visitor
  1223      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1224      * effectively-final local variables/parameters.
  1225      */
  1226     class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
  1228         /** The set of definitely assigned variables.
  1229          */
  1230         Bits inits;
  1232         /** The set of definitely unassigned variables.
  1233          */
  1234         Bits uninits;
  1236         /** The set of variables that are definitely unassigned everywhere
  1237          *  in current try block. This variable is maintained lazily; it is
  1238          *  updated only when something gets removed from uninits,
  1239          *  typically by being assigned in reachable code.  To obtain the
  1240          *  correct set of variables which are definitely unassigned
  1241          *  anywhere in current try block, intersect uninitsTry and
  1242          *  uninits.
  1243          */
  1244         Bits uninitsTry;
  1246         /** When analyzing a condition, inits and uninits are null.
  1247          *  Instead we have:
  1248          */
  1249         Bits initsWhenTrue;
  1250         Bits initsWhenFalse;
  1251         Bits uninitsWhenTrue;
  1252         Bits uninitsWhenFalse;
  1254         /** A mapping from addresses to variable symbols.
  1255          */
  1256         VarSymbol[] vars;
  1258         /** The current class being defined.
  1259          */
  1260         JCClassDecl classDef;
  1262         /** The first variable sequence number in this class definition.
  1263          */
  1264         int firstadr;
  1266         /** The next available variable sequence number.
  1267          */
  1268         int nextadr;
  1270         /** The list of unreferenced automatic resources.
  1271          */
  1272         Scope unrefdResources;
  1274         /** Set when processing a loop body the second time for DU analysis. */
  1275         FlowKind flowKind = FlowKind.NORMAL;
  1277         /** The starting position of the analysed tree */
  1278         int startPos;
  1280         class AssignPendingExit extends BaseAnalyzer.PendingExit {
  1282             Bits exit_inits;
  1283             Bits exit_uninits;
  1285             AssignPendingExit(JCTree tree, Bits inits, Bits uninits) {
  1286                 super(tree);
  1287                 this.exit_inits = inits.dup();
  1288                 this.exit_uninits = uninits.dup();
  1291             void resolveJump() {
  1292                 inits.andSet(exit_inits);
  1293                 uninits.andSet(exit_uninits);
  1297         @Override
  1298         void markDead() {
  1299             inits.inclRange(firstadr, nextadr);
  1300             uninits.inclRange(firstadr, nextadr);
  1303         /*-------------- Processing variables ----------------------*/
  1305         /** Do we need to track init/uninit state of this symbol?
  1306          *  I.e. is symbol either a local or a blank final variable?
  1307          */
  1308         boolean trackable(VarSymbol sym) {
  1309             return
  1310                 sym.pos >= startPos &&
  1311                 ((sym.owner.kind == MTH ||
  1312                  ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1313                   classDef.sym.isEnclosedBy((ClassSymbol)sym.owner))));
  1316         /** Initialize new trackable variable by setting its address field
  1317          *  to the next available sequence number and entering it under that
  1318          *  index into the vars array.
  1319          */
  1320         void newVar(VarSymbol sym) {
  1321             if (nextadr == vars.length) {
  1322                 VarSymbol[] newvars = new VarSymbol[nextadr * 2];
  1323                 System.arraycopy(vars, 0, newvars, 0, nextadr);
  1324                 vars = newvars;
  1326             if ((sym.flags() & FINAL) == 0) {
  1327                 sym.flags_field |= EFFECTIVELY_FINAL;
  1329             sym.adr = nextadr;
  1330             vars[nextadr] = sym;
  1331             inits.excl(nextadr);
  1332             uninits.incl(nextadr);
  1333             nextadr++;
  1336         /** Record an initialization of a trackable variable.
  1337          */
  1338         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1339             if (sym.adr >= firstadr && trackable(sym)) {
  1340                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
  1341                     if (!uninits.isMember(sym.adr)) {
  1342                         //assignment targeting an effectively final variable
  1343                         //makes the variable lose its status of effectively final
  1344                         //if the variable is _not_ definitively unassigned
  1345                         sym.flags_field &= ~EFFECTIVELY_FINAL;
  1346                     } else {
  1347                         uninit(sym);
  1350                 else if ((sym.flags() & FINAL) != 0) {
  1351                     if ((sym.flags() & PARAMETER) != 0) {
  1352                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  1353                             log.error(pos, "multicatch.parameter.may.not.be.assigned",
  1354                                       sym);
  1356                         else {
  1357                             log.error(pos, "final.parameter.may.not.be.assigned",
  1358                                   sym);
  1360                     } else if (!uninits.isMember(sym.adr)) {
  1361                         log.error(pos, flowKind.errKey, sym);
  1362                     } else {
  1363                         uninit(sym);
  1366                 inits.incl(sym.adr);
  1367             } else if ((sym.flags() & FINAL) != 0) {
  1368                 log.error(pos, "var.might.already.be.assigned", sym);
  1371         //where
  1372             void uninit(VarSymbol sym) {
  1373                 if (!inits.isMember(sym.adr)) {
  1374                     // reachable assignment
  1375                     uninits.excl(sym.adr);
  1376                     uninitsTry.excl(sym.adr);
  1377                 } else {
  1378                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
  1379                     uninits.excl(sym.adr);
  1383         /** If tree is either a simple name or of the form this.name or
  1384          *  C.this.name, and tree represents a trackable variable,
  1385          *  record an initialization of the variable.
  1386          */
  1387         void letInit(JCTree tree) {
  1388             tree = TreeInfo.skipParens(tree);
  1389             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  1390                 Symbol sym = TreeInfo.symbol(tree);
  1391                 if (sym.kind == VAR) {
  1392                     letInit(tree.pos(), (VarSymbol)sym);
  1397         /** Check that trackable variable is initialized.
  1398          */
  1399         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
  1400             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  1401                 trackable(sym) &&
  1402                 !inits.isMember(sym.adr)) {
  1403                 log.error(pos, "var.might.not.have.been.initialized",
  1404                           sym);
  1405                 inits.incl(sym.adr);
  1409         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
  1410          */
  1411         void split(boolean setToNull) {
  1412             initsWhenFalse = inits.dup();
  1413             uninitsWhenFalse = uninits.dup();
  1414             initsWhenTrue = inits;
  1415             uninitsWhenTrue = uninits;
  1416             if (setToNull)
  1417                 inits = uninits = null;
  1420         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
  1421          */
  1422         void merge() {
  1423             inits = initsWhenFalse.andSet(initsWhenTrue);
  1424             uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
  1427     /* ************************************************************************
  1428      * Visitor methods for statements and definitions
  1429      *************************************************************************/
  1431         /** Analyze an expression. Make sure to set (un)inits rather than
  1432          *  (un)initsWhenTrue(WhenFalse) on exit.
  1433          */
  1434         void scanExpr(JCTree tree) {
  1435             if (tree != null) {
  1436                 scan(tree);
  1437                 if (inits == null) merge();
  1441         /** Analyze a list of expressions.
  1442          */
  1443         void scanExprs(List<? extends JCExpression> trees) {
  1444             if (trees != null)
  1445                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
  1446                     scanExpr(l.head);
  1449         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
  1450          *  rather than (un)inits on exit.
  1451          */
  1452         void scanCond(JCTree tree) {
  1453             if (tree.type.isFalse()) {
  1454                 if (inits == null) merge();
  1455                 initsWhenTrue = inits.dup();
  1456                 initsWhenTrue.inclRange(firstadr, nextadr);
  1457                 uninitsWhenTrue = uninits.dup();
  1458                 uninitsWhenTrue.inclRange(firstadr, nextadr);
  1459                 initsWhenFalse = inits;
  1460                 uninitsWhenFalse = uninits;
  1461             } else if (tree.type.isTrue()) {
  1462                 if (inits == null) merge();
  1463                 initsWhenFalse = inits.dup();
  1464                 initsWhenFalse.inclRange(firstadr, nextadr);
  1465                 uninitsWhenFalse = uninits.dup();
  1466                 uninitsWhenFalse.inclRange(firstadr, nextadr);
  1467                 initsWhenTrue = inits;
  1468                 uninitsWhenTrue = uninits;
  1469             } else {
  1470                 scan(tree);
  1471                 if (inits != null)
  1472                     split(tree.type != syms.unknownType);
  1474             if (tree.type != syms.unknownType)
  1475                 inits = uninits = null;
  1478         /* ------------ Visitor methods for various sorts of trees -------------*/
  1480         public void visitClassDef(JCClassDecl tree) {
  1481             if (tree.sym == null) return;
  1483             JCClassDecl classDefPrev = classDef;
  1484             int firstadrPrev = firstadr;
  1485             int nextadrPrev = nextadr;
  1486             ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
  1487             Lint lintPrev = lint;
  1489             pendingExits = new ListBuffer<AssignPendingExit>();
  1490             if (tree.name != names.empty) {
  1491                 firstadr = nextadr;
  1493             classDef = tree;
  1494             lint = lint.augment(tree.sym.attributes_field);
  1496             try {
  1497                 // define all the static fields
  1498                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1499                     if (l.head.hasTag(VARDEF)) {
  1500                         JCVariableDecl def = (JCVariableDecl)l.head;
  1501                         if ((def.mods.flags & STATIC) != 0) {
  1502                             VarSymbol sym = def.sym;
  1503                             if (trackable(sym))
  1504                                 newVar(sym);
  1509                 // process all the static initializers
  1510                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1511                     if (!l.head.hasTag(METHODDEF) &&
  1512                         (TreeInfo.flags(l.head) & STATIC) != 0) {
  1513                         scan(l.head);
  1517                 // define all the instance fields
  1518                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1519                     if (l.head.hasTag(VARDEF)) {
  1520                         JCVariableDecl def = (JCVariableDecl)l.head;
  1521                         if ((def.mods.flags & STATIC) == 0) {
  1522                             VarSymbol sym = def.sym;
  1523                             if (trackable(sym))
  1524                                 newVar(sym);
  1529                 // process all the instance initializers
  1530                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1531                     if (!l.head.hasTag(METHODDEF) &&
  1532                         (TreeInfo.flags(l.head) & STATIC) == 0) {
  1533                         scan(l.head);
  1537                 // process all the methods
  1538                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1539                     if (l.head.hasTag(METHODDEF)) {
  1540                         scan(l.head);
  1543             } finally {
  1544                 pendingExits = pendingExitsPrev;
  1545                 nextadr = nextadrPrev;
  1546                 firstadr = firstadrPrev;
  1547                 classDef = classDefPrev;
  1548                 lint = lintPrev;
  1552         public void visitMethodDef(JCMethodDecl tree) {
  1553             if (tree.body == null) return;
  1555             Bits initsPrev = inits.dup();
  1556             Bits uninitsPrev = uninits.dup();
  1557             int nextadrPrev = nextadr;
  1558             int firstadrPrev = firstadr;
  1559             Lint lintPrev = lint;
  1561             lint = lint.augment(tree.sym.attributes_field);
  1563             Assert.check(pendingExits.isEmpty());
  1565             try {
  1566                 boolean isInitialConstructor =
  1567                     TreeInfo.isInitialConstructor(tree);
  1569                 if (!isInitialConstructor)
  1570                     firstadr = nextadr;
  1571                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  1572                     JCVariableDecl def = l.head;
  1573                     scan(def);
  1574                     inits.incl(def.sym.adr);
  1575                     uninits.excl(def.sym.adr);
  1577                 // else we are in an instance initializer block;
  1578                 // leave caught unchanged.
  1579                 scan(tree.body);
  1581                 if (isInitialConstructor) {
  1582                     for (int i = firstadr; i < nextadr; i++)
  1583                         if (vars[i].owner == classDef.sym)
  1584                             checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
  1586                 List<AssignPendingExit> exits = pendingExits.toList();
  1587                 pendingExits = new ListBuffer<AssignPendingExit>();
  1588                 while (exits.nonEmpty()) {
  1589                     AssignPendingExit exit = exits.head;
  1590                     exits = exits.tail;
  1591                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1592                     if (isInitialConstructor) {
  1593                         inits = exit.exit_inits;
  1594                         for (int i = firstadr; i < nextadr; i++)
  1595                             checkInit(exit.tree.pos(), vars[i]);
  1598             } finally {
  1599                 inits = initsPrev;
  1600                 uninits = uninitsPrev;
  1601                 nextadr = nextadrPrev;
  1602                 firstadr = firstadrPrev;
  1603                 lint = lintPrev;
  1607         public void visitVarDef(JCVariableDecl tree) {
  1608             boolean track = trackable(tree.sym);
  1609             if (track && tree.sym.owner.kind == MTH) newVar(tree.sym);
  1610             if (tree.init != null) {
  1611                 Lint lintPrev = lint;
  1612                 lint = lint.augment(tree.sym.attributes_field);
  1613                 try{
  1614                     scanExpr(tree.init);
  1615                     if (track) letInit(tree.pos(), tree.sym);
  1616                 } finally {
  1617                     lint = lintPrev;
  1622         public void visitBlock(JCBlock tree) {
  1623             int nextadrPrev = nextadr;
  1624             scan(tree.stats);
  1625             nextadr = nextadrPrev;
  1628         public void visitDoLoop(JCDoWhileLoop tree) {
  1629             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1630             FlowKind prevFlowKind = flowKind;
  1631             flowKind = FlowKind.NORMAL;
  1632             Bits initsSkip = null;
  1633             Bits uninitsSkip = null;
  1634             pendingExits = new ListBuffer<AssignPendingExit>();
  1635             int prevErrors = log.nerrors;
  1636             do {
  1637                 Bits uninitsEntry = uninits.dup();
  1638                 uninitsEntry.excludeFrom(nextadr);
  1639                 scan(tree.body);
  1640                 resolveContinues(tree);
  1641                 scanCond(tree.cond);
  1642                 if (!flowKind.isFinal()) {
  1643                     initsSkip = initsWhenFalse;
  1644                     uninitsSkip = uninitsWhenFalse;
  1646                 if (log.nerrors !=  prevErrors ||
  1647                     flowKind.isFinal() ||
  1648                     uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1649                     break;
  1650                 inits = initsWhenTrue;
  1651                 uninits = uninitsEntry.andSet(uninitsWhenTrue);
  1652                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1653             } while (true);
  1654             flowKind = prevFlowKind;
  1655             inits = initsSkip;
  1656             uninits = uninitsSkip;
  1657             resolveBreaks(tree, prevPendingExits);
  1660         public void visitWhileLoop(JCWhileLoop tree) {
  1661             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1662             FlowKind prevFlowKind = flowKind;
  1663             flowKind = FlowKind.NORMAL;
  1664             Bits initsSkip = null;
  1665             Bits uninitsSkip = null;
  1666             pendingExits = new ListBuffer<AssignPendingExit>();
  1667             int prevErrors = log.nerrors;
  1668             Bits uninitsEntry = uninits.dup();
  1669             uninitsEntry.excludeFrom(nextadr);
  1670             do {
  1671                 scanCond(tree.cond);
  1672                 if (!flowKind.isFinal()) {
  1673                     initsSkip = initsWhenFalse;
  1674                     uninitsSkip = uninitsWhenFalse;
  1676                 inits = initsWhenTrue;
  1677                 uninits = uninitsWhenTrue;
  1678                 scan(tree.body);
  1679                 resolveContinues(tree);
  1680                 if (log.nerrors != prevErrors ||
  1681                     flowKind.isFinal() ||
  1682                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1683                     break;
  1684                 uninits = uninitsEntry.andSet(uninits);
  1685                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1686             } while (true);
  1687             flowKind = prevFlowKind;
  1688             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
  1689             //branch is not taken AND if it's DA/DU before any break statement
  1690             inits = initsSkip;
  1691             uninits = uninitsSkip;
  1692             resolveBreaks(tree, prevPendingExits);
  1695         public void visitForLoop(JCForLoop tree) {
  1696             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1697             FlowKind prevFlowKind = flowKind;
  1698             flowKind = FlowKind.NORMAL;
  1699             int nextadrPrev = nextadr;
  1700             scan(tree.init);
  1701             Bits initsSkip = null;
  1702             Bits uninitsSkip = null;
  1703             pendingExits = new ListBuffer<AssignPendingExit>();
  1704             int prevErrors = log.nerrors;
  1705             do {
  1706                 Bits uninitsEntry = uninits.dup();
  1707                 uninitsEntry.excludeFrom(nextadr);
  1708                 if (tree.cond != null) {
  1709                     scanCond(tree.cond);
  1710                     if (!flowKind.isFinal()) {
  1711                         initsSkip = initsWhenFalse;
  1712                         uninitsSkip = uninitsWhenFalse;
  1714                     inits = initsWhenTrue;
  1715                     uninits = uninitsWhenTrue;
  1716                 } else if (!flowKind.isFinal()) {
  1717                     initsSkip = inits.dup();
  1718                     initsSkip.inclRange(firstadr, nextadr);
  1719                     uninitsSkip = uninits.dup();
  1720                     uninitsSkip.inclRange(firstadr, nextadr);
  1722                 scan(tree.body);
  1723                 resolveContinues(tree);
  1724                 scan(tree.step);
  1725                 if (log.nerrors != prevErrors ||
  1726                     flowKind.isFinal() ||
  1727                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1728                     break;
  1729                 uninits = uninitsEntry.andSet(uninits);
  1730                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1731             } while (true);
  1732             flowKind = prevFlowKind;
  1733             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
  1734             //branch is not taken AND if it's DA/DU before any break statement
  1735             inits = initsSkip;
  1736             uninits = uninitsSkip;
  1737             resolveBreaks(tree, prevPendingExits);
  1738             nextadr = nextadrPrev;
  1741         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1742             visitVarDef(tree.var);
  1744             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1745             FlowKind prevFlowKind = flowKind;
  1746             flowKind = FlowKind.NORMAL;
  1747             int nextadrPrev = nextadr;
  1748             scan(tree.expr);
  1749             Bits initsStart = inits.dup();
  1750             Bits uninitsStart = uninits.dup();
  1752             letInit(tree.pos(), tree.var.sym);
  1753             pendingExits = new ListBuffer<AssignPendingExit>();
  1754             int prevErrors = log.nerrors;
  1755             do {
  1756                 Bits uninitsEntry = uninits.dup();
  1757                 uninitsEntry.excludeFrom(nextadr);
  1758                 scan(tree.body);
  1759                 resolveContinues(tree);
  1760                 if (log.nerrors != prevErrors ||
  1761                     flowKind.isFinal() ||
  1762                     uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  1763                     break;
  1764                 uninits = uninitsEntry.andSet(uninits);
  1765                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1766             } while (true);
  1767             flowKind = prevFlowKind;
  1768             inits = initsStart;
  1769             uninits = uninitsStart.andSet(uninits);
  1770             resolveBreaks(tree, prevPendingExits);
  1771             nextadr = nextadrPrev;
  1774         public void visitLabelled(JCLabeledStatement tree) {
  1775             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1776             pendingExits = new ListBuffer<AssignPendingExit>();
  1777             scan(tree.body);
  1778             resolveBreaks(tree, prevPendingExits);
  1781         public void visitSwitch(JCSwitch tree) {
  1782             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1783             pendingExits = new ListBuffer<AssignPendingExit>();
  1784             int nextadrPrev = nextadr;
  1785             scanExpr(tree.selector);
  1786             Bits initsSwitch = inits;
  1787             Bits uninitsSwitch = uninits.dup();
  1788             boolean hasDefault = false;
  1789             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1790                 inits = initsSwitch.dup();
  1791                 uninits = uninits.andSet(uninitsSwitch);
  1792                 JCCase c = l.head;
  1793                 if (c.pat == null)
  1794                     hasDefault = true;
  1795                 else
  1796                     scanExpr(c.pat);
  1797                 scan(c.stats);
  1798                 addVars(c.stats, initsSwitch, uninitsSwitch);
  1799                 // Warn about fall-through if lint switch fallthrough enabled.
  1801             if (!hasDefault) {
  1802                 inits.andSet(initsSwitch);
  1804             resolveBreaks(tree, prevPendingExits);
  1805             nextadr = nextadrPrev;
  1807         // where
  1808             /** Add any variables defined in stats to inits and uninits. */
  1809             private void addVars(List<JCStatement> stats, Bits inits,
  1810                                         Bits uninits) {
  1811                 for (;stats.nonEmpty(); stats = stats.tail) {
  1812                     JCTree stat = stats.head;
  1813                     if (stat.hasTag(VARDEF)) {
  1814                         int adr = ((JCVariableDecl) stat).sym.adr;
  1815                         inits.excl(adr);
  1816                         uninits.incl(adr);
  1821         public void visitTry(JCTry tree) {
  1822             ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
  1823             Bits uninitsTryPrev = uninitsTry;
  1824             ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
  1825             pendingExits = new ListBuffer<AssignPendingExit>();
  1826             Bits initsTry = inits.dup();
  1827             uninitsTry = uninits.dup();
  1828             for (JCTree resource : tree.resources) {
  1829                 if (resource instanceof JCVariableDecl) {
  1830                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1831                     visitVarDef(vdecl);
  1832                     unrefdResources.enter(vdecl.sym);
  1833                     resourceVarDecls.append(vdecl);
  1834                 } else if (resource instanceof JCExpression) {
  1835                     scanExpr((JCExpression) resource);
  1836                 } else {
  1837                     throw new AssertionError(tree);  // parser error
  1840             scan(tree.body);
  1841             uninitsTry.andSet(uninits);
  1842             Bits initsEnd = inits;
  1843             Bits uninitsEnd = uninits;
  1844             int nextadrCatch = nextadr;
  1846             if (!resourceVarDecls.isEmpty() &&
  1847                     lint.isEnabled(Lint.LintCategory.TRY)) {
  1848                 for (JCVariableDecl resVar : resourceVarDecls) {
  1849                     if (unrefdResources.includes(resVar.sym)) {
  1850                         log.warning(Lint.LintCategory.TRY, resVar.pos(),
  1851                                     "try.resource.not.referenced", resVar.sym);
  1852                         unrefdResources.remove(resVar.sym);
  1857             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1858                 JCVariableDecl param = l.head.param;
  1859                 inits = initsTry.dup();
  1860                 uninits = uninitsTry.dup();
  1861                 scan(param);
  1862                 inits.incl(param.sym.adr);
  1863                 uninits.excl(param.sym.adr);
  1864                 scan(l.head.body);
  1865                 initsEnd.andSet(inits);
  1866                 uninitsEnd.andSet(uninits);
  1867                 nextadr = nextadrCatch;
  1869             if (tree.finalizer != null) {
  1870                 inits = initsTry.dup();
  1871                 uninits = uninitsTry.dup();
  1872                 ListBuffer<AssignPendingExit> exits = pendingExits;
  1873                 pendingExits = prevPendingExits;
  1874                 scan(tree.finalizer);
  1875                 if (!tree.finallyCanCompleteNormally) {
  1876                     // discard exits and exceptions from try and finally
  1877                 } else {
  1878                     uninits.andSet(uninitsEnd);
  1879                     // FIX: this doesn't preserve source order of exits in catch
  1880                     // versus finally!
  1881                     while (exits.nonEmpty()) {
  1882                         AssignPendingExit exit = exits.next();
  1883                         if (exit.exit_inits != null) {
  1884                             exit.exit_inits.orSet(inits);
  1885                             exit.exit_uninits.andSet(uninits);
  1887                         pendingExits.append(exit);
  1889                     inits.orSet(initsEnd);
  1891             } else {
  1892                 inits = initsEnd;
  1893                 uninits = uninitsEnd;
  1894                 ListBuffer<AssignPendingExit> exits = pendingExits;
  1895                 pendingExits = prevPendingExits;
  1896                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1898             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  1901         public void visitConditional(JCConditional tree) {
  1902             scanCond(tree.cond);
  1903             Bits initsBeforeElse = initsWhenFalse;
  1904             Bits uninitsBeforeElse = uninitsWhenFalse;
  1905             inits = initsWhenTrue;
  1906             uninits = uninitsWhenTrue;
  1907             if (tree.truepart.type.tag == BOOLEAN &&
  1908                 tree.falsepart.type.tag == BOOLEAN) {
  1909                 // if b and c are boolean valued, then
  1910                 // v is (un)assigned after a?b:c when true iff
  1911                 //    v is (un)assigned after b when true and
  1912                 //    v is (un)assigned after c when true
  1913                 scanCond(tree.truepart);
  1914                 Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
  1915                 Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
  1916                 Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
  1917                 Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
  1918                 inits = initsBeforeElse;
  1919                 uninits = uninitsBeforeElse;
  1920                 scanCond(tree.falsepart);
  1921                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
  1922                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
  1923                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
  1924                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
  1925             } else {
  1926                 scanExpr(tree.truepart);
  1927                 Bits initsAfterThen = inits.dup();
  1928                 Bits uninitsAfterThen = uninits.dup();
  1929                 inits = initsBeforeElse;
  1930                 uninits = uninitsBeforeElse;
  1931                 scanExpr(tree.falsepart);
  1932                 inits.andSet(initsAfterThen);
  1933                 uninits.andSet(uninitsAfterThen);
  1937         public void visitIf(JCIf tree) {
  1938             scanCond(tree.cond);
  1939             Bits initsBeforeElse = initsWhenFalse;
  1940             Bits uninitsBeforeElse = uninitsWhenFalse;
  1941             inits = initsWhenTrue;
  1942             uninits = uninitsWhenTrue;
  1943             scan(tree.thenpart);
  1944             if (tree.elsepart != null) {
  1945                 Bits initsAfterThen = inits.dup();
  1946                 Bits uninitsAfterThen = uninits.dup();
  1947                 inits = initsBeforeElse;
  1948                 uninits = uninitsBeforeElse;
  1949                 scan(tree.elsepart);
  1950                 inits.andSet(initsAfterThen);
  1951                 uninits.andSet(uninitsAfterThen);
  1952             } else {
  1953                 inits.andSet(initsBeforeElse);
  1954                 uninits.andSet(uninitsBeforeElse);
  1958         public void visitBreak(JCBreak tree) {
  1959             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  1962         public void visitContinue(JCContinue tree) {
  1963             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  1966         public void visitReturn(JCReturn tree) {
  1967             scanExpr(tree.expr);
  1968             recordExit(tree, new AssignPendingExit(tree, inits, uninits));
  1971         public void visitThrow(JCThrow tree) {
  1972             scanExpr(tree.expr);
  1973             markDead();
  1976         public void visitApply(JCMethodInvocation tree) {
  1977             scanExpr(tree.meth);
  1978             scanExprs(tree.args);
  1981         public void visitNewClass(JCNewClass tree) {
  1982             scanExpr(tree.encl);
  1983             scanExprs(tree.args);
  1984             scan(tree.def);
  1987         public void visitNewArray(JCNewArray tree) {
  1988             scanExprs(tree.dims);
  1989             scanExprs(tree.elems);
  1992         public void visitAssert(JCAssert tree) {
  1993             Bits initsExit = inits.dup();
  1994             Bits uninitsExit = uninits.dup();
  1995             scanCond(tree.cond);
  1996             uninitsExit.andSet(uninitsWhenTrue);
  1997             if (tree.detail != null) {
  1998                 inits = initsWhenFalse;
  1999                 uninits = uninitsWhenFalse;
  2000                 scanExpr(tree.detail);
  2002             inits = initsExit;
  2003             uninits = uninitsExit;
  2006         public void visitAssign(JCAssign tree) {
  2007             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2008             if (!(lhs instanceof JCIdent)) {
  2009                 scanExpr(lhs);
  2011             scanExpr(tree.rhs);
  2012             letInit(lhs);
  2015         public void visitAssignop(JCAssignOp tree) {
  2016             scanExpr(tree.lhs);
  2017             scanExpr(tree.rhs);
  2018             letInit(tree.lhs);
  2021         public void visitUnary(JCUnary tree) {
  2022             switch (tree.getTag()) {
  2023             case NOT:
  2024                 scanCond(tree.arg);
  2025                 Bits t = initsWhenFalse;
  2026                 initsWhenFalse = initsWhenTrue;
  2027                 initsWhenTrue = t;
  2028                 t = uninitsWhenFalse;
  2029                 uninitsWhenFalse = uninitsWhenTrue;
  2030                 uninitsWhenTrue = t;
  2031                 break;
  2032             case PREINC: case POSTINC:
  2033             case PREDEC: case POSTDEC:
  2034                 scanExpr(tree.arg);
  2035                 letInit(tree.arg);
  2036                 break;
  2037             default:
  2038                 scanExpr(tree.arg);
  2042         public void visitBinary(JCBinary tree) {
  2043             switch (tree.getTag()) {
  2044             case AND:
  2045                 scanCond(tree.lhs);
  2046                 Bits initsWhenFalseLeft = initsWhenFalse;
  2047                 Bits uninitsWhenFalseLeft = uninitsWhenFalse;
  2048                 inits = initsWhenTrue;
  2049                 uninits = uninitsWhenTrue;
  2050                 scanCond(tree.rhs);
  2051                 initsWhenFalse.andSet(initsWhenFalseLeft);
  2052                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
  2053                 break;
  2054             case OR:
  2055                 scanCond(tree.lhs);
  2056                 Bits initsWhenTrueLeft = initsWhenTrue;
  2057                 Bits uninitsWhenTrueLeft = uninitsWhenTrue;
  2058                 inits = initsWhenFalse;
  2059                 uninits = uninitsWhenFalse;
  2060                 scanCond(tree.rhs);
  2061                 initsWhenTrue.andSet(initsWhenTrueLeft);
  2062                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
  2063                 break;
  2064             default:
  2065                 scanExpr(tree.lhs);
  2066                 scanExpr(tree.rhs);
  2070         public void visitIdent(JCIdent tree) {
  2071             if (tree.sym.kind == VAR) {
  2072                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2073                 referenced(tree.sym);
  2077         void referenced(Symbol sym) {
  2078             unrefdResources.remove(sym);
  2081         public void visitTopLevel(JCCompilationUnit tree) {
  2082             // Do nothing for TopLevel since each class is visited individually
  2085     /**************************************************************************
  2086      * main method
  2087      *************************************************************************/
  2089         /** Perform definite assignment/unassignment analysis on a tree.
  2090          */
  2091         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2092             analyzeTree(env, env.tree, make);
  2095         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2096             try {
  2097                 attrEnv = env;
  2098                 Flow.this.make = make;
  2099                 startPos = tree.pos().getStartPosition();
  2100                 inits = new Bits();
  2101                 uninits = new Bits();
  2102                 uninitsTry = new Bits();
  2103                 initsWhenTrue = initsWhenFalse =
  2104                     uninitsWhenTrue = uninitsWhenFalse = null;
  2105                 if (vars == null)
  2106                     vars = new VarSymbol[32];
  2107                 else
  2108                     for (int i=0; i<vars.length; i++)
  2109                         vars[i] = null;
  2110                 firstadr = 0;
  2111                 nextadr = 0;
  2112                 pendingExits = new ListBuffer<AssignPendingExit>();
  2113                 this.classDef = null;
  2114                 unrefdResources = new Scope(env.enclClass.sym);
  2115                 scan(tree);
  2116             } finally {
  2117                 // note that recursive invocations of this method fail hard
  2118                 startPos = -1;
  2119                 inits = uninits = uninitsTry = null;
  2120                 initsWhenTrue = initsWhenFalse =
  2121                     uninitsWhenTrue = uninitsWhenFalse = null;
  2122                 if (vars != null) for (int i=0; i<vars.length; i++)
  2123                     vars[i] = null;
  2124                 firstadr = 0;
  2125                 nextadr = 0;
  2126                 pendingExits = null;
  2127                 Flow.this.make = null;
  2128                 this.classDef = null;
  2129                 unrefdResources = null;
  2134     /**
  2135      * This pass implements the last step of the dataflow analysis, namely
  2136      * the effectively-final analysis check. This checks that every local variable
  2137      * reference from a lambda body/local inner class is either final or effectively final.
  2138      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2139      * AssignAnalyzer.
  2140      */
  2141     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
  2143         JCTree currentTree; //local class or lambda
  2145         @Override
  2146         void markDead() {
  2147             //do nothing
  2150         @SuppressWarnings("fallthrough")
  2151         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
  2152             if (currentTree != null &&
  2153                     sym.owner.kind == MTH &&
  2154                     sym.pos < currentTree.getStartPosition()) {
  2155                 switch (currentTree.getTag()) {
  2156                     case CLASSDEF:
  2157                         if (!allowEffectivelyFinalInInnerClasses) {
  2158                             if ((sym.flags() & FINAL) == 0) {
  2159                                 reportInnerClsNeedsFinalError(pos, sym);
  2161                             break;
  2163                     case LAMBDA:
  2164                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
  2165                            reportEffectivelyFinalError(pos, sym);
  2171         @SuppressWarnings("fallthrough")
  2172         void letInit(JCTree tree) {
  2173             tree = TreeInfo.skipParens(tree);
  2174             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  2175                 Symbol sym = TreeInfo.symbol(tree);
  2176                 if (currentTree != null &&
  2177                         sym.kind == VAR &&
  2178                         sym.owner.kind == MTH &&
  2179                         ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
  2180                     switch (currentTree.getTag()) {
  2181                         case CLASSDEF:
  2182                             if (!allowEffectivelyFinalInInnerClasses) {
  2183                                 reportInnerClsNeedsFinalError(tree, sym);
  2184                                 break;
  2186                         case LAMBDA:
  2187                             reportEffectivelyFinalError(tree, sym);
  2193         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
  2194             String subKey = currentTree.hasTag(LAMBDA) ?
  2195                   "lambda"  : "inner.cls";
  2196             log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
  2199         void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
  2200             log.error(pos,
  2201                     "local.var.accessed.from.icls.needs.final",
  2202                     sym);
  2205     /*************************************************************************
  2206      * Visitor methods for statements and definitions
  2207      *************************************************************************/
  2209         /* ------------ Visitor methods for various sorts of trees -------------*/
  2211         public void visitClassDef(JCClassDecl tree) {
  2212             JCTree prevTree = currentTree;
  2213             try {
  2214                 currentTree = tree.sym.isLocal() ? tree : null;
  2215                 super.visitClassDef(tree);
  2216             } finally {
  2217                 currentTree = prevTree;
  2221         @Override
  2222         public void visitLambda(JCLambda tree) {
  2223             JCTree prevTree = currentTree;
  2224             try {
  2225                 currentTree = tree;
  2226                 super.visitLambda(tree);
  2227             } finally {
  2228                 currentTree = prevTree;
  2232         @Override
  2233         public void visitIdent(JCIdent tree) {
  2234             if (tree.sym.kind == VAR) {
  2235                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
  2239         public void visitAssign(JCAssign tree) {
  2240             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2241             if (!(lhs instanceof JCIdent)) {
  2242                 scan(lhs);
  2244             scan(tree.rhs);
  2245             letInit(lhs);
  2248         public void visitAssignop(JCAssignOp tree) {
  2249             scan(tree.lhs);
  2250             scan(tree.rhs);
  2251             letInit(tree.lhs);
  2254         public void visitUnary(JCUnary tree) {
  2255             switch (tree.getTag()) {
  2256                 case PREINC: case POSTINC:
  2257                 case PREDEC: case POSTDEC:
  2258                     scan(tree.arg);
  2259                     letInit(tree.arg);
  2260                     break;
  2261                 default:
  2262                     scan(tree.arg);
  2266         public void visitTopLevel(JCCompilationUnit tree) {
  2267             // Do nothing for TopLevel since each class is visited individually
  2270     /**************************************************************************
  2271      * main method
  2272      *************************************************************************/
  2274         /** Perform definite assignment/unassignment analysis on a tree.
  2275          */
  2276         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2277             analyzeTree(env, env.tree, make);
  2279         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2280             try {
  2281                 attrEnv = env;
  2282                 Flow.this.make = make;
  2283                 pendingExits = new ListBuffer<PendingExit>();
  2284                 scan(tree);
  2285             } finally {
  2286                 pendingExits = null;
  2287                 Flow.this.make = null;

mercurial