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