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

Fri, 14 Jan 2011 09:45:04 +0000

author
mcimadamore
date
Fri, 14 Jan 2011 09:45:04 +0000
changeset 820
2d5aff89aaa3
parent 816
7c537f4298fb
child 878
fa0e4e1916f4
permissions
-rw-r--r--

6992698: JSR 292: remove support for transient syntax in polymorphic signature calls
Summary: special syntax to denote indy return type through type parameters should be removed (and cast shall be used instead)
Reviewed-by: jjg, jrose

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

mercurial