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

Tue, 15 Feb 2011 11:51:04 +0000

author
mcimadamore
date
Tue, 15 Feb 2011 11:51:04 +0000
changeset 878
fa0e4e1916f4
parent 820
2d5aff89aaa3
child 880
0c24826853b2
permissions
-rw-r--r--

7017104: improve error reporting for uncaught/undeclared exceptions from try-with-resources
Summary: twr should generate better error message when uncaught exceptions are thrown by implicit call of close() method
Reviewed-by: jjg

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

mercurial