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

Wed, 06 Apr 2011 19:30:57 -0700

author
darcy
date
Wed, 06 Apr 2011 19:30:57 -0700
changeset 969
8cc5b440fdde
parent 935
5b29f2a85085
child 972
694ff82ca68e
permissions
-rw-r--r--

7033809: Rename "disjunctive" to "union" in javax.lang.model
Reviewed-by: mcimadamore, jjg

     1 /*
     2  * Copyright (c) 1999, 2011, 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;
    31 import java.util.Map;
    32 import java.util.LinkedHashMap;
    34 import com.sun.tools.javac.code.*;
    35 import com.sun.tools.javac.tree.*;
    36 import com.sun.tools.javac.util.*;
    37 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    39 import com.sun.tools.javac.code.Symbol.*;
    40 import com.sun.tools.javac.tree.JCTree.*;
    42 import static com.sun.tools.javac.code.Flags.*;
    43 import static com.sun.tools.javac.code.Kinds.*;
    44 import static com.sun.tools.javac.code.TypeTags.*;
    46 /** This pass implements dataflow analysis for Java programs.
    47  *  Liveness analysis checks that every statement is reachable.
    48  *  Exception analysis ensures that every checked exception that is
    49  *  thrown is declared or caught.  Definite assignment analysis
    50  *  ensures that each variable is assigned when used.  Definite
    51  *  unassignment analysis ensures that no final variable is assigned
    52  *  more than once.
    53  *
    54  *  <p>The second edition of the JLS has a number of problems in the
    55  *  specification of these flow analysis problems. This implementation
    56  *  attempts to address those issues.
    57  *
    58  *  <p>First, there is no accommodation for a finally clause that cannot
    59  *  complete normally. For liveness analysis, an intervening finally
    60  *  clause can cause a break, continue, or return not to reach its
    61  *  target.  For exception analysis, an intervening finally clause can
    62  *  cause any exception to be "caught".  For DA/DU analysis, the finally
    63  *  clause can prevent a transfer of control from propagating DA/DU
    64  *  state to the target.  In addition, code in the finally clause can
    65  *  affect the DA/DU status of variables.
    66  *
    67  *  <p>For try statements, we introduce the idea of a variable being
    68  *  definitely unassigned "everywhere" in a block.  A variable V is
    69  *  "unassigned everywhere" in a block iff it is unassigned at the
    70  *  beginning of the block and there is no reachable assignment to V
    71  *  in the block.  An assignment V=e is reachable iff V is not DA
    72  *  after e.  Then we can say that V is DU at the beginning of the
    73  *  catch block iff V is DU everywhere in the try block.  Similarly, V
    74  *  is DU at the beginning of the finally block iff V is DU everywhere
    75  *  in the try block and in every catch block.  Specifically, the
    76  *  following bullet is added to 16.2.2
    77  *  <pre>
    78  *      V is <em>unassigned everywhere</em> in a block if it is
    79  *      unassigned before the block and there is no reachable
    80  *      assignment to V within the block.
    81  *  </pre>
    82  *  <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all
    83  *  try blocks is changed to
    84  *  <pre>
    85  *      V is definitely unassigned before a catch block iff V is
    86  *      definitely unassigned everywhere in the try block.
    87  *  </pre>
    88  *  <p>The last bullet (and all of its sub-bullets) for try blocks that
    89  *  have a finally block is changed to
    90  *  <pre>
    91  *      V is definitely unassigned before the finally block iff
    92  *      V is definitely unassigned everywhere in the try block
    93  *      and everywhere in each catch block of the try statement.
    94  *  </pre>
    95  *  <p>In addition,
    96  *  <pre>
    97  *      V is definitely assigned at the end of a constructor iff
    98  *      V is definitely assigned after the block that is the body
    99  *      of the constructor and V is definitely assigned at every
   100  *      return that can return from the constructor.
   101  *  </pre>
   102  *  <p>In addition, each continue statement with the loop as its target
   103  *  is treated as a jump to the end of the loop body, and "intervening"
   104  *  finally clauses are treated as follows: V is DA "due to the
   105  *  continue" iff V is DA before the continue statement or V is DA at
   106  *  the end of any intervening finally block.  V is DU "due to the
   107  *  continue" iff any intervening finally cannot complete normally or V
   108  *  is DU at the end of every intervening finally block.  This "due to
   109  *  the continue" concept is then used in the spec for the loops.
   110  *
   111  *  <p>Similarly, break statements must consider intervening finally
   112  *  blocks.  For liveness analysis, a break statement for which any
   113  *  intervening finally cannot complete normally is not considered to
   114  *  cause the target statement to be able to complete normally. Then
   115  *  we say V is DA "due to the break" iff V is DA before the break or
   116  *  V is DA at the end of any intervening finally block.  V is DU "due
   117  *  to the break" iff any intervening finally cannot complete normally
   118  *  or V is DU at the break and at the end of every intervening
   119  *  finally block.  (I suspect this latter condition can be
   120  *  simplified.)  This "due to the break" is then used in the spec for
   121  *  all statements that can be "broken".
   122  *
   123  *  <p>The return statement is treated similarly.  V is DA "due to a
   124  *  return statement" iff V is DA before the return statement or V is
   125  *  DA at the end of any intervening finally block.  Note that we
   126  *  don't have to worry about the return expression because this
   127  *  concept is only used for construcrors.
   128  *
   129  *  <p>There is no spec in JLS2 for when a variable is definitely
   130  *  assigned at the end of a constructor, which is needed for final
   131  *  fields (8.3.1.2).  We implement the rule that V is DA at the end
   132  *  of the constructor iff it is DA and the end of the body of the
   133  *  constructor and V is DA "due to" every return of the constructor.
   134  *
   135  *  <p>Intervening finally blocks similarly affect exception analysis.  An
   136  *  intervening finally that cannot complete normally allows us to ignore
   137  *  an otherwise uncaught exception.
   138  *
   139  *  <p>To implement the semantics of intervening finally clauses, all
   140  *  nonlocal transfers (break, continue, return, throw, method call that
   141  *  can throw a checked exception, and a constructor invocation that can
   142  *  thrown a checked exception) are recorded in a queue, and removed
   143  *  from the queue when we complete processing the target of the
   144  *  nonlocal transfer.  This allows us to modify the queue in accordance
   145  *  with the above rules when we encounter a finally clause.  The only
   146  *  exception to this [no pun intended] is that checked exceptions that
   147  *  are known to be caught or declared to be caught in the enclosing
   148  *  method are not recorded in the queue, but instead are recorded in a
   149  *  global variable "Set<Type> thrown" that records the type of all
   150  *  exceptions that can be thrown.
   151  *
   152  *  <p>Other minor issues the treatment of members of other classes
   153  *  (always considered DA except that within an anonymous class
   154  *  constructor, where DA status from the enclosing scope is
   155  *  preserved), treatment of the case expression (V is DA before the
   156  *  case expression iff V is DA after the switch expression),
   157  *  treatment of variables declared in a switch block (the implied
   158  *  DA/DU status after the switch expression is DU and not DA for
   159  *  variables defined in a switch block), the treatment of boolean ?:
   160  *  expressions (The JLS rules only handle b and c non-boolean; the
   161  *  new rule is that if b and c are boolean valued, then V is
   162  *  (un)assigned after a?b:c when true/false iff V is (un)assigned
   163  *  after b when true/false and V is (un)assigned after c when
   164  *  true/false).
   165  *
   166  *  <p>There is the remaining question of what syntactic forms constitute a
   167  *  reference to a variable.  It is conventional to allow this.x on the
   168  *  left-hand-side to initialize a final instance field named x, yet
   169  *  this.x isn't considered a "use" when appearing on a right-hand-side
   170  *  in most implementations.  Should parentheses affect what is
   171  *  considered a variable reference?  The simplest rule would be to
   172  *  allow unqualified forms only, parentheses optional, and phase out
   173  *  support for assigning to a final field via this.x.
   174  *
   175  *  <p><b>This is NOT part of any supported API.
   176  *  If you write code that depends on this, you do so at your own risk.
   177  *  This code and its internal interfaces are subject to change or
   178  *  deletion without notice.</b>
   179  */
   180 public class Flow extends TreeScanner {
   181     protected static final Context.Key<Flow> flowKey =
   182         new Context.Key<Flow>();
   184     private final Names names;
   185     private final Log log;
   186     private final Symtab syms;
   187     private final Types types;
   188     private final Check chk;
   189     private       TreeMaker make;
   190     private final Resolve rs;
   191     private Env<AttrContext> attrEnv;
   192     private       Lint lint;
   193     private final boolean allowImprovedRethrowAnalysis;
   194     private final boolean allowImprovedCatchAnalysis;
   196     public static Flow instance(Context context) {
   197         Flow instance = context.get(flowKey);
   198         if (instance == null)
   199             instance = new Flow(context);
   200         return instance;
   201     }
   203     protected Flow(Context context) {
   204         context.put(flowKey, this);
   205         names = Names.instance(context);
   206         log = Log.instance(context);
   207         syms = Symtab.instance(context);
   208         types = Types.instance(context);
   209         chk = Check.instance(context);
   210         lint = Lint.instance(context);
   211         rs = Resolve.instance(context);
   212         Source source = Source.instance(context);
   213         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   214         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   215     }
   217     /** A flag that indicates whether the last statement could
   218      *  complete normally.
   219      */
   220     private boolean alive;
   222     /** The set of definitely assigned variables.
   223      */
   224     Bits inits;
   226     /** The set of definitely unassigned variables.
   227      */
   228     Bits uninits;
   230     HashMap<Symbol, List<Type>> preciseRethrowTypes;
   232     /** The set of variables that are definitely unassigned everywhere
   233      *  in current try block. This variable is maintained lazily; it is
   234      *  updated only when something gets removed from uninits,
   235      *  typically by being assigned in reachable code.  To obtain the
   236      *  correct set of variables which are definitely unassigned
   237      *  anywhere in current try block, intersect uninitsTry and
   238      *  uninits.
   239      */
   240     Bits uninitsTry;
   242     /** When analyzing a condition, inits and uninits are null.
   243      *  Instead we have:
   244      */
   245     Bits initsWhenTrue;
   246     Bits initsWhenFalse;
   247     Bits uninitsWhenTrue;
   248     Bits uninitsWhenFalse;
   250     /** A mapping from addresses to variable symbols.
   251      */
   252     VarSymbol[] vars;
   254     /** The current class being defined.
   255      */
   256     JCClassDecl classDef;
   258     /** The first variable sequence number in this class definition.
   259      */
   260     int firstadr;
   262     /** The next available variable sequence number.
   263      */
   264     int nextadr;
   266     /** The list of possibly thrown declarable exceptions.
   267      */
   268     List<Type> thrown;
   270     /** The list of exceptions that are either caught or declared to be
   271      *  thrown.
   272      */
   273     List<Type> caught;
   275     /** The list of unreferenced automatic resources.
   276      */
   277     Scope unrefdResources;
   279     /** Set when processing a loop body the second time for DU analysis. */
   280     boolean loopPassTwo = false;
   282     /*-------------------- Environments ----------------------*/
   284     /** A pending exit.  These are the statements return, break, and
   285      *  continue.  In addition, exception-throwing expressions or
   286      *  statements are put here when not known to be caught.  This
   287      *  will typically result in an error unless it is within a
   288      *  try-finally whose finally block cannot complete normally.
   289      */
   290     static class PendingExit {
   291         JCTree tree;
   292         Bits inits;
   293         Bits uninits;
   294         Type thrown;
   295         PendingExit(JCTree tree, Bits inits, Bits uninits) {
   296             this.tree = tree;
   297             this.inits = inits.dup();
   298             this.uninits = uninits.dup();
   299         }
   300         PendingExit(JCTree tree, Type thrown) {
   301             this.tree = tree;
   302             this.thrown = thrown;
   303         }
   304     }
   306     /** The currently pending exits that go from current inner blocks
   307      *  to an enclosing block, in source order.
   308      */
   309     ListBuffer<PendingExit> pendingExits;
   311     /*-------------------- Exceptions ----------------------*/
   313     /** Complain that pending exceptions are not caught.
   314      */
   315     void errorUncaught() {
   316         for (PendingExit exit = pendingExits.next();
   317              exit != null;
   318              exit = pendingExits.next()) {
   319             if (classDef != null &&
   320                 classDef.pos == exit.tree.pos) {
   321                 log.error(exit.tree.pos(),
   322                         "unreported.exception.default.constructor",
   323                         exit.thrown);
   324             } else if (exit.tree.getTag() == JCTree.VARDEF &&
   325                     ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   326                 log.error(exit.tree.pos(),
   327                         "unreported.exception.implicit.close",
   328                         exit.thrown,
   329                         ((JCVariableDecl)exit.tree).sym.name);
   330             } else {
   331                 log.error(exit.tree.pos(),
   332                         "unreported.exception.need.to.catch.or.throw",
   333                         exit.thrown);
   334             }
   335         }
   336     }
   338     /** Record that exception is potentially thrown and check that it
   339      *  is caught.
   340      */
   341     void markThrown(JCTree tree, Type exc) {
   342         if (!chk.isUnchecked(tree.pos(), exc)) {
   343             if (!chk.isHandled(exc, caught))
   344                 pendingExits.append(new PendingExit(tree, exc));
   345                 thrown = chk.incl(exc, thrown);
   346         }
   347     }
   349     /*-------------- Processing variables ----------------------*/
   351     /** Do we need to track init/uninit state of this symbol?
   352      *  I.e. is symbol either a local or a blank final variable?
   353      */
   354     boolean trackable(VarSymbol sym) {
   355         return
   356             (sym.owner.kind == MTH ||
   357              ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
   358               classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)));
   359     }
   361     /** Initialize new trackable variable by setting its address field
   362      *  to the next available sequence number and entering it under that
   363      *  index into the vars array.
   364      */
   365     void newVar(VarSymbol sym) {
   366         if (nextadr == vars.length) {
   367             VarSymbol[] newvars = new VarSymbol[nextadr * 2];
   368             System.arraycopy(vars, 0, newvars, 0, nextadr);
   369             vars = newvars;
   370         }
   371         sym.adr = nextadr;
   372         vars[nextadr] = sym;
   373         inits.excl(nextadr);
   374         uninits.incl(nextadr);
   375         nextadr++;
   376     }
   378     /** Record an initialization of a trackable variable.
   379      */
   380     void letInit(DiagnosticPosition pos, VarSymbol sym) {
   381         if (sym.adr >= firstadr && trackable(sym)) {
   382             if ((sym.flags() & FINAL) != 0) {
   383                 if ((sym.flags() & PARAMETER) != 0) {
   384                     if ((sym.flags() & UNION) != 0) { //multi-catch parameter
   385                         log.error(pos, "multicatch.parameter.may.not.be.assigned",
   386                                   sym);
   387                     }
   388                     else {
   389                         log.error(pos, "final.parameter.may.not.be.assigned",
   390                               sym);
   391                     }
   392                 } else if (!uninits.isMember(sym.adr)) {
   393                     log.error(pos,
   394                               loopPassTwo
   395                               ? "var.might.be.assigned.in.loop"
   396                               : "var.might.already.be.assigned",
   397                               sym);
   398                 } else if (!inits.isMember(sym.adr)) {
   399                     // reachable assignment
   400                     uninits.excl(sym.adr);
   401                     uninitsTry.excl(sym.adr);
   402                 } else {
   403                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
   404                     uninits.excl(sym.adr);
   405                 }
   406             }
   407             inits.incl(sym.adr);
   408         } else if ((sym.flags() & FINAL) != 0) {
   409             log.error(pos, "var.might.already.be.assigned", sym);
   410         }
   411     }
   413     /** If tree is either a simple name or of the form this.name or
   414      *  C.this.name, and tree represents a trackable variable,
   415      *  record an initialization of the variable.
   416      */
   417     void letInit(JCTree tree) {
   418         tree = TreeInfo.skipParens(tree);
   419         if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) {
   420             Symbol sym = TreeInfo.symbol(tree);
   421             if (sym.kind == VAR) {
   422                 letInit(tree.pos(), (VarSymbol)sym);
   423             }
   424         }
   425     }
   427     /** Check that trackable variable is initialized.
   428      */
   429     void checkInit(DiagnosticPosition pos, VarSymbol sym) {
   430         if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
   431             trackable(sym) &&
   432             !inits.isMember(sym.adr)) {
   433             log.error(pos, "var.might.not.have.been.initialized",
   434                       sym);
   435             inits.incl(sym.adr);
   436         }
   437     }
   439     /*-------------------- Handling jumps ----------------------*/
   441     /** Record an outward transfer of control. */
   442     void recordExit(JCTree tree) {
   443         pendingExits.append(new PendingExit(tree, inits, uninits));
   444         markDead();
   445     }
   447     /** Resolve all breaks of this statement. */
   448     boolean resolveBreaks(JCTree tree,
   449                           ListBuffer<PendingExit> oldPendingExits) {
   450         boolean result = false;
   451         List<PendingExit> exits = pendingExits.toList();
   452         pendingExits = oldPendingExits;
   453         for (; exits.nonEmpty(); exits = exits.tail) {
   454             PendingExit exit = exits.head;
   455             if (exit.tree.getTag() == JCTree.BREAK &&
   456                 ((JCBreak) exit.tree).target == tree) {
   457                 inits.andSet(exit.inits);
   458                 uninits.andSet(exit.uninits);
   459                 result = true;
   460             } else {
   461                 pendingExits.append(exit);
   462             }
   463         }
   464         return result;
   465     }
   467     /** Resolve all continues of this statement. */
   468     boolean resolveContinues(JCTree tree) {
   469         boolean result = false;
   470         List<PendingExit> exits = pendingExits.toList();
   471         pendingExits = new ListBuffer<PendingExit>();
   472         for (; exits.nonEmpty(); exits = exits.tail) {
   473             PendingExit exit = exits.head;
   474             if (exit.tree.getTag() == JCTree.CONTINUE &&
   475                 ((JCContinue) exit.tree).target == tree) {
   476                 inits.andSet(exit.inits);
   477                 uninits.andSet(exit.uninits);
   478                 result = true;
   479             } else {
   480                 pendingExits.append(exit);
   481             }
   482         }
   483         return result;
   484     }
   486     /** Record that statement is unreachable.
   487      */
   488     void markDead() {
   489         inits.inclRange(firstadr, nextadr);
   490         uninits.inclRange(firstadr, nextadr);
   491         alive = false;
   492     }
   494     /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
   495      */
   496     void split(boolean setToNull) {
   497         initsWhenFalse = inits.dup();
   498         uninitsWhenFalse = uninits.dup();
   499         initsWhenTrue = inits;
   500         uninitsWhenTrue = uninits;
   501         if (setToNull)
   502             inits = uninits = null;
   503     }
   505     /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
   506      */
   507     void merge() {
   508         inits = initsWhenFalse.andSet(initsWhenTrue);
   509         uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
   510     }
   512 /* ************************************************************************
   513  * Visitor methods for statements and definitions
   514  *************************************************************************/
   516     /** Analyze a definition.
   517      */
   518     void scanDef(JCTree tree) {
   519         scanStat(tree);
   520         if (tree != null && tree.getTag() == JCTree.BLOCK && !alive) {
   521             log.error(tree.pos(),
   522                       "initializer.must.be.able.to.complete.normally");
   523         }
   524     }
   526     /** Analyze a statement. Check that statement is reachable.
   527      */
   528     void scanStat(JCTree tree) {
   529         if (!alive && tree != null) {
   530             log.error(tree.pos(), "unreachable.stmt");
   531             if (tree.getTag() != JCTree.SKIP) alive = true;
   532         }
   533         scan(tree);
   534     }
   536     /** Analyze list of statements.
   537      */
   538     void scanStats(List<? extends JCStatement> trees) {
   539         if (trees != null)
   540             for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
   541                 scanStat(l.head);
   542     }
   544     /** Analyze an expression. Make sure to set (un)inits rather than
   545      *  (un)initsWhenTrue(WhenFalse) on exit.
   546      */
   547     void scanExpr(JCTree tree) {
   548         if (tree != null) {
   549             scan(tree);
   550             if (inits == null) merge();
   551         }
   552     }
   554     /** Analyze a list of expressions.
   555      */
   556     void scanExprs(List<? extends JCExpression> trees) {
   557         if (trees != null)
   558             for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
   559                 scanExpr(l.head);
   560     }
   562     /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
   563      *  rather than (un)inits on exit.
   564      */
   565     void scanCond(JCTree tree) {
   566         if (tree.type.isFalse()) {
   567             if (inits == null) merge();
   568             initsWhenTrue = inits.dup();
   569             initsWhenTrue.inclRange(firstadr, nextadr);
   570             uninitsWhenTrue = uninits.dup();
   571             uninitsWhenTrue.inclRange(firstadr, nextadr);
   572             initsWhenFalse = inits;
   573             uninitsWhenFalse = uninits;
   574         } else if (tree.type.isTrue()) {
   575             if (inits == null) merge();
   576             initsWhenFalse = inits.dup();
   577             initsWhenFalse.inclRange(firstadr, nextadr);
   578             uninitsWhenFalse = uninits.dup();
   579             uninitsWhenFalse.inclRange(firstadr, nextadr);
   580             initsWhenTrue = inits;
   581             uninitsWhenTrue = uninits;
   582         } else {
   583             scan(tree);
   584             if (inits != null)
   585                 split(tree.type != syms.unknownType);
   586         }
   587         if (tree.type != syms.unknownType)
   588             inits = uninits = null;
   589     }
   591     /* ------------ Visitor methods for various sorts of trees -------------*/
   593     public void visitClassDef(JCClassDecl tree) {
   594         if (tree.sym == null) return;
   596         JCClassDecl classDefPrev = classDef;
   597         List<Type> thrownPrev = thrown;
   598         List<Type> caughtPrev = caught;
   599         boolean alivePrev = alive;
   600         int firstadrPrev = firstadr;
   601         int nextadrPrev = nextadr;
   602         ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   603         Lint lintPrev = lint;
   605         pendingExits = new ListBuffer<PendingExit>();
   606         if (tree.name != names.empty) {
   607             caught = List.nil();
   608             firstadr = nextadr;
   609         }
   610         classDef = tree;
   611         thrown = List.nil();
   612         lint = lint.augment(tree.sym.attributes_field);
   614         try {
   615             // define all the static fields
   616             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   617                 if (l.head.getTag() == JCTree.VARDEF) {
   618                     JCVariableDecl def = (JCVariableDecl)l.head;
   619                     if ((def.mods.flags & STATIC) != 0) {
   620                         VarSymbol sym = def.sym;
   621                         if (trackable(sym))
   622                             newVar(sym);
   623                     }
   624                 }
   625             }
   627             // process all the static initializers
   628             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   629                 if (l.head.getTag() != JCTree.METHODDEF &&
   630                     (TreeInfo.flags(l.head) & STATIC) != 0) {
   631                     scanDef(l.head);
   632                     errorUncaught();
   633                 }
   634             }
   636             // add intersection of all thrown clauses of initial constructors
   637             // to set of caught exceptions, unless class is anonymous.
   638             if (tree.name != names.empty) {
   639                 boolean firstConstructor = true;
   640                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   641                     if (TreeInfo.isInitialConstructor(l.head)) {
   642                         List<Type> mthrown =
   643                             ((JCMethodDecl) l.head).sym.type.getThrownTypes();
   644                         if (firstConstructor) {
   645                             caught = mthrown;
   646                             firstConstructor = false;
   647                         } else {
   648                             caught = chk.intersect(mthrown, caught);
   649                         }
   650                     }
   651                 }
   652             }
   654             // define all the instance fields
   655             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   656                 if (l.head.getTag() == JCTree.VARDEF) {
   657                     JCVariableDecl def = (JCVariableDecl)l.head;
   658                     if ((def.mods.flags & STATIC) == 0) {
   659                         VarSymbol sym = def.sym;
   660                         if (trackable(sym))
   661                             newVar(sym);
   662                     }
   663                 }
   664             }
   666             // process all the instance initializers
   667             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   668                 if (l.head.getTag() != JCTree.METHODDEF &&
   669                     (TreeInfo.flags(l.head) & STATIC) == 0) {
   670                     scanDef(l.head);
   671                     errorUncaught();
   672                 }
   673             }
   675             // in an anonymous class, add the set of thrown exceptions to
   676             // the throws clause of the synthetic constructor and propagate
   677             // outwards.
   678             // Changing the throws clause on the fly is okay here because
   679             // the anonymous constructor can't be invoked anywhere else,
   680             // and its type hasn't been cached.
   681             if (tree.name == names.empty) {
   682                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   683                     if (TreeInfo.isInitialConstructor(l.head)) {
   684                         JCMethodDecl mdef = (JCMethodDecl)l.head;
   685                         mdef.thrown = make.Types(thrown);
   686                         mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
   687                     }
   688                 }
   689                 thrownPrev = chk.union(thrown, thrownPrev);
   690             }
   692             // process all the methods
   693             for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   694                 if (l.head.getTag() == JCTree.METHODDEF) {
   695                     scan(l.head);
   696                     errorUncaught();
   697                 }
   698             }
   700             thrown = thrownPrev;
   701         } finally {
   702             pendingExits = pendingExitsPrev;
   703             alive = alivePrev;
   704             nextadr = nextadrPrev;
   705             firstadr = firstadrPrev;
   706             caught = caughtPrev;
   707             classDef = classDefPrev;
   708             lint = lintPrev;
   709         }
   710     }
   712     public void visitMethodDef(JCMethodDecl tree) {
   713         if (tree.body == null) return;
   715         List<Type> caughtPrev = caught;
   716         List<Type> mthrown = tree.sym.type.getThrownTypes();
   717         Bits initsPrev = inits.dup();
   718         Bits uninitsPrev = uninits.dup();
   719         int nextadrPrev = nextadr;
   720         int firstadrPrev = firstadr;
   721         Lint lintPrev = lint;
   723         lint = lint.augment(tree.sym.attributes_field);
   725         Assert.check(pendingExits.isEmpty());
   727         try {
   728             boolean isInitialConstructor =
   729                 TreeInfo.isInitialConstructor(tree);
   731             if (!isInitialConstructor)
   732                 firstadr = nextadr;
   733             for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   734                 JCVariableDecl def = l.head;
   735                 scan(def);
   736                 inits.incl(def.sym.adr);
   737                 uninits.excl(def.sym.adr);
   738             }
   739             if (isInitialConstructor)
   740                 caught = chk.union(caught, mthrown);
   741             else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   742                 caught = mthrown;
   743             // else we are in an instance initializer block;
   744             // leave caught unchanged.
   746             alive = true;
   747             scanStat(tree.body);
   749             if (alive && tree.sym.type.getReturnType().tag != VOID)
   750                 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   752             if (isInitialConstructor) {
   753                 for (int i = firstadr; i < nextadr; i++)
   754                     if (vars[i].owner == classDef.sym)
   755                         checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
   756             }
   757             List<PendingExit> exits = pendingExits.toList();
   758             pendingExits = new ListBuffer<PendingExit>();
   759             while (exits.nonEmpty()) {
   760                 PendingExit exit = exits.head;
   761                 exits = exits.tail;
   762                 if (exit.thrown == null) {
   763                     Assert.check(exit.tree.getTag() == JCTree.RETURN);
   764                     if (isInitialConstructor) {
   765                         inits = exit.inits;
   766                         for (int i = firstadr; i < nextadr; i++)
   767                             checkInit(exit.tree.pos(), vars[i]);
   768                     }
   769                 } else {
   770                     // uncaught throws will be reported later
   771                     pendingExits.append(exit);
   772                 }
   773             }
   774         } finally {
   775             inits = initsPrev;
   776             uninits = uninitsPrev;
   777             nextadr = nextadrPrev;
   778             firstadr = firstadrPrev;
   779             caught = caughtPrev;
   780             lint = lintPrev;
   781         }
   782     }
   784     public void visitVarDef(JCVariableDecl tree) {
   785         boolean track = trackable(tree.sym);
   786         if (track && tree.sym.owner.kind == MTH) newVar(tree.sym);
   787         if (tree.init != null) {
   788             Lint lintPrev = lint;
   789             lint = lint.augment(tree.sym.attributes_field);
   790             try{
   791                 scanExpr(tree.init);
   792                 if (track) letInit(tree.pos(), tree.sym);
   793             } finally {
   794                 lint = lintPrev;
   795             }
   796         }
   797     }
   799     public void visitBlock(JCBlock tree) {
   800         int nextadrPrev = nextadr;
   801         scanStats(tree.stats);
   802         nextadr = nextadrPrev;
   803     }
   805     public void visitDoLoop(JCDoWhileLoop tree) {
   806         ListBuffer<PendingExit> prevPendingExits = pendingExits;
   807         boolean prevLoopPassTwo = loopPassTwo;
   808         pendingExits = new ListBuffer<PendingExit>();
   809         int prevErrors = log.nerrors;
   810         do {
   811             Bits uninitsEntry = uninits.dup();
   812             uninitsEntry.excludeFrom(nextadr);
   813             scanStat(tree.body);
   814             alive |= resolveContinues(tree);
   815             scanCond(tree.cond);
   816             if (log.nerrors !=  prevErrors ||
   817                 loopPassTwo ||
   818                 uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
   819                 break;
   820             inits = initsWhenTrue;
   821             uninits = uninitsEntry.andSet(uninitsWhenTrue);
   822             loopPassTwo = true;
   823             alive = true;
   824         } while (true);
   825         loopPassTwo = prevLoopPassTwo;
   826         inits = initsWhenFalse;
   827         uninits = uninitsWhenFalse;
   828         alive = alive && !tree.cond.type.isTrue();
   829         alive |= resolveBreaks(tree, prevPendingExits);
   830     }
   832     public void visitWhileLoop(JCWhileLoop tree) {
   833         ListBuffer<PendingExit> prevPendingExits = pendingExits;
   834         boolean prevLoopPassTwo = loopPassTwo;
   835         Bits initsCond;
   836         Bits uninitsCond;
   837         pendingExits = new ListBuffer<PendingExit>();
   838         int prevErrors = log.nerrors;
   839         do {
   840             Bits uninitsEntry = uninits.dup();
   841             uninitsEntry.excludeFrom(nextadr);
   842             scanCond(tree.cond);
   843             initsCond = initsWhenFalse;
   844             uninitsCond = uninitsWhenFalse;
   845             inits = initsWhenTrue;
   846             uninits = uninitsWhenTrue;
   847             alive = !tree.cond.type.isFalse();
   848             scanStat(tree.body);
   849             alive |= resolveContinues(tree);
   850             if (log.nerrors != prevErrors ||
   851                 loopPassTwo ||
   852                 uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
   853                 break;
   854             uninits = uninitsEntry.andSet(uninits);
   855             loopPassTwo = true;
   856             alive = true;
   857         } while (true);
   858         loopPassTwo = prevLoopPassTwo;
   859         inits = initsCond;
   860         uninits = uninitsCond;
   861         alive = resolveBreaks(tree, prevPendingExits) ||
   862             !tree.cond.type.isTrue();
   863     }
   865     public void visitForLoop(JCForLoop tree) {
   866         ListBuffer<PendingExit> prevPendingExits = pendingExits;
   867         boolean prevLoopPassTwo = loopPassTwo;
   868         int nextadrPrev = nextadr;
   869         scanStats(tree.init);
   870         Bits initsCond;
   871         Bits uninitsCond;
   872         pendingExits = new ListBuffer<PendingExit>();
   873         int prevErrors = log.nerrors;
   874         do {
   875             Bits uninitsEntry = uninits.dup();
   876             uninitsEntry.excludeFrom(nextadr);
   877             if (tree.cond != null) {
   878                 scanCond(tree.cond);
   879                 initsCond = initsWhenFalse;
   880                 uninitsCond = uninitsWhenFalse;
   881                 inits = initsWhenTrue;
   882                 uninits = uninitsWhenTrue;
   883                 alive = !tree.cond.type.isFalse();
   884             } else {
   885                 initsCond = inits.dup();
   886                 initsCond.inclRange(firstadr, nextadr);
   887                 uninitsCond = uninits.dup();
   888                 uninitsCond.inclRange(firstadr, nextadr);
   889                 alive = true;
   890             }
   891             scanStat(tree.body);
   892             alive |= resolveContinues(tree);
   893             scan(tree.step);
   894             if (log.nerrors != prevErrors ||
   895                 loopPassTwo ||
   896                 uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
   897                 break;
   898             uninits = uninitsEntry.andSet(uninits);
   899             loopPassTwo = true;
   900             alive = true;
   901         } while (true);
   902         loopPassTwo = prevLoopPassTwo;
   903         inits = initsCond;
   904         uninits = uninitsCond;
   905         alive = resolveBreaks(tree, prevPendingExits) ||
   906             tree.cond != null && !tree.cond.type.isTrue();
   907         nextadr = nextadrPrev;
   908     }
   910     public void visitForeachLoop(JCEnhancedForLoop tree) {
   911         visitVarDef(tree.var);
   913         ListBuffer<PendingExit> prevPendingExits = pendingExits;
   914         boolean prevLoopPassTwo = loopPassTwo;
   915         int nextadrPrev = nextadr;
   916         scan(tree.expr);
   917         Bits initsStart = inits.dup();
   918         Bits uninitsStart = uninits.dup();
   920         letInit(tree.pos(), tree.var.sym);
   921         pendingExits = new ListBuffer<PendingExit>();
   922         int prevErrors = log.nerrors;
   923         do {
   924             Bits uninitsEntry = uninits.dup();
   925             uninitsEntry.excludeFrom(nextadr);
   926             scanStat(tree.body);
   927             alive |= resolveContinues(tree);
   928             if (log.nerrors != prevErrors ||
   929                 loopPassTwo ||
   930                 uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
   931                 break;
   932             uninits = uninitsEntry.andSet(uninits);
   933             loopPassTwo = true;
   934             alive = true;
   935         } while (true);
   936         loopPassTwo = prevLoopPassTwo;
   937         inits = initsStart;
   938         uninits = uninitsStart.andSet(uninits);
   939         resolveBreaks(tree, prevPendingExits);
   940         alive = true;
   941         nextadr = nextadrPrev;
   942     }
   944     public void visitLabelled(JCLabeledStatement tree) {
   945         ListBuffer<PendingExit> prevPendingExits = pendingExits;
   946         pendingExits = new ListBuffer<PendingExit>();
   947         scanStat(tree.body);
   948         alive |= resolveBreaks(tree, prevPendingExits);
   949     }
   951     public void visitSwitch(JCSwitch tree) {
   952         ListBuffer<PendingExit> prevPendingExits = pendingExits;
   953         pendingExits = new ListBuffer<PendingExit>();
   954         int nextadrPrev = nextadr;
   955         scanExpr(tree.selector);
   956         Bits initsSwitch = inits;
   957         Bits uninitsSwitch = uninits.dup();
   958         boolean hasDefault = false;
   959         for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   960             alive = true;
   961             inits = initsSwitch.dup();
   962             uninits = uninits.andSet(uninitsSwitch);
   963             JCCase c = l.head;
   964             if (c.pat == null)
   965                 hasDefault = true;
   966             else
   967                 scanExpr(c.pat);
   968             scanStats(c.stats);
   969             addVars(c.stats, initsSwitch, uninitsSwitch);
   970             // Warn about fall-through if lint switch fallthrough enabled.
   971             if (!loopPassTwo &&
   972                 alive &&
   973                 lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   974                 c.stats.nonEmpty() && l.tail.nonEmpty())
   975                 log.warning(Lint.LintCategory.FALLTHROUGH,
   976                             l.tail.head.pos(),
   977                             "possible.fall-through.into.case");
   978         }
   979         if (!hasDefault) {
   980             inits.andSet(initsSwitch);
   981             alive = true;
   982         }
   983         alive |= resolveBreaks(tree, prevPendingExits);
   984         nextadr = nextadrPrev;
   985     }
   986     // where
   987         /** Add any variables defined in stats to inits and uninits. */
   988         private static void addVars(List<JCStatement> stats, Bits inits,
   989                                     Bits uninits) {
   990             for (;stats.nonEmpty(); stats = stats.tail) {
   991                 JCTree stat = stats.head;
   992                 if (stat.getTag() == JCTree.VARDEF) {
   993                     int adr = ((JCVariableDecl) stat).sym.adr;
   994                     inits.excl(adr);
   995                     uninits.incl(adr);
   996                 }
   997             }
   998         }
  1000     public void visitTry(JCTry tree) {
  1001         List<Type> caughtPrev = caught;
  1002         List<Type> thrownPrev = thrown;
  1003         thrown = List.nil();
  1004         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1005             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1006                     ((JCTypeUnion)l.head.param.vartype).alternatives :
  1007                     List.of(l.head.param.vartype);
  1008             for (JCExpression ct : subClauses) {
  1009                 caught = chk.incl(ct.type, caught);
  1012         ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
  1013         Bits uninitsTryPrev = uninitsTry;
  1014         ListBuffer<PendingExit> prevPendingExits = pendingExits;
  1015         pendingExits = new ListBuffer<PendingExit>();
  1016         Bits initsTry = inits.dup();
  1017         uninitsTry = uninits.dup();
  1018         for (JCTree resource : tree.resources) {
  1019             if (resource instanceof JCVariableDecl) {
  1020                 JCVariableDecl vdecl = (JCVariableDecl) resource;
  1021                 visitVarDef(vdecl);
  1022                 unrefdResources.enter(vdecl.sym);
  1023                 resourceVarDecls.append(vdecl);
  1024             } else if (resource instanceof JCExpression) {
  1025                 scanExpr((JCExpression) resource);
  1026             } else {
  1027                 throw new AssertionError(tree);  // parser error
  1030         for (JCTree resource : tree.resources) {
  1031             List<Type> closeableSupertypes = resource.type.isCompound() ?
  1032                 types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
  1033                 List.of(resource.type);
  1034             for (Type sup : closeableSupertypes) {
  1035                 if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
  1036                     Symbol closeMethod = rs.resolveQualifiedMethod(tree,
  1037                             attrEnv,
  1038                             sup,
  1039                             names.close,
  1040                             List.<Type>nil(),
  1041                             List.<Type>nil());
  1042                     if (closeMethod.kind == MTH) {
  1043                         for (Type t : ((MethodSymbol)closeMethod).getThrownTypes()) {
  1044                             markThrown(resource, t);
  1050         scanStat(tree.body);
  1051         List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1052             chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1053             thrown;
  1054         thrown = thrownPrev;
  1055         caught = caughtPrev;
  1056         boolean aliveEnd = alive;
  1057         uninitsTry.andSet(uninits);
  1058         Bits initsEnd = inits;
  1059         Bits uninitsEnd = uninits;
  1060         int nextadrCatch = nextadr;
  1062         if (!resourceVarDecls.isEmpty() &&
  1063                 lint.isEnabled(Lint.LintCategory.TRY)) {
  1064             for (JCVariableDecl resVar : resourceVarDecls) {
  1065                 if (unrefdResources.includes(resVar.sym)) {
  1066                     log.warning(Lint.LintCategory.TRY, resVar.pos(),
  1067                                 "try.resource.not.referenced", resVar.sym);
  1068                     unrefdResources.remove(resVar.sym);
  1073         List<Type> caughtInTry = List.nil();
  1074         for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1075             alive = true;
  1076             JCVariableDecl param = l.head.param;
  1077             List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1078                     ((JCTypeUnion)l.head.param.vartype).alternatives :
  1079                     List.of(l.head.param.vartype);
  1080             List<Type> ctypes = List.nil();
  1081             List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
  1082             for (JCExpression ct : subClauses) {
  1083                 Type exc = ct.type;
  1084                 if (exc != syms.unknownType) {
  1085                     ctypes = ctypes.append(exc);
  1086                     if (types.isSameType(exc, syms.objectType))
  1087                         continue;
  1088                     checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
  1089                     caughtInTry = chk.incl(exc, caughtInTry);
  1092             inits = initsTry.dup();
  1093             uninits = uninitsTry.dup();
  1094             scan(param);
  1095             inits.incl(param.sym.adr);
  1096             uninits.excl(param.sym.adr);
  1097             preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1098             scanStat(l.head.body);
  1099             initsEnd.andSet(inits);
  1100             uninitsEnd.andSet(uninits);
  1101             nextadr = nextadrCatch;
  1102             preciseRethrowTypes.remove(param.sym);
  1103             aliveEnd |= alive;
  1105         if (tree.finalizer != null) {
  1106             List<Type> savedThrown = thrown;
  1107             thrown = List.nil();
  1108             inits = initsTry.dup();
  1109             uninits = uninitsTry.dup();
  1110             ListBuffer<PendingExit> exits = pendingExits;
  1111             pendingExits = prevPendingExits;
  1112             alive = true;
  1113             scanStat(tree.finalizer);
  1114             if (!alive) {
  1115                 // discard exits and exceptions from try and finally
  1116                 thrown = chk.union(thrown, thrownPrev);
  1117                 if (!loopPassTwo &&
  1118                     lint.isEnabled(Lint.LintCategory.FINALLY)) {
  1119                     log.warning(Lint.LintCategory.FINALLY,
  1120                             TreeInfo.diagEndPos(tree.finalizer),
  1121                             "finally.cannot.complete");
  1123             } else {
  1124                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1125                 thrown = chk.union(thrown, savedThrown);
  1126                 uninits.andSet(uninitsEnd);
  1127                 // FIX: this doesn't preserve source order of exits in catch
  1128                 // versus finally!
  1129                 while (exits.nonEmpty()) {
  1130                     PendingExit exit = exits.next();
  1131                     if (exit.inits != null) {
  1132                         exit.inits.orSet(inits);
  1133                         exit.uninits.andSet(uninits);
  1135                     pendingExits.append(exit);
  1137                 inits.orSet(initsEnd);
  1138                 alive = aliveEnd;
  1140         } else {
  1141             thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1142             inits = initsEnd;
  1143             uninits = uninitsEnd;
  1144             alive = aliveEnd;
  1145             ListBuffer<PendingExit> exits = pendingExits;
  1146             pendingExits = prevPendingExits;
  1147             while (exits.nonEmpty()) pendingExits.append(exits.next());
  1149         uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  1152     void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1153         if (chk.subset(exc, caughtInTry)) {
  1154             log.error(pos, "except.already.caught", exc);
  1155         } else if (!chk.isUnchecked(pos, exc) &&
  1156                 exc.tsym != syms.throwableType.tsym &&
  1157                 exc.tsym != syms.exceptionType.tsym &&
  1158                 !chk.intersects(exc, thrownInTry)) {
  1159             log.error(pos, "except.never.thrown.in.try", exc);
  1160         } else if (allowImprovedCatchAnalysis) {
  1161             List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
  1162             // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
  1163             // unchecked exception, the result list would not be empty, as the augmented
  1164             // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
  1165             // exception, that would have been covered in the branch above
  1166             if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty()) {
  1167                 String key = catchableThrownTypes.length() == 1 ?
  1168                         "unreachable.catch" :
  1169                         "unreachable.catch.1";
  1170                 log.warning(pos, key, catchableThrownTypes);
  1175     public void visitConditional(JCConditional tree) {
  1176         scanCond(tree.cond);
  1177         Bits initsBeforeElse = initsWhenFalse;
  1178         Bits uninitsBeforeElse = uninitsWhenFalse;
  1179         inits = initsWhenTrue;
  1180         uninits = uninitsWhenTrue;
  1181         if (tree.truepart.type.tag == BOOLEAN &&
  1182             tree.falsepart.type.tag == BOOLEAN) {
  1183             // if b and c are boolean valued, then
  1184             // v is (un)assigned after a?b:c when true iff
  1185             //    v is (un)assigned after b when true and
  1186             //    v is (un)assigned after c when true
  1187             scanCond(tree.truepart);
  1188             Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
  1189             Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
  1190             Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
  1191             Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
  1192             inits = initsBeforeElse;
  1193             uninits = uninitsBeforeElse;
  1194             scanCond(tree.falsepart);
  1195             initsWhenTrue.andSet(initsAfterThenWhenTrue);
  1196             initsWhenFalse.andSet(initsAfterThenWhenFalse);
  1197             uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
  1198             uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
  1199         } else {
  1200             scanExpr(tree.truepart);
  1201             Bits initsAfterThen = inits.dup();
  1202             Bits uninitsAfterThen = uninits.dup();
  1203             inits = initsBeforeElse;
  1204             uninits = uninitsBeforeElse;
  1205             scanExpr(tree.falsepart);
  1206             inits.andSet(initsAfterThen);
  1207             uninits.andSet(uninitsAfterThen);
  1211     public void visitIf(JCIf tree) {
  1212         scanCond(tree.cond);
  1213         Bits initsBeforeElse = initsWhenFalse;
  1214         Bits uninitsBeforeElse = uninitsWhenFalse;
  1215         inits = initsWhenTrue;
  1216         uninits = uninitsWhenTrue;
  1217         scanStat(tree.thenpart);
  1218         if (tree.elsepart != null) {
  1219             boolean aliveAfterThen = alive;
  1220             alive = true;
  1221             Bits initsAfterThen = inits.dup();
  1222             Bits uninitsAfterThen = uninits.dup();
  1223             inits = initsBeforeElse;
  1224             uninits = uninitsBeforeElse;
  1225             scanStat(tree.elsepart);
  1226             inits.andSet(initsAfterThen);
  1227             uninits.andSet(uninitsAfterThen);
  1228             alive = alive | aliveAfterThen;
  1229         } else {
  1230             inits.andSet(initsBeforeElse);
  1231             uninits.andSet(uninitsBeforeElse);
  1232             alive = true;
  1238     public void visitBreak(JCBreak tree) {
  1239         recordExit(tree);
  1242     public void visitContinue(JCContinue tree) {
  1243         recordExit(tree);
  1246     public void visitReturn(JCReturn tree) {
  1247         scanExpr(tree.expr);
  1248         // if not initial constructor, should markDead instead of recordExit
  1249         recordExit(tree);
  1252     public void visitThrow(JCThrow tree) {
  1253         scanExpr(tree.expr);
  1254         Symbol sym = TreeInfo.symbol(tree.expr);
  1255         if (sym != null &&
  1256             sym.kind == VAR &&
  1257             (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
  1258             preciseRethrowTypes.get(sym) != null &&
  1259             allowImprovedRethrowAnalysis) {
  1260             for (Type t : preciseRethrowTypes.get(sym)) {
  1261                 markThrown(tree, t);
  1264         else {
  1265             markThrown(tree, tree.expr.type);
  1267         markDead();
  1270     public void visitApply(JCMethodInvocation tree) {
  1271         scanExpr(tree.meth);
  1272         scanExprs(tree.args);
  1273         for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
  1274             markThrown(tree, l.head);
  1277     public void visitNewClass(JCNewClass tree) {
  1278         scanExpr(tree.encl);
  1279         scanExprs(tree.args);
  1280        // scan(tree.def);
  1281         for (List<Type> l = tree.constructorType.getThrownTypes();
  1282              l.nonEmpty();
  1283              l = l.tail) {
  1284             markThrown(tree, l.head);
  1286         List<Type> caughtPrev = caught;
  1287         try {
  1288             // If the new class expression defines an anonymous class,
  1289             // analysis of the anonymous constructor may encounter thrown
  1290             // types which are unsubstituted type variables.
  1291             // However, since the constructor's actual thrown types have
  1292             // already been marked as thrown, it is safe to simply include
  1293             // each of the constructor's formal thrown types in the set of
  1294             // 'caught/declared to be thrown' types, for the duration of
  1295             // the class def analysis.
  1296             if (tree.def != null)
  1297                 for (List<Type> l = tree.constructor.type.getThrownTypes();
  1298                      l.nonEmpty();
  1299                      l = l.tail) {
  1300                     caught = chk.incl(l.head, caught);
  1302             scan(tree.def);
  1304         finally {
  1305             caught = caughtPrev;
  1309     public void visitNewArray(JCNewArray tree) {
  1310         scanExprs(tree.dims);
  1311         scanExprs(tree.elems);
  1314     public void visitAssert(JCAssert tree) {
  1315         Bits initsExit = inits.dup();
  1316         Bits uninitsExit = uninits.dup();
  1317         scanCond(tree.cond);
  1318         uninitsExit.andSet(uninitsWhenTrue);
  1319         if (tree.detail != null) {
  1320             inits = initsWhenFalse;
  1321             uninits = uninitsWhenFalse;
  1322             scanExpr(tree.detail);
  1324         inits = initsExit;
  1325         uninits = uninitsExit;
  1328     public void visitAssign(JCAssign tree) {
  1329         JCTree lhs = TreeInfo.skipParens(tree.lhs);
  1330         if (!(lhs instanceof JCIdent)) scanExpr(lhs);
  1331         scanExpr(tree.rhs);
  1332         letInit(lhs);
  1335     public void visitAssignop(JCAssignOp tree) {
  1336         scanExpr(tree.lhs);
  1337         scanExpr(tree.rhs);
  1338         letInit(tree.lhs);
  1341     public void visitUnary(JCUnary tree) {
  1342         switch (tree.getTag()) {
  1343         case JCTree.NOT:
  1344             scanCond(tree.arg);
  1345             Bits t = initsWhenFalse;
  1346             initsWhenFalse = initsWhenTrue;
  1347             initsWhenTrue = t;
  1348             t = uninitsWhenFalse;
  1349             uninitsWhenFalse = uninitsWhenTrue;
  1350             uninitsWhenTrue = t;
  1351             break;
  1352         case JCTree.PREINC: case JCTree.POSTINC:
  1353         case JCTree.PREDEC: case JCTree.POSTDEC:
  1354             scanExpr(tree.arg);
  1355             letInit(tree.arg);
  1356             break;
  1357         default:
  1358             scanExpr(tree.arg);
  1362     public void visitBinary(JCBinary tree) {
  1363         switch (tree.getTag()) {
  1364         case JCTree.AND:
  1365             scanCond(tree.lhs);
  1366             Bits initsWhenFalseLeft = initsWhenFalse;
  1367             Bits uninitsWhenFalseLeft = uninitsWhenFalse;
  1368             inits = initsWhenTrue;
  1369             uninits = uninitsWhenTrue;
  1370             scanCond(tree.rhs);
  1371             initsWhenFalse.andSet(initsWhenFalseLeft);
  1372             uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
  1373             break;
  1374         case JCTree.OR:
  1375             scanCond(tree.lhs);
  1376             Bits initsWhenTrueLeft = initsWhenTrue;
  1377             Bits uninitsWhenTrueLeft = uninitsWhenTrue;
  1378             inits = initsWhenFalse;
  1379             uninits = uninitsWhenFalse;
  1380             scanCond(tree.rhs);
  1381             initsWhenTrue.andSet(initsWhenTrueLeft);
  1382             uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
  1383             break;
  1384         default:
  1385             scanExpr(tree.lhs);
  1386             scanExpr(tree.rhs);
  1390     public void visitIdent(JCIdent tree) {
  1391         if (tree.sym.kind == VAR) {
  1392             checkInit(tree.pos(), (VarSymbol)tree.sym);
  1393             referenced(tree.sym);
  1397     void referenced(Symbol sym) {
  1398         unrefdResources.remove(sym);
  1401     public void visitTypeCast(JCTypeCast tree) {
  1402         super.visitTypeCast(tree);
  1403         if (!tree.type.isErroneous()
  1404             && lint.isEnabled(Lint.LintCategory.CAST)
  1405             && types.isSameType(tree.expr.type, tree.clazz.type)
  1406             && !is292targetTypeCast(tree)) {
  1407             log.warning(Lint.LintCategory.CAST,
  1408                     tree.pos(), "redundant.cast", tree.expr.type);
  1411     //where
  1412         private boolean is292targetTypeCast(JCTypeCast tree) {
  1413             boolean is292targetTypeCast = false;
  1414             JCExpression expr = TreeInfo.skipParens(tree.expr);
  1415             if (expr.getTag() == JCTree.APPLY) {
  1416                 JCMethodInvocation apply = (JCMethodInvocation)expr;
  1417                 Symbol sym = TreeInfo.symbol(apply.meth);
  1418                 is292targetTypeCast = sym != null &&
  1419                     sym.kind == MTH &&
  1420                     (sym.flags() & POLYMORPHIC_SIGNATURE) != 0;
  1422             return is292targetTypeCast;
  1425     public void visitTopLevel(JCCompilationUnit tree) {
  1426         // Do nothing for TopLevel since each class is visited individually
  1429 /**************************************************************************
  1430  * main method
  1431  *************************************************************************/
  1433     /** Perform definite assignment/unassignment analysis on a tree.
  1434      */
  1435     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1436         try {
  1437             attrEnv = env;
  1438             JCTree tree = env.tree;
  1439             this.make = make;
  1440             inits = new Bits();
  1441             uninits = new Bits();
  1442             uninitsTry = new Bits();
  1443             initsWhenTrue = initsWhenFalse =
  1444                 uninitsWhenTrue = uninitsWhenFalse = null;
  1445             if (vars == null)
  1446                 vars = new VarSymbol[32];
  1447             else
  1448                 for (int i=0; i<vars.length; i++)
  1449                     vars[i] = null;
  1450             firstadr = 0;
  1451             nextadr = 0;
  1452             pendingExits = new ListBuffer<PendingExit>();
  1453             preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1454             alive = true;
  1455             this.thrown = this.caught = null;
  1456             this.classDef = null;
  1457             unrefdResources = new Scope(env.enclClass.sym);
  1458             scan(tree);
  1459         } finally {
  1460             // note that recursive invocations of this method fail hard
  1461             inits = uninits = uninitsTry = null;
  1462             initsWhenTrue = initsWhenFalse =
  1463                 uninitsWhenTrue = uninitsWhenFalse = null;
  1464             if (vars != null) for (int i=0; i<vars.length; i++)
  1465                 vars[i] = null;
  1466             firstadr = 0;
  1467             nextadr = 0;
  1468             pendingExits = null;
  1469             this.make = null;
  1470             this.thrown = this.caught = null;
  1471             this.classDef = null;
  1472             unrefdResources = null;

mercurial