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

Thu, 02 Oct 2008 19:58:40 -0700

author
xdono
date
Thu, 02 Oct 2008 19:58:40 -0700
changeset 117
24a47c3062fe
parent 113
eff38cc97183
child 186
09eb1acc9610
permissions
-rw-r--r--

6754988: Update copyright year
Summary: Update for files that have been modified starting July 2008
Reviewed-by: ohair, tbell

     1 /*
     2  * Copyright 1999-2008 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  */
    26 //todo: one might eliminate uninits.andSets when monotonic
    28 package com.sun.tools.javac.comp;
    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;
    35 import com.sun.tools.javac.code.Symbol.*;
    36 import com.sun.tools.javac.tree.JCTree.*;
    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.*;
    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>();
   180     private final Names 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;
   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     }
   195     protected Flow(Context context) {
   196         context.put(flowKey, this);
   198         names = Names.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     }
   206     /** A flag that indicates whether the last statement could
   207      *  complete normally.
   208      */
   209     private boolean alive;
   211     /** The set of definitely assigned variables.
   212      */
   213     Bits inits;
   215     /** The set of definitely unassigned variables.
   216      */
   217     Bits uninits;
   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;
   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;
   237     /** A mapping from addresses to variable symbols.
   238      */
   239     VarSymbol[] vars;
   241     /** The current class being defined.
   242      */
   243     JCClassDecl classDef;
   245     /** The first variable sequence number in this class definition.
   246      */
   247     int firstadr;
   249     /** The next available variable sequence number.
   250      */
   251     int nextadr;
   253     /** The list of possibly thrown declarable exceptions.
   254      */
   255     List<Type> thrown;
   257     /** The list of exceptions that are either caught or declared to be
   258      *  thrown.
   259      */
   260     List<Type> caught;
   262     /** Set when processing a loop body the second time for DU analysis. */
   263     boolean loopPassTwo = false;
   265     /*-------------------- Environments ----------------------*/
   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     }
   289     /** The currently pending exits that go from current inner blocks
   290      *  to an enclosing block, in source order.
   291      */
   292     ListBuffer<PendingExit> pendingExits;
   294     /*-------------------- Exceptions ----------------------*/
   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     }
   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     }
   323     /*-------------- Processing variables ----------------------*/
   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     }
   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     }
   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     }
   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     }
   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     }
   405     /*-------------------- Handling jumps ----------------------*/
   407     /** Record an outward transfer of control. */
   408     void recordExit(JCTree tree) {
   409         pendingExits.append(new PendingExit(tree, inits, uninits));
   410         markDead();
   411     }
   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     }
   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     }
   452     /** Record that statement is unreachable.
   453      */
   454     void markDead() {
   455         inits.inclRange(firstadr, nextadr);
   456         uninits.inclRange(firstadr, nextadr);
   457         alive = false;
   458     }
   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     }
   470     /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
   471      */
   472     void merge() {
   473         inits = initsWhenFalse.andSet(initsWhenTrue);
   474         uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
   475     }
   477 /* ************************************************************************
   478  * Visitor methods for statements and definitions
   479  *************************************************************************/
   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     }
   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     }
   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     }
   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     }
   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     }
   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     }
   554     /* ------------ Visitor methods for various sorts of trees -------------*/
   556     public void visitClassDef(JCClassDecl tree) {
   557         if (tree.sym == null) return;
   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;
   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);
   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             }
   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             }
   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             }
   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             }
   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             }
   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             }
   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             }
   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     }
   672     public void visitMethodDef(JCMethodDecl tree) {
   673         if (tree.body == null) return;
   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;
   683         lint = lint.augment(tree.sym.attributes_field);
   685         assert pendingExits.isEmpty();
   687         try {
   688             boolean isInitialConstructor =
   689                 TreeInfo.isInitialConstructor(tree);
   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.
   706             alive = true;
   707             scanStat(tree.body);
   709             if (alive && tree.sym.type.getReturnType().tag != VOID)
   710                 log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   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     }
   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     }
   759     public void visitBlock(JCBlock tree) {
   760         int nextadrPrev = nextadr;
   761         scanStats(tree.stats);
   762         nextadr = nextadrPrev;
   763     }
   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     }
   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     }
   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     }
   864     public void visitForeachLoop(JCEnhancedForLoop tree) {
   865         visitVarDef(tree.var);
   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();
   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     }
   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     }
   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         }
   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;
   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");
  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);
  1028                     pendingExits.append(exit);
  1030                 inits.orSet(initsEnd);
  1031                 alive = aliveEnd;
  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());
  1042         uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  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);
  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;
  1108     public void visitBreak(JCBreak tree) {
  1109         recordExit(tree);
  1112     public void visitContinue(JCContinue tree) {
  1113         recordExit(tree);
  1116     public void visitReturn(JCReturn tree) {
  1117         scanExpr(tree.expr);
  1118         // if not initial constructor, should markDead instead of recordExit
  1119         recordExit(tree);
  1122     public void visitThrow(JCThrow tree) {
  1123         scanExpr(tree.expr);
  1124         markThrown(tree, tree.expr.type);
  1125         markDead();
  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);
  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);
  1146     public void visitNewArray(JCNewArray tree) {
  1147         scanExprs(tree.dims);
  1148         scanExprs(tree.elems);
  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);
  1161         inits = initsExit;
  1162         uninits = uninitsExit;
  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);
  1172     public void visitAssignop(JCAssignOp tree) {
  1173         scanExpr(tree.lhs);
  1174         scanExpr(tree.rhs);
  1175         letInit(tree.lhs);
  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);
  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);
  1227     public void visitIdent(JCIdent tree) {
  1228         if (tree.sym.kind == VAR)
  1229             checkInit(tree.pos(), (VarSymbol)tree.sym);
  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);
  1241     public void visitTopLevel(JCCompilationUnit tree) {
  1242         // Do nothing for TopLevel since each class is visited individually
  1245 /**************************************************************************
  1246  * main method
  1247  *************************************************************************/
  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;

mercurial