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

Tue, 26 Oct 2010 14:29:48 -0700

author
jjg
date
Tue, 26 Oct 2010 14:29:48 -0700
changeset 724
7755f47542a0
parent 676
bfdfc13fe641
child 735
f2048d9c666e
permissions
-rw-r--r--

6949587: rename "DisjointType" to "DisjunctType"
Reviewed-by: mcimadamore

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

mercurial