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

Thu, 10 Jun 2010 17:09:56 -0700

author
jjg
date
Thu, 10 Jun 2010 17:09:56 -0700
changeset 582
366a7b9b5627
parent 581
f2fdd52e4e87
child 609
13354e1abba7
permissions
-rw-r--r--

6960407: Potential rebranding issues in openjdk/langtools repository sources
Reviewed-by: darcy

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

mercurial