Home » openjdk-7 » com.sun.tools » javac » comp » [javadoc | source]

    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    */
   25   
   26   //todo: one might eliminate uninits.andSets when monotonic
   27   
   28   package com.sun.tools.javac.comp;
   29   
   30   import java.util.HashMap;
   31   import java.util.Map;
   32   import java.util.LinkedHashMap;
   33   
   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;
   38   
   39   import com.sun.tools.javac.code.Symbol;
   40   import com.sun.tools.javac.tree.JCTree;
   41   
   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.*;
   45   
   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 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 the JLS 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>();
  183   
  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 allowImprovedRethrowAnalysis;
  194       private final boolean allowImprovedCatchAnalysis;
  195   
  196       public static Flow instance(Context context) {
  197           Flow instance = context.get(flowKey);
  198           if (instance == null)
  199               instance = new Flow(context);
  200           return instance;
  201       }
  202   
  203       protected Flow(Context context) {
  204           context.put(flowKey, this);
  205           names = Names.instance(context);
  206           log = Log.instance(context);
  207           syms = Symtab.instance(context);
  208           types = Types.instance(context);
  209           chk = Check.instance(context);
  210           lint = Lint.instance(context);
  211           rs = Resolve.instance(context);
  212           Source source = Source.instance(context);
  213           allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
  214           allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
  215       }
  216   
  217       /** A flag that indicates whether the last statement could
  218        *  complete normally.
  219        */
  220       private boolean alive;
  221   
  222       /** The set of definitely assigned variables.
  223        */
  224       Bits inits;
  225   
  226       /** The set of definitely unassigned variables.
  227        */
  228       Bits uninits;
  229   
  230       HashMap<Symbol, List<Type>> preciseRethrowTypes;
  231   
  232       /** The set of variables that are definitely unassigned everywhere
  233        *  in current try block. This variable is maintained lazily; it is
  234        *  updated only when something gets removed from uninits,
  235        *  typically by being assigned in reachable code.  To obtain the
  236        *  correct set of variables which are definitely unassigned
  237        *  anywhere in current try block, intersect uninitsTry and
  238        *  uninits.
  239        */
  240       Bits uninitsTry;
  241   
  242       /** When analyzing a condition, inits and uninits are null.
  243        *  Instead we have:
  244        */
  245       Bits initsWhenTrue;
  246       Bits initsWhenFalse;
  247       Bits uninitsWhenTrue;
  248       Bits uninitsWhenFalse;
  249   
  250       /** A mapping from addresses to variable symbols.
  251        */
  252       VarSymbol[] vars;
  253   
  254       /** The current class being defined.
  255        */
  256       JCClassDecl classDef;
  257   
  258       /** The first variable sequence number in this class definition.
  259        */
  260       int firstadr;
  261   
  262       /** The next available variable sequence number.
  263        */
  264       int nextadr;
  265   
  266       /** The list of possibly thrown declarable exceptions.
  267        */
  268       List<Type> thrown;
  269   
  270       /** The list of exceptions that are either caught or declared to be
  271        *  thrown.
  272        */
  273       List<Type> caught;
  274   
  275       /** The list of unreferenced automatic resources.
  276        */
  277       Scope unrefdResources;
  278   
  279       /** Set when processing a loop body the second time for DU analysis. */
  280       boolean loopPassTwo = false;
  281   
  282       /*-------------------- Environments ----------------------*/
  283   
  284       /** A pending exit.  These are the statements return, break, and
  285        *  continue.  In addition, exception-throwing expressions or
  286        *  statements are put here when not known to be caught.  This
  287        *  will typically result in an error unless it is within a
  288        *  try-finally whose finally block cannot complete normally.
  289        */
  290       static class PendingExit {
  291           JCTree tree;
  292           Bits inits;
  293           Bits uninits;
  294           Type thrown;
  295           PendingExit(JCTree tree, Bits inits, Bits uninits) {
  296               this.tree = tree;
  297               this.inits = inits.dup();
  298               this.uninits = uninits.dup();
  299           }
  300           PendingExit(JCTree tree, Type thrown) {
  301               this.tree = tree;
  302               this.thrown = thrown;
  303           }
  304       }
  305   
  306       /** The currently pending exits that go from current inner blocks
  307        *  to an enclosing block, in source order.
  308        */
  309       ListBuffer<PendingExit> pendingExits;
  310   
  311       /*-------------------- Exceptions ----------------------*/
  312   
  313       /** Complain that pending exceptions are not caught.
  314        */
  315       void errorUncaught() {
  316           for (PendingExit exit = pendingExits.next();
  317                exit != null;
  318                exit = pendingExits.next()) {
  319               if (classDef != null &&
  320                   classDef.pos == exit.tree.pos) {
  321                   log.error(exit.tree.pos(),
  322                           "unreported.exception.default.constructor",
  323                           exit.thrown);
  324               } else if (exit.tree.getTag() == JCTree.VARDEF &&
  325                       ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
  326                   log.error(exit.tree.pos(),
  327                           "unreported.exception.implicit.close",
  328                           exit.thrown,
  329                           ((JCVariableDecl)exit.tree).sym.name);
  330               } else {
  331                   log.error(exit.tree.pos(),
  332                           "unreported.exception.need.to.catch.or.throw",
  333                           exit.thrown);
  334               }
  335           }
  336       }
  337   
  338       /** Record that exception is potentially thrown and check that it
  339        *  is caught.
  340        */
  341       void markThrown(JCTree tree, Type exc) {
  342           if (!chk.isUnchecked(tree.pos(), exc)) {
  343               if (!chk.isHandled(exc, caught))
  344                   pendingExits.append(new PendingExit(tree, exc));
  345                   thrown = chk.incl(exc, thrown);
  346           }
  347       }
  348   
  349       /*-------------- Processing variables ----------------------*/
  350   
  351       /** Do we need to track init/uninit state of this symbol?
  352        *  I.e. is symbol either a local or a blank final variable?
  353        */
  354       boolean trackable(VarSymbol sym) {
  355           return
  356               (sym.owner.kind == MTH ||
  357                ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  358                 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner)));
  359       }
  360   
  361       /** Initialize new trackable variable by setting its address field
  362        *  to the next available sequence number and entering it under that
  363        *  index into the vars array.
  364        */
  365       void newVar(VarSymbol sym) {
  366           if (nextadr == vars.length) {
  367               VarSymbol[] newvars = new VarSymbol[nextadr * 2];
  368               System.arraycopy(vars, 0, newvars, 0, nextadr);
  369               vars = newvars;
  370           }
  371           sym.adr = nextadr;
  372           vars[nextadr] = sym;
  373           inits.excl(nextadr);
  374           uninits.incl(nextadr);
  375           nextadr++;
  376       }
  377   
  378       /** Record an initialization of a trackable variable.
  379        */
  380       void letInit(DiagnosticPosition pos, VarSymbol sym) {
  381           if (sym.adr >= firstadr && trackable(sym)) {
  382               if ((sym.flags() & FINAL) != 0) {
  383                   if ((sym.flags() & PARAMETER) != 0) {
  384                       if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  385                           log.error(pos, "multicatch.parameter.may.not.be.assigned",
  386                                     sym);
  387                       }
  388                       else {
  389                           log.error(pos, "final.parameter.may.not.be.assigned",
  390                                 sym);
  391                       }
  392                   } else if (!uninits.isMember(sym.adr)) {
  393                       log.error(pos,
  394                                 loopPassTwo
  395                                 ? "var.might.be.assigned.in.loop"
  396                                 : "var.might.already.be.assigned",
  397                                 sym);
  398                   } else if (!inits.isMember(sym.adr)) {
  399                       // reachable assignment
  400                       uninits.excl(sym.adr);
  401                       uninitsTry.excl(sym.adr);
  402                   } else {
  403                       //log.rawWarning(pos, "unreachable assignment");//DEBUG
  404                       uninits.excl(sym.adr);
  405                   }
  406               }
  407               inits.incl(sym.adr);
  408           } else if ((sym.flags() & FINAL) != 0) {
  409               log.error(pos, "var.might.already.be.assigned", sym);
  410           }
  411       }
  412   
  413       /** If tree is either a simple name or of the form this.name or
  414        *  C.this.name, and tree represents a trackable variable,
  415        *  record an initialization of the variable.
  416        */
  417       void letInit(JCTree tree) {
  418           tree = TreeInfo.skipParens(tree);
  419           if (tree.getTag() == JCTree.IDENT || tree.getTag() == JCTree.SELECT) {
  420               Symbol sym = TreeInfo.symbol(tree);
  421               if (sym.kind == VAR) {
  422                   letInit(tree.pos(), (VarSymbol)sym);
  423               }
  424           }
  425       }
  426   
  427       /** Check that trackable variable is initialized.
  428        */
  429       void checkInit(DiagnosticPosition pos, VarSymbol sym) {
  430           if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  431               trackable(sym) &&
  432               !inits.isMember(sym.adr)) {
  433               log.error(pos, "var.might.not.have.been.initialized",
  434                         sym);
  435               inits.incl(sym.adr);
  436           }
  437       }
  438   
  439       /*-------------------- Handling jumps ----------------------*/
  440   
  441       /** Record an outward transfer of control. */
  442       void recordExit(JCTree tree) {
  443           pendingExits.append(new PendingExit(tree, inits, uninits));
  444           markDead();
  445       }
  446   
  447       /** Resolve all breaks of this statement. */
  448       boolean resolveBreaks(JCTree tree,
  449                             ListBuffer<PendingExit> oldPendingExits) {
  450           boolean result = false;
  451           List<PendingExit> exits = pendingExits.toList();
  452           pendingExits = oldPendingExits;
  453           for (; exits.nonEmpty(); exits = exits.tail) {
  454               PendingExit exit = exits.head;
  455               if (exit.tree.getTag() == JCTree.BREAK &&
  456                   ((JCBreak) exit.tree).target == tree) {
  457                   inits.andSet(exit.inits);
  458                   uninits.andSet(exit.uninits);
  459                   result = true;
  460               } else {
  461                   pendingExits.append(exit);
  462               }
  463           }
  464           return result;
  465       }
  466   
  467       /** Resolve all continues of this statement. */
  468       boolean resolveContinues(JCTree tree) {
  469           boolean result = false;
  470           List<PendingExit> exits = pendingExits.toList();
  471           pendingExits = new ListBuffer<PendingExit>();
  472           for (; exits.nonEmpty(); exits = exits.tail) {
  473               PendingExit exit = exits.head;
  474               if (exit.tree.getTag() == JCTree.CONTINUE &&
  475                   ((JCContinue) exit.tree).target == tree) {
  476                   inits.andSet(exit.inits);
  477                   uninits.andSet(exit.uninits);
  478                   result = true;
  479               } else {
  480                   pendingExits.append(exit);
  481               }
  482           }
  483           return result;
  484       }
  485   
  486       /** Record that statement is unreachable.
  487        */
  488       void markDead() {
  489           inits.inclRange(firstadr, nextadr);
  490           uninits.inclRange(firstadr, nextadr);
  491           alive = false;
  492       }
  493   
  494       /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
  495        */
  496       void split(boolean setToNull) {
  497           initsWhenFalse = inits.dup();
  498           uninitsWhenFalse = uninits.dup();
  499           initsWhenTrue = inits;
  500           uninitsWhenTrue = uninits;
  501           if (setToNull)
  502               inits = uninits = null;
  503       }
  504   
  505       /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
  506        */
  507       void merge() {
  508           inits = initsWhenFalse.andSet(initsWhenTrue);
  509           uninits = uninitsWhenFalse.andSet(uninitsWhenTrue);
  510       }
  511   
  512   /* ************************************************************************
  513    * Visitor methods for statements and definitions
  514    *************************************************************************/
  515   
  516       /** Analyze a definition.
  517        */
  518       void scanDef(JCTree tree) {
  519           scanStat(tree);
  520           if (tree != null && tree.getTag() == JCTree.BLOCK && !alive) {
  521               log.error(tree.pos(),
  522                         "initializer.must.be.able.to.complete.normally");
  523           }
  524       }
  525   
  526       /** Analyze a statement. Check that statement is reachable.
  527        */
  528       void scanStat(JCTree tree) {
  529           if (!alive && tree != null) {
  530               log.error(tree.pos(), "unreachable.stmt");
  531               if (tree.getTag() != JCTree.SKIP) alive = true;
  532           }
  533           scan(tree);
  534       }
  535   
  536       /** Analyze list of statements.
  537        */
  538       void scanStats(List<? extends JCStatement> trees) {
  539           if (trees != null)
  540               for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
  541                   scanStat(l.head);
  542       }
  543   
  544       /** Analyze an expression. Make sure to set (un)inits rather than
  545        *  (un)initsWhenTrue(WhenFalse) on exit.
  546        */
  547       void scanExpr(JCTree tree) {
  548           if (tree != null) {
  549               scan(tree);
  550               if (inits == null) merge();
  551           }
  552       }
  553   
  554       /** Analyze a list of expressions.
  555        */
  556       void scanExprs(List<? extends JCExpression> trees) {
  557           if (trees != null)
  558               for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
  559                   scanExpr(l.head);
  560       }
  561   
  562       /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
  563        *  rather than (un)inits on exit.
  564        */
  565       void scanCond(JCTree tree) {
  566           if (tree.type.isFalse()) {
  567               if (inits == null) merge();
  568               initsWhenTrue = inits.dup();
  569               initsWhenTrue.inclRange(firstadr, nextadr);
  570               uninitsWhenTrue = uninits.dup();
  571               uninitsWhenTrue.inclRange(firstadr, nextadr);
  572               initsWhenFalse = inits;
  573               uninitsWhenFalse = uninits;
  574           } else if (tree.type.isTrue()) {
  575               if (inits == null) merge();
  576               initsWhenFalse = inits.dup();
  577               initsWhenFalse.inclRange(firstadr, nextadr);
  578               uninitsWhenFalse = uninits.dup();
  579               uninitsWhenFalse.inclRange(firstadr, nextadr);
  580               initsWhenTrue = inits;
  581               uninitsWhenTrue = uninits;
  582           } else {
  583               scan(tree);
  584               if (inits != null)
  585                   split(tree.type != syms.unknownType);
  586           }
  587           if (tree.type != syms.unknownType)
  588               inits = uninits = null;
  589       }
  590   
  591       /* ------------ Visitor methods for various sorts of trees -------------*/
  592   
  593       public void visitClassDef(JCClassDecl tree) {
  594           if (tree.sym == null) return;
  595   
  596           JCClassDecl classDefPrev = classDef;
  597           List<Type> thrownPrev = thrown;
  598           List<Type> caughtPrev = caught;
  599           boolean alivePrev = alive;
  600           int firstadrPrev = firstadr;
  601           int nextadrPrev = nextadr;
  602           ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
  603           Lint lintPrev = lint;
  604   
  605           pendingExits = new ListBuffer<PendingExit>();
  606           if (tree.name != names.empty) {
  607               caught = List.nil();
  608               firstadr = nextadr;
  609           }
  610           classDef = tree;
  611           thrown = List.nil();
  612           lint = lint.augment(tree.sym.attributes_field);
  613   
  614           try {
  615               // define all the static fields
  616               for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  617                   if (l.head.getTag() == JCTree.VARDEF) {
  618                       JCVariableDecl def = (JCVariableDecl)l.head;
  619                       if ((def.mods.flags & STATIC) != 0) {
  620                           VarSymbol sym = def.sym;
  621                           if (trackable(sym))
  622                               newVar(sym);
  623                       }
  624                   }
  625               }
  626   
  627               // process all the static initializers
  628               for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  629                   if (l.head.getTag() != JCTree.METHODDEF &&
  630                       (TreeInfo.flags(l.head) & STATIC) != 0) {
  631                       scanDef(l.head);
  632                       errorUncaught();
  633                   }
  634               }
  635   
  636               // add intersection of all thrown clauses of initial constructors
  637               // to set of caught exceptions, unless class is anonymous.
  638               if (tree.name != names.empty) {
  639                   boolean firstConstructor = true;
  640                   for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  641                       if (TreeInfo.isInitialConstructor(l.head)) {
  642                           List<Type> mthrown =
  643                               ((JCMethodDecl) l.head).sym.type.getThrownTypes();
  644                           if (firstConstructor) {
  645                               caught = mthrown;
  646                               firstConstructor = false;
  647                           } else {
  648                               caught = chk.intersect(mthrown, caught);
  649                           }
  650                       }
  651                   }
  652               }
  653   
  654               // define all the instance fields
  655               for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  656                   if (l.head.getTag() == JCTree.VARDEF) {
  657                       JCVariableDecl def = (JCVariableDecl)l.head;
  658                       if ((def.mods.flags & STATIC) == 0) {
  659                           VarSymbol sym = def.sym;
  660                           if (trackable(sym))
  661                               newVar(sym);
  662                       }
  663                   }
  664               }
  665   
  666               // process all the instance initializers
  667               for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  668                   if (l.head.getTag() != JCTree.METHODDEF &&
  669                       (TreeInfo.flags(l.head) & STATIC) == 0) {
  670                       scanDef(l.head);
  671                       errorUncaught();
  672                   }
  673               }
  674   
  675               // in an anonymous class, add the set of thrown exceptions to
  676               // the throws clause of the synthetic constructor and propagate
  677               // outwards.
  678               // Changing the throws clause on the fly is okay here because
  679               // the anonymous constructor can't be invoked anywhere else,
  680               // and its type hasn't been cached.
  681               if (tree.name == names.empty) {
  682                   for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  683                       if (TreeInfo.isInitialConstructor(l.head)) {
  684                           JCMethodDecl mdef = (JCMethodDecl)l.head;
  685                           mdef.thrown = make.Types(thrown);
  686                           mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
  687                       }
  688                   }
  689                   thrownPrev = chk.union(thrown, thrownPrev);
  690               }
  691   
  692               // process all the methods
  693               for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  694                   if (l.head.getTag() == JCTree.METHODDEF) {
  695                       scan(l.head);
  696                       errorUncaught();
  697                   }
  698               }
  699   
  700               thrown = thrownPrev;
  701           } finally {
  702               pendingExits = pendingExitsPrev;
  703               alive = alivePrev;
  704               nextadr = nextadrPrev;
  705               firstadr = firstadrPrev;
  706               caught = caughtPrev;
  707               classDef = classDefPrev;
  708               lint = lintPrev;
  709           }
  710       }
  711   
  712       public void visitMethodDef(JCMethodDecl tree) {
  713           if (tree.body == null) return;
  714   
  715           List<Type> caughtPrev = caught;
  716           List<Type> mthrown = tree.sym.type.getThrownTypes();
  717           Bits initsPrev = inits.dup();
  718           Bits uninitsPrev = uninits.dup();
  719           int nextadrPrev = nextadr;
  720           int firstadrPrev = firstadr;
  721           Lint lintPrev = lint;
  722   
  723           lint = lint.augment(tree.sym.attributes_field);
  724   
  725           Assert.check(pendingExits.isEmpty());
  726   
  727           try {
  728               boolean isInitialConstructor =
  729                   TreeInfo.isInitialConstructor(tree);
  730   
  731               if (!isInitialConstructor)
  732                   firstadr = nextadr;
  733               for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  734                   JCVariableDecl def = l.head;
  735                   scan(def);
  736                   inits.incl(def.sym.adr);
  737                   uninits.excl(def.sym.adr);
  738               }
  739               if (isInitialConstructor)
  740                   caught = chk.union(caught, mthrown);
  741               else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
  742                   caught = mthrown;
  743               // else we are in an instance initializer block;
  744               // leave caught unchanged.
  745   
  746               alive = true;
  747               scanStat(tree.body);
  748   
  749               if (alive && tree.sym.type.getReturnType().tag != VOID)
  750                   log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
  751   
  752               if (isInitialConstructor) {
  753                   for (int i = firstadr; i < nextadr; i++)
  754                       if (vars[i].owner == classDef.sym)
  755                           checkInit(TreeInfo.diagEndPos(tree.body), vars[i]);
  756               }
  757               List<PendingExit> exits = pendingExits.toList();
  758               pendingExits = new ListBuffer<PendingExit>();
  759               while (exits.nonEmpty()) {
  760                   PendingExit exit = exits.head;
  761                   exits = exits.tail;
  762                   if (exit.thrown == null) {
  763                       Assert.check(exit.tree.getTag() == JCTree.RETURN);
  764                       if (isInitialConstructor) {
  765                           inits = exit.inits;
  766                           for (int i = firstadr; i < nextadr; i++)
  767                               checkInit(exit.tree.pos(), vars[i]);
  768                       }
  769                   } else {
  770                       // uncaught throws will be reported later
  771                       pendingExits.append(exit);
  772                   }
  773               }
  774           } finally {
  775               inits = initsPrev;
  776               uninits = uninitsPrev;
  777               nextadr = nextadrPrev;
  778               firstadr = firstadrPrev;
  779               caught = caughtPrev;
  780               lint = lintPrev;
  781           }
  782       }
  783   
  784       public void visitVarDef(JCVariableDecl tree) {
  785           boolean track = trackable(tree.sym);
  786           if (track && tree.sym.owner.kind == MTH) newVar(tree.sym);
  787           if (tree.init != null) {
  788               Lint lintPrev = lint;
  789               lint = lint.augment(tree.sym.attributes_field);
  790               try{
  791                   scanExpr(tree.init);
  792                   if (track) letInit(tree.pos(), tree.sym);
  793               } finally {
  794                   lint = lintPrev;
  795               }
  796           }
  797       }
  798   
  799       public void visitBlock(JCBlock tree) {
  800           int nextadrPrev = nextadr;
  801           scanStats(tree.stats);
  802           nextadr = nextadrPrev;
  803       }
  804   
  805       public void visitDoLoop(JCDoWhileLoop tree) {
  806           ListBuffer<PendingExit> prevPendingExits = pendingExits;
  807           boolean prevLoopPassTwo = loopPassTwo;
  808           pendingExits = new ListBuffer<PendingExit>();
  809           int prevErrors = log.nerrors;
  810           do {
  811               Bits uninitsEntry = uninits.dup();
  812               uninitsEntry.excludeFrom(nextadr);
  813               scanStat(tree.body);
  814               alive |= resolveContinues(tree);
  815               scanCond(tree.cond);
  816               if (log.nerrors !=  prevErrors ||
  817                   loopPassTwo ||
  818                   uninitsEntry.dup().diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  819                   break;
  820               inits = initsWhenTrue;
  821               uninits = uninitsEntry.andSet(uninitsWhenTrue);
  822               loopPassTwo = true;
  823               alive = true;
  824           } while (true);
  825           loopPassTwo = prevLoopPassTwo;
  826           inits = initsWhenFalse;
  827           uninits = uninitsWhenFalse;
  828           alive = alive && !tree.cond.type.isTrue();
  829           alive |= resolveBreaks(tree, prevPendingExits);
  830       }
  831   
  832       public void visitWhileLoop(JCWhileLoop tree) {
  833           ListBuffer<PendingExit> prevPendingExits = pendingExits;
  834           boolean prevLoopPassTwo = loopPassTwo;
  835           Bits initsCond;
  836           Bits uninitsCond;
  837           pendingExits = new ListBuffer<PendingExit>();
  838           int prevErrors = log.nerrors;
  839           do {
  840               Bits uninitsEntry = uninits.dup();
  841               uninitsEntry.excludeFrom(nextadr);
  842               scanCond(tree.cond);
  843               initsCond = initsWhenFalse;
  844               uninitsCond = uninitsWhenFalse;
  845               inits = initsWhenTrue;
  846               uninits = uninitsWhenTrue;
  847               alive = !tree.cond.type.isFalse();
  848               scanStat(tree.body);
  849               alive |= resolveContinues(tree);
  850               if (log.nerrors != prevErrors ||
  851                   loopPassTwo ||
  852                   uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  853                   break;
  854               uninits = uninitsEntry.andSet(uninits);
  855               loopPassTwo = true;
  856               alive = true;
  857           } while (true);
  858           loopPassTwo = prevLoopPassTwo;
  859           inits = initsCond;
  860           uninits = uninitsCond;
  861           alive = resolveBreaks(tree, prevPendingExits) ||
  862               !tree.cond.type.isTrue();
  863       }
  864   
  865       public void visitForLoop(JCForLoop tree) {
  866           ListBuffer<PendingExit> prevPendingExits = pendingExits;
  867           boolean prevLoopPassTwo = loopPassTwo;
  868           int nextadrPrev = nextadr;
  869           scanStats(tree.init);
  870           Bits initsCond;
  871           Bits uninitsCond;
  872           pendingExits = new ListBuffer<PendingExit>();
  873           int prevErrors = log.nerrors;
  874           do {
  875               Bits uninitsEntry = uninits.dup();
  876               uninitsEntry.excludeFrom(nextadr);
  877               if (tree.cond != null) {
  878                   scanCond(tree.cond);
  879                   initsCond = initsWhenFalse;
  880                   uninitsCond = uninitsWhenFalse;
  881                   inits = initsWhenTrue;
  882                   uninits = uninitsWhenTrue;
  883                   alive = !tree.cond.type.isFalse();
  884               } else {
  885                   initsCond = inits.dup();
  886                   initsCond.inclRange(firstadr, nextadr);
  887                   uninitsCond = uninits.dup();
  888                   uninitsCond.inclRange(firstadr, nextadr);
  889                   alive = true;
  890               }
  891               scanStat(tree.body);
  892               alive |= resolveContinues(tree);
  893               scan(tree.step);
  894               if (log.nerrors != prevErrors ||
  895                   loopPassTwo ||
  896                   uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  897                   break;
  898               uninits = uninitsEntry.andSet(uninits);
  899               loopPassTwo = true;
  900               alive = true;
  901           } while (true);
  902           loopPassTwo = prevLoopPassTwo;
  903           inits = initsCond;
  904           uninits = uninitsCond;
  905           alive = resolveBreaks(tree, prevPendingExits) ||
  906               tree.cond != null && !tree.cond.type.isTrue();
  907           nextadr = nextadrPrev;
  908       }
  909   
  910       public void visitForeachLoop(JCEnhancedForLoop tree) {
  911           visitVarDef(tree.var);
  912   
  913           ListBuffer<PendingExit> prevPendingExits = pendingExits;
  914           boolean prevLoopPassTwo = loopPassTwo;
  915           int nextadrPrev = nextadr;
  916           scan(tree.expr);
  917           Bits initsStart = inits.dup();
  918           Bits uninitsStart = uninits.dup();
  919   
  920           letInit(tree.pos(), tree.var.sym);
  921           pendingExits = new ListBuffer<PendingExit>();
  922           int prevErrors = log.nerrors;
  923           do {
  924               Bits uninitsEntry = uninits.dup();
  925               uninitsEntry.excludeFrom(nextadr);
  926               scanStat(tree.body);
  927               alive |= resolveContinues(tree);
  928               if (log.nerrors != prevErrors ||
  929                   loopPassTwo ||
  930                   uninitsEntry.dup().diffSet(uninits).nextBit(firstadr) == -1)
  931                   break;
  932               uninits = uninitsEntry.andSet(uninits);
  933               loopPassTwo = true;
  934               alive = true;
  935           } while (true);
  936           loopPassTwo = prevLoopPassTwo;
  937           inits = initsStart;
  938           uninits = uninitsStart.andSet(uninits);
  939           resolveBreaks(tree, prevPendingExits);
  940           alive = true;
  941           nextadr = nextadrPrev;
  942       }
  943   
  944       public void visitLabelled(JCLabeledStatement tree) {
  945           ListBuffer<PendingExit> prevPendingExits = pendingExits;
  946           pendingExits = new ListBuffer<PendingExit>();
  947           scanStat(tree.body);
  948           alive |= resolveBreaks(tree, prevPendingExits);
  949       }
  950   
  951       public void visitSwitch(JCSwitch tree) {
  952           ListBuffer<PendingExit> prevPendingExits = pendingExits;
  953           pendingExits = new ListBuffer<PendingExit>();
  954           int nextadrPrev = nextadr;
  955           scanExpr(tree.selector);
  956           Bits initsSwitch = inits;
  957           Bits uninitsSwitch = uninits.dup();
  958           boolean hasDefault = false;
  959           for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  960               alive = true;
  961               inits = initsSwitch.dup();
  962               uninits = uninits.andSet(uninitsSwitch);
  963               JCCase c = l.head;
  964               if (c.pat == null)
  965                   hasDefault = true;
  966               else
  967                   scanExpr(c.pat);
  968               scanStats(c.stats);
  969               addVars(c.stats, initsSwitch, uninitsSwitch);
  970               // Warn about fall-through if lint switch fallthrough enabled.
  971               if (!loopPassTwo &&
  972                   alive &&
  973                   lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
  974                   c.stats.nonEmpty() && l.tail.nonEmpty())
  975                   log.warning(Lint.LintCategory.FALLTHROUGH,
  976                               l.tail.head.pos(),
  977                               "possible.fall-through.into.case");
  978           }
  979           if (!hasDefault) {
  980               inits.andSet(initsSwitch);
  981               alive = true;
  982           }
  983           alive |= resolveBreaks(tree, prevPendingExits);
  984           nextadr = nextadrPrev;
  985       }
  986       // where
  987           /** Add any variables defined in stats to inits and uninits. */
  988           private static void addVars(List<JCStatement> stats, Bits inits,
  989                                       Bits uninits) {
  990               for (;stats.nonEmpty(); stats = stats.tail) {
  991                   JCTree stat = stats.head;
  992                   if (stat.getTag() == JCTree.VARDEF) {
  993                       int adr = ((JCVariableDecl) stat).sym.adr;
  994                       inits.excl(adr);
  995                       uninits.incl(adr);
  996                   }
  997               }
  998           }
  999   
 1000       public void visitTry(JCTry tree) {
 1001           List<Type> caughtPrev = caught;
 1002           List<Type> thrownPrev = thrown;
 1003           thrown = List.nil();
 1004           for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
 1005               List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
 1006                       ((JCTypeUnion)l.head.param.vartype).alternatives :
 1007                       List.of(l.head.param.vartype);
 1008               for (JCExpression ct : subClauses) {
 1009                   caught = chk.incl(ct.type, caught);
 1010               }
 1011           }
 1012           ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
 1013           Bits uninitsTryPrev = uninitsTry;
 1014           ListBuffer<PendingExit> prevPendingExits = pendingExits;
 1015           pendingExits = new ListBuffer<PendingExit>();
 1016           Bits initsTry = inits.dup();
 1017           uninitsTry = uninits.dup();
 1018           for (JCTree resource : tree.resources) {
 1019               if (resource instanceof JCVariableDecl) {
 1020                   JCVariableDecl vdecl = (JCVariableDecl) resource;
 1021                   visitVarDef(vdecl);
 1022                   unrefdResources.enter(vdecl.sym);
 1023                   resourceVarDecls.append(vdecl);
 1024               } else if (resource instanceof JCExpression) {
 1025                   scanExpr((JCExpression) resource);
 1026               } else {
 1027                   throw new AssertionError(tree);  // parser error
 1028               }
 1029           }
 1030           for (JCTree resource : tree.resources) {
 1031               List<Type> closeableSupertypes = resource.type.isCompound() ?
 1032                   types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
 1033                   List.of(resource.type);
 1034               for (Type sup : closeableSupertypes) {
 1035                   if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
 1036                       Symbol closeMethod = rs.resolveQualifiedMethod(tree,
 1037                               attrEnv,
 1038                               sup,
 1039                               names.close,
 1040                               List.<Type>nil(),
 1041                               List.<Type>nil());
 1042                       if (closeMethod.kind == MTH) {
 1043                           for (Type t : ((MethodSymbol)closeMethod).getThrownTypes()) {
 1044                               markThrown(resource, t);
 1045                           }
 1046                       }
 1047                   }
 1048               }
 1049           }
 1050           scanStat(tree.body);
 1051           List<Type> thrownInTry = allowImprovedCatchAnalysis ?
 1052               chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
 1053               thrown;
 1054           thrown = thrownPrev;
 1055           caught = caughtPrev;
 1056           boolean aliveEnd = alive;
 1057           uninitsTry.andSet(uninits);
 1058           Bits initsEnd = inits;
 1059           Bits uninitsEnd = uninits;
 1060           int nextadrCatch = nextadr;
 1061   
 1062           if (!resourceVarDecls.isEmpty() &&
 1063                   lint.isEnabled(Lint.LintCategory.TRY)) {
 1064               for (JCVariableDecl resVar : resourceVarDecls) {
 1065                   if (unrefdResources.includes(resVar.sym)) {
 1066                       log.warning(Lint.LintCategory.TRY, resVar.pos(),
 1067                                   "try.resource.not.referenced", resVar.sym);
 1068                       unrefdResources.remove(resVar.sym);
 1069                   }
 1070               }
 1071           }
 1072   
 1073           List<Type> caughtInTry = List.nil();
 1074           for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
 1075               alive = true;
 1076               JCVariableDecl param = l.head.param;
 1077               List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
 1078                       ((JCTypeUnion)l.head.param.vartype).alternatives :
 1079                       List.of(l.head.param.vartype);
 1080               List<Type> ctypes = List.nil();
 1081               List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
 1082               for (JCExpression ct : subClauses) {
 1083                   Type exc = ct.type;
 1084                   if (exc != syms.unknownType) {
 1085                       ctypes = ctypes.append(exc);
 1086                       if (types.isSameType(exc, syms.objectType))
 1087                           continue;
 1088                       checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
 1089                       caughtInTry = chk.incl(exc, caughtInTry);
 1090                   }
 1091               }
 1092               inits = initsTry.dup();
 1093               uninits = uninitsTry.dup();
 1094               scan(param);
 1095               inits.incl(param.sym.adr);
 1096               uninits.excl(param.sym.adr);
 1097               preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
 1098               scanStat(l.head.body);
 1099               initsEnd.andSet(inits);
 1100               uninitsEnd.andSet(uninits);
 1101               nextadr = nextadrCatch;
 1102               preciseRethrowTypes.remove(param.sym);
 1103               aliveEnd |= alive;
 1104           }
 1105           if (tree.finalizer != null) {
 1106               List<Type> savedThrown = thrown;
 1107               thrown = List.nil();
 1108               inits = initsTry.dup();
 1109               uninits = uninitsTry.dup();
 1110               ListBuffer<PendingExit> exits = pendingExits;
 1111               pendingExits = prevPendingExits;
 1112               alive = true;
 1113               scanStat(tree.finalizer);
 1114               if (!alive) {
 1115                   // discard exits and exceptions from try and finally
 1116                   thrown = chk.union(thrown, thrownPrev);
 1117                   if (!loopPassTwo &&
 1118                       lint.isEnabled(Lint.LintCategory.FINALLY)) {
 1119                       log.warning(Lint.LintCategory.FINALLY,
 1120                               TreeInfo.diagEndPos(tree.finalizer),
 1121                               "finally.cannot.complete");
 1122                   }
 1123               } else {
 1124                   thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
 1125                   thrown = chk.union(thrown, savedThrown);
 1126                   uninits.andSet(uninitsEnd);
 1127                   // FIX: this doesn't preserve source order of exits in catch
 1128                   // versus finally!
 1129                   while (exits.nonEmpty()) {
 1130                       PendingExit exit = exits.next();
 1131                       if (exit.inits != null) {
 1132                           exit.inits.orSet(inits);
 1133                           exit.uninits.andSet(uninits);
 1134                       }
 1135                       pendingExits.append(exit);
 1136                   }
 1137                   inits.orSet(initsEnd);
 1138                   alive = aliveEnd;
 1139               }
 1140           } else {
 1141               thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
 1142               inits = initsEnd;
 1143               uninits = uninitsEnd;
 1144               alive = aliveEnd;
 1145               ListBuffer<PendingExit> exits = pendingExits;
 1146               pendingExits = prevPendingExits;
 1147               while (exits.nonEmpty()) pendingExits.append(exits.next());
 1148           }
 1149           uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
 1150       }
 1151   
 1152       void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
 1153           if (chk.subset(exc, caughtInTry)) {
 1154               log.error(pos, "except.already.caught", exc);
 1155           } else if (!chk.isUnchecked(pos, exc) &&
 1156                   !isExceptionOrThrowable(exc) &&
 1157                   !chk.intersects(exc, thrownInTry)) {
 1158               log.error(pos, "except.never.thrown.in.try", exc);
 1159           } else if (allowImprovedCatchAnalysis) {
 1160               List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
 1161               // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
 1162               // unchecked exception, the result list would not be empty, as the augmented
 1163               // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
 1164               // exception, that would have been covered in the branch above
 1165               if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
 1166                       !isExceptionOrThrowable(exc)) {
 1167                   String key = catchableThrownTypes.length() == 1 ?
 1168                           "unreachable.catch" :
 1169                           "unreachable.catch.1";
 1170                   log.warning(pos, key, catchableThrownTypes);
 1171               }
 1172           }
 1173       }
 1174       //where
 1175           private boolean isExceptionOrThrowable(Type exc) {
 1176               return exc.tsym == syms.throwableType.tsym ||
 1177                   exc.tsym == syms.exceptionType.tsym;
 1178           }
 1179   
 1180   
 1181       public void visitConditional(JCConditional tree) {
 1182           scanCond(tree.cond);
 1183           Bits initsBeforeElse = initsWhenFalse;
 1184           Bits uninitsBeforeElse = uninitsWhenFalse;
 1185           inits = initsWhenTrue;
 1186           uninits = uninitsWhenTrue;
 1187           if (tree.truepart.type.tag == BOOLEAN &&
 1188               tree.falsepart.type.tag == BOOLEAN) {
 1189               // if b and c are boolean valued, then
 1190               // v is (un)assigned after a?b:c when true iff
 1191               //    v is (un)assigned after b when true and
 1192               //    v is (un)assigned after c when true
 1193               scanCond(tree.truepart);
 1194               Bits initsAfterThenWhenTrue = initsWhenTrue.dup();
 1195               Bits initsAfterThenWhenFalse = initsWhenFalse.dup();
 1196               Bits uninitsAfterThenWhenTrue = uninitsWhenTrue.dup();
 1197               Bits uninitsAfterThenWhenFalse = uninitsWhenFalse.dup();
 1198               inits = initsBeforeElse;
 1199               uninits = uninitsBeforeElse;
 1200               scanCond(tree.falsepart);
 1201               initsWhenTrue.andSet(initsAfterThenWhenTrue);
 1202               initsWhenFalse.andSet(initsAfterThenWhenFalse);
 1203               uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
 1204               uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
 1205           } else {
 1206               scanExpr(tree.truepart);
 1207               Bits initsAfterThen = inits.dup();
 1208               Bits uninitsAfterThen = uninits.dup();
 1209               inits = initsBeforeElse;
 1210               uninits = uninitsBeforeElse;
 1211               scanExpr(tree.falsepart);
 1212               inits.andSet(initsAfterThen);
 1213               uninits.andSet(uninitsAfterThen);
 1214           }
 1215       }
 1216   
 1217       public void visitIf(JCIf tree) {
 1218           scanCond(tree.cond);
 1219           Bits initsBeforeElse = initsWhenFalse;
 1220           Bits uninitsBeforeElse = uninitsWhenFalse;
 1221           inits = initsWhenTrue;
 1222           uninits = uninitsWhenTrue;
 1223           scanStat(tree.thenpart);
 1224           if (tree.elsepart != null) {
 1225               boolean aliveAfterThen = alive;
 1226               alive = true;
 1227               Bits initsAfterThen = inits.dup();
 1228               Bits uninitsAfterThen = uninits.dup();
 1229               inits = initsBeforeElse;
 1230               uninits = uninitsBeforeElse;
 1231               scanStat(tree.elsepart);
 1232               inits.andSet(initsAfterThen);
 1233               uninits.andSet(uninitsAfterThen);
 1234               alive = alive | aliveAfterThen;
 1235           } else {
 1236               inits.andSet(initsBeforeElse);
 1237               uninits.andSet(uninitsBeforeElse);
 1238               alive = true;
 1239           }
 1240       }
 1241   
 1242   
 1243   
 1244       public void visitBreak(JCBreak tree) {
 1245           recordExit(tree);
 1246       }
 1247   
 1248       public void visitContinue(JCContinue tree) {
 1249           recordExit(tree);
 1250       }
 1251   
 1252       public void visitReturn(JCReturn tree) {
 1253           scanExpr(tree.expr);
 1254           // if not initial constructor, should markDead instead of recordExit
 1255           recordExit(tree);
 1256       }
 1257   
 1258       public void visitThrow(JCThrow tree) {
 1259           scanExpr(tree.expr);
 1260           Symbol sym = TreeInfo.symbol(tree.expr);
 1261           if (sym != null &&
 1262               sym.kind == VAR &&
 1263               (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
 1264               preciseRethrowTypes.get(sym) != null &&
 1265               allowImprovedRethrowAnalysis) {
 1266               for (Type t : preciseRethrowTypes.get(sym)) {
 1267                   markThrown(tree, t);
 1268               }
 1269           }
 1270           else {
 1271               markThrown(tree, tree.expr.type);
 1272           }
 1273           markDead();
 1274       }
 1275   
 1276       public void visitApply(JCMethodInvocation tree) {
 1277           scanExpr(tree.meth);
 1278           scanExprs(tree.args);
 1279           for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
 1280               markThrown(tree, l.head);
 1281       }
 1282   
 1283       public void visitNewClass(JCNewClass tree) {
 1284           scanExpr(tree.encl);
 1285           scanExprs(tree.args);
 1286          // scan(tree.def);
 1287           for (List<Type> l = tree.constructorType.getThrownTypes();
 1288                l.nonEmpty();
 1289                l = l.tail) {
 1290               markThrown(tree, l.head);
 1291           }
 1292           List<Type> caughtPrev = caught;
 1293           try {
 1294               // If the new class expression defines an anonymous class,
 1295               // analysis of the anonymous constructor may encounter thrown
 1296               // types which are unsubstituted type variables.
 1297               // However, since the constructor's actual thrown types have
 1298               // already been marked as thrown, it is safe to simply include
 1299               // each of the constructor's formal thrown types in the set of
 1300               // 'caught/declared to be thrown' types, for the duration of
 1301               // the class def analysis.
 1302               if (tree.def != null)
 1303                   for (List<Type> l = tree.constructor.type.getThrownTypes();
 1304                        l.nonEmpty();
 1305                        l = l.tail) {
 1306                       caught = chk.incl(l.head, caught);
 1307                   }
 1308               scan(tree.def);
 1309           }
 1310           finally {
 1311               caught = caughtPrev;
 1312           }
 1313       }
 1314   
 1315       public void visitNewArray(JCNewArray tree) {
 1316           scanExprs(tree.dims);
 1317           scanExprs(tree.elems);
 1318       }
 1319   
 1320       public void visitAssert(JCAssert tree) {
 1321           Bits initsExit = inits.dup();
 1322           Bits uninitsExit = uninits.dup();
 1323           scanCond(tree.cond);
 1324           uninitsExit.andSet(uninitsWhenTrue);
 1325           if (tree.detail != null) {
 1326               inits = initsWhenFalse;
 1327               uninits = uninitsWhenFalse;
 1328               scanExpr(tree.detail);
 1329           }
 1330           inits = initsExit;
 1331           uninits = uninitsExit;
 1332       }
 1333   
 1334       public void visitAssign(JCAssign tree) {
 1335           JCTree lhs = TreeInfo.skipParens(tree.lhs);
 1336           if (!(lhs instanceof JCIdent)) scanExpr(lhs);
 1337           scanExpr(tree.rhs);
 1338           letInit(lhs);
 1339       }
 1340   
 1341       public void visitAssignop(JCAssignOp tree) {
 1342           scanExpr(tree.lhs);
 1343           scanExpr(tree.rhs);
 1344           letInit(tree.lhs);
 1345       }
 1346   
 1347       public void visitUnary(JCUnary tree) {
 1348           switch (tree.getTag()) {
 1349           case JCTree.NOT:
 1350               scanCond(tree.arg);
 1351               Bits t = initsWhenFalse;
 1352               initsWhenFalse = initsWhenTrue;
 1353               initsWhenTrue = t;
 1354               t = uninitsWhenFalse;
 1355               uninitsWhenFalse = uninitsWhenTrue;
 1356               uninitsWhenTrue = t;
 1357               break;
 1358           case JCTree.PREINC: case JCTree.POSTINC:
 1359           case JCTree.PREDEC: case JCTree.POSTDEC:
 1360               scanExpr(tree.arg);
 1361               letInit(tree.arg);
 1362               break;
 1363           default:
 1364               scanExpr(tree.arg);
 1365           }
 1366       }
 1367   
 1368       public void visitBinary(JCBinary tree) {
 1369           switch (tree.getTag()) {
 1370           case JCTree.AND:
 1371               scanCond(tree.lhs);
 1372               Bits initsWhenFalseLeft = initsWhenFalse;
 1373               Bits uninitsWhenFalseLeft = uninitsWhenFalse;
 1374               inits = initsWhenTrue;
 1375               uninits = uninitsWhenTrue;
 1376               scanCond(tree.rhs);
 1377               initsWhenFalse.andSet(initsWhenFalseLeft);
 1378               uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
 1379               break;
 1380           case JCTree.OR:
 1381               scanCond(tree.lhs);
 1382               Bits initsWhenTrueLeft = initsWhenTrue;
 1383               Bits uninitsWhenTrueLeft = uninitsWhenTrue;
 1384               inits = initsWhenFalse;
 1385               uninits = uninitsWhenFalse;
 1386               scanCond(tree.rhs);
 1387               initsWhenTrue.andSet(initsWhenTrueLeft);
 1388               uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
 1389               break;
 1390           default:
 1391               scanExpr(tree.lhs);
 1392               scanExpr(tree.rhs);
 1393           }
 1394       }
 1395   
 1396       public void visitIdent(JCIdent tree) {
 1397           if (tree.sym.kind == VAR) {
 1398               checkInit(tree.pos(), (VarSymbol)tree.sym);
 1399               referenced(tree.sym);
 1400           }
 1401       }
 1402   
 1403       void referenced(Symbol sym) {
 1404           unrefdResources.remove(sym);
 1405       }
 1406   
 1407       public void visitTypeCast(JCTypeCast tree) {
 1408           super.visitTypeCast(tree);
 1409           if (!tree.type.isErroneous()
 1410               && lint.isEnabled(Lint.LintCategory.CAST)
 1411               && types.isSameType(tree.expr.type, tree.clazz.type)
 1412               && !is292targetTypeCast(tree)) {
 1413               log.warning(Lint.LintCategory.CAST,
 1414                       tree.pos(), "redundant.cast", tree.expr.type);
 1415           }
 1416       }
 1417       //where
 1418           private boolean is292targetTypeCast(JCTypeCast tree) {
 1419               boolean is292targetTypeCast = false;
 1420               JCExpression expr = TreeInfo.skipParens(tree.expr);
 1421               if (expr.getTag() == JCTree.APPLY) {
 1422                   JCMethodInvocation apply = (JCMethodInvocation)expr;
 1423                   Symbol sym = TreeInfo.symbol(apply.meth);
 1424                   is292targetTypeCast = sym != null &&
 1425                       sym.kind == MTH &&
 1426                       (sym.flags() & POLYMORPHIC_SIGNATURE) != 0;
 1427               }
 1428               return is292targetTypeCast;
 1429           }
 1430   
 1431       public void visitTopLevel(JCCompilationUnit tree) {
 1432           // Do nothing for TopLevel since each class is visited individually
 1433       }
 1434   
 1435   /**************************************************************************
 1436    * main method
 1437    *************************************************************************/
 1438   
 1439       /** Perform definite assignment/unassignment analysis on a tree.
 1440        */
 1441       public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
 1442           try {
 1443               attrEnv = env;
 1444               JCTree tree = env.tree;
 1445               this.make = make;
 1446               inits = new Bits();
 1447               uninits = new Bits();
 1448               uninitsTry = new Bits();
 1449               initsWhenTrue = initsWhenFalse =
 1450                   uninitsWhenTrue = uninitsWhenFalse = null;
 1451               if (vars == null)
 1452                   vars = new VarSymbol[32];
 1453               else
 1454                   for (int i=0; i<vars.length; i++)
 1455                       vars[i] = null;
 1456               firstadr = 0;
 1457               nextadr = 0;
 1458               pendingExits = new ListBuffer<PendingExit>();
 1459               preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
 1460               alive = true;
 1461               this.thrown = this.caught = null;
 1462               this.classDef = null;
 1463               unrefdResources = new Scope(env.enclClass.sym);
 1464               scan(tree);
 1465           } finally {
 1466               // note that recursive invocations of this method fail hard
 1467               inits = uninits = uninitsTry = null;
 1468               initsWhenTrue = initsWhenFalse =
 1469                   uninitsWhenTrue = uninitsWhenFalse = null;
 1470               if (vars != null) for (int i=0; i<vars.length; i++)
 1471                   vars[i] = null;
 1472               firstadr = 0;
 1473               nextadr = 0;
 1474               pendingExits = null;
 1475               this.make = null;
 1476               this.thrown = this.caught = null;
 1477               this.classDef = null;
 1478               unrefdResources = null;
 1479           }
 1480       }
 1481   }

Home » openjdk-7 » com.sun.tools » javac » comp » [javadoc | source]