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

Fri, 02 Mar 2012 12:57:47 +0000

author
mcimadamore
date
Fri, 02 Mar 2012 12:57:47 +0000
changeset 1216
6aafebe9a394
parent 1127
ca49d50318dc
child 1237
568e70bbd9aa
permissions
-rw-r--r--

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

mercurial