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

Wed, 30 Apr 2014 23:29:43 +0100

author
pgovereau
date
Wed, 30 Apr 2014 23:29:43 +0100
changeset 2376
12f99d1f23d9
parent 2370
acd64168cf8b
child 2408
716f2466ddd0
permissions
-rw-r--r--

8039026: Definitely unassigned field can be accessed
Reviewed-by: vromero, jlahoda

     1 /*
     2  * Copyright (c) 1999, 2014, 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;
    32 import com.sun.tools.javac.code.*;
    33 import com.sun.tools.javac.tree.*;
    34 import com.sun.tools.javac.util.*;
    35 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
    37 import com.sun.tools.javac.code.Symbol.*;
    38 import com.sun.tools.javac.tree.JCTree.*;
    40 import static com.sun.tools.javac.code.Flags.*;
    41 import static com.sun.tools.javac.code.Flags.BLOCK;
    42 import static com.sun.tools.javac.code.Kinds.*;
    43 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
    44 import static com.sun.tools.javac.code.TypeTag.VOID;
    45 import static com.sun.tools.javac.tree.JCTree.Tag.*;
    47 /** This pass implements dataflow analysis for Java programs though
    48  *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
    49  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
    50  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
    51  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
    52  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
    53  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
    54  *  determines that local variables accessed within the scope of an inner class/lambda
    55  *  are either final or effectively-final.
    56  *
    57  *  <p>The JLS has a number of problems in the
    58  *  specification of these flow analysis problems. This implementation
    59  *  attempts to address those issues.
    60  *
    61  *  <p>First, there is no accommodation for a finally clause that cannot
    62  *  complete normally. For liveness analysis, an intervening finally
    63  *  clause can cause a break, continue, or return not to reach its
    64  *  target.  For exception analysis, an intervening finally clause can
    65  *  cause any exception to be "caught".  For DA/DU analysis, the finally
    66  *  clause can prevent a transfer of control from propagating DA/DU
    67  *  state to the target.  In addition, code in the finally clause can
    68  *  affect the DA/DU status of variables.
    69  *
    70  *  <p>For try statements, we introduce the idea of a variable being
    71  *  definitely unassigned "everywhere" in a block.  A variable V is
    72  *  "unassigned everywhere" in a block iff it is unassigned at the
    73  *  beginning of the block and there is no reachable assignment to V
    74  *  in the block.  An assignment V=e is reachable iff V is not DA
    75  *  after e.  Then we can say that V is DU at the beginning of the
    76  *  catch block iff V is DU everywhere in the try block.  Similarly, V
    77  *  is DU at the beginning of the finally block iff V is DU everywhere
    78  *  in the try block and in every catch block.  Specifically, the
    79  *  following bullet is added to 16.2.2
    80  *  <pre>
    81  *      V is <em>unassigned everywhere</em> in a block if it is
    82  *      unassigned before the block and there is no reachable
    83  *      assignment to V within the block.
    84  *  </pre>
    85  *  <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all
    86  *  try blocks is changed to
    87  *  <pre>
    88  *      V is definitely unassigned before a catch block iff V is
    89  *      definitely unassigned everywhere in the try block.
    90  *  </pre>
    91  *  <p>The last bullet (and all of its sub-bullets) for try blocks that
    92  *  have a finally block is changed to
    93  *  <pre>
    94  *      V is definitely unassigned before the finally block iff
    95  *      V is definitely unassigned everywhere in the try block
    96  *      and everywhere in each catch block of the try statement.
    97  *  </pre>
    98  *  <p>In addition,
    99  *  <pre>
   100  *      V is definitely assigned at the end of a constructor iff
   101  *      V is definitely assigned after the block that is the body
   102  *      of the constructor and V is definitely assigned at every
   103  *      return that can return from the constructor.
   104  *  </pre>
   105  *  <p>In addition, each continue statement with the loop as its target
   106  *  is treated as a jump to the end of the loop body, and "intervening"
   107  *  finally clauses are treated as follows: V is DA "due to the
   108  *  continue" iff V is DA before the continue statement or V is DA at
   109  *  the end of any intervening finally block.  V is DU "due to the
   110  *  continue" iff any intervening finally cannot complete normally or V
   111  *  is DU at the end of every intervening finally block.  This "due to
   112  *  the continue" concept is then used in the spec for the loops.
   113  *
   114  *  <p>Similarly, break statements must consider intervening finally
   115  *  blocks.  For liveness analysis, a break statement for which any
   116  *  intervening finally cannot complete normally is not considered to
   117  *  cause the target statement to be able to complete normally. Then
   118  *  we say V is DA "due to the break" iff V is DA before the break or
   119  *  V is DA at the end of any intervening finally block.  V is DU "due
   120  *  to the break" iff any intervening finally cannot complete normally
   121  *  or V is DU at the break and at the end of every intervening
   122  *  finally block.  (I suspect this latter condition can be
   123  *  simplified.)  This "due to the break" is then used in the spec for
   124  *  all statements that can be "broken".
   125  *
   126  *  <p>The return statement is treated similarly.  V is DA "due to a
   127  *  return statement" iff V is DA before the return statement or V is
   128  *  DA at the end of any intervening finally block.  Note that we
   129  *  don't have to worry about the return expression because this
   130  *  concept is only used for construcrors.
   131  *
   132  *  <p>There is no spec in the JLS for when a variable is definitely
   133  *  assigned at the end of a constructor, which is needed for final
   134  *  fields (8.3.1.2).  We implement the rule that V is DA at the end
   135  *  of the constructor iff it is DA and the end of the body of the
   136  *  constructor and V is DA "due to" every return of the constructor.
   137  *
   138  *  <p>Intervening finally blocks similarly affect exception analysis.  An
   139  *  intervening finally that cannot complete normally allows us to ignore
   140  *  an otherwise uncaught exception.
   141  *
   142  *  <p>To implement the semantics of intervening finally clauses, all
   143  *  nonlocal transfers (break, continue, return, throw, method call that
   144  *  can throw a checked exception, and a constructor invocation that can
   145  *  thrown a checked exception) are recorded in a queue, and removed
   146  *  from the queue when we complete processing the target of the
   147  *  nonlocal transfer.  This allows us to modify the queue in accordance
   148  *  with the above rules when we encounter a finally clause.  The only
   149  *  exception to this [no pun intended] is that checked exceptions that
   150  *  are known to be caught or declared to be caught in the enclosing
   151  *  method are not recorded in the queue, but instead are recorded in a
   152  *  global variable "{@code Set<Type> thrown}" that records the type of all
   153  *  exceptions that can be thrown.
   154  *
   155  *  <p>Other minor issues the treatment of members of other classes
   156  *  (always considered DA except that within an anonymous class
   157  *  constructor, where DA status from the enclosing scope is
   158  *  preserved), treatment of the case expression (V is DA before the
   159  *  case expression iff V is DA after the switch expression),
   160  *  treatment of variables declared in a switch block (the implied
   161  *  DA/DU status after the switch expression is DU and not DA for
   162  *  variables defined in a switch block), the treatment of boolean ?:
   163  *  expressions (The JLS rules only handle b and c non-boolean; the
   164  *  new rule is that if b and c are boolean valued, then V is
   165  *  (un)assigned after a?b:c when true/false iff V is (un)assigned
   166  *  after b when true/false and V is (un)assigned after c when
   167  *  true/false).
   168  *
   169  *  <p>There is the remaining question of what syntactic forms constitute a
   170  *  reference to a variable.  It is conventional to allow this.x on the
   171  *  left-hand-side to initialize a final instance field named x, yet
   172  *  this.x isn't considered a "use" when appearing on a right-hand-side
   173  *  in most implementations.  Should parentheses affect what is
   174  *  considered a variable reference?  The simplest rule would be to
   175  *  allow unqualified forms only, parentheses optional, and phase out
   176  *  support for assigning to a final field via this.x.
   177  *
   178  *  <p><b>This is NOT part of any supported API.
   179  *  If you write code that depends on this, you do so at your own risk.
   180  *  This code and its internal interfaces are subject to change or
   181  *  deletion without notice.</b>
   182  */
   183 public class Flow {
   184     protected static final Context.Key<Flow> flowKey =
   185         new Context.Key<Flow>();
   187     private final Names names;
   188     private final Log log;
   189     private final Symtab syms;
   190     private final Types types;
   191     private final Check chk;
   192     private       TreeMaker make;
   193     private final Resolve rs;
   194     private final JCDiagnostic.Factory diags;
   195     private Env<AttrContext> attrEnv;
   196     private       Lint lint;
   197     private final boolean allowImprovedRethrowAnalysis;
   198     private final boolean allowImprovedCatchAnalysis;
   199     private final boolean allowEffectivelyFinalInInnerClasses;
   200     private final boolean enforceThisDotInit;
   202     public static Flow instance(Context context) {
   203         Flow instance = context.get(flowKey);
   204         if (instance == null)
   205             instance = new Flow(context);
   206         return instance;
   207     }
   209     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   210         new AliveAnalyzer().analyzeTree(env, make);
   211         new AssignAnalyzer(log, syms, lint, names, enforceThisDotInit).analyzeTree(env);
   212         new FlowAnalyzer().analyzeTree(env, make);
   213         new CaptureAnalyzer().analyzeTree(env, make);
   214     }
   216     public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
   217         Log.DiagnosticHandler diagHandler = null;
   218         //we need to disable diagnostics temporarily; the problem is that if
   219         //a lambda expression contains e.g. an unreachable statement, an error
   220         //message will be reported and will cause compilation to skip the flow analyis
   221         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
   222         //related errors, which will allow for more errors to be detected
   223         if (!speculative) {
   224             diagHandler = new Log.DiscardDiagnosticHandler(log);
   225         }
   226         try {
   227             new AliveAnalyzer().analyzeTree(env, that, make);
   228         } finally {
   229             if (!speculative) {
   230                 log.popDiagnosticHandler(diagHandler);
   231             }
   232         }
   233     }
   235     public List<Type> analyzeLambdaThrownTypes(Env<AttrContext> env, JCLambda that, TreeMaker make) {
   236         //we need to disable diagnostics temporarily; the problem is that if
   237         //a lambda expression contains e.g. an unreachable statement, an error
   238         //message will be reported and will cause compilation to skip the flow analyis
   239         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
   240         //related errors, which will allow for more errors to be detected
   241         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
   242         try {
   243             new AssignAnalyzer(log, syms, lint, names, enforceThisDotInit).analyzeTree(env);
   244             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
   245             flowAnalyzer.analyzeTree(env, that, make);
   246             return flowAnalyzer.inferredThrownTypes;
   247         } finally {
   248             log.popDiagnosticHandler(diagHandler);
   249         }
   250     }
   252     /**
   253      * Definite assignment scan mode
   254      */
   255     enum FlowKind {
   256         /**
   257          * This is the normal DA/DU analysis mode
   258          */
   259         NORMAL("var.might.already.be.assigned", false),
   260         /**
   261          * This is the speculative DA/DU analysis mode used to speculatively
   262          * derive assertions within loop bodies
   263          */
   264         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
   266         final String errKey;
   267         final boolean isFinal;
   269         FlowKind(String errKey, boolean isFinal) {
   270             this.errKey = errKey;
   271             this.isFinal = isFinal;
   272         }
   274         boolean isFinal() {
   275             return isFinal;
   276         }
   277     }
   279     protected Flow(Context context) {
   280         context.put(flowKey, this);
   281         names = Names.instance(context);
   282         log = Log.instance(context);
   283         syms = Symtab.instance(context);
   284         types = Types.instance(context);
   285         chk = Check.instance(context);
   286         lint = Lint.instance(context);
   287         rs = Resolve.instance(context);
   288         diags = JCDiagnostic.Factory.instance(context);
   289         Source source = Source.instance(context);
   290         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   291         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   292         allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
   293         enforceThisDotInit = source.enforceThisDotInit();
   294     }
   296     /**
   297      * Base visitor class for all visitors implementing dataflow analysis logic.
   298      * This class define the shared logic for handling jumps (break/continue statements).
   299      */
   300     static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
   302         enum JumpKind {
   303             BREAK(JCTree.Tag.BREAK) {
   304                 @Override
   305                 JCTree getTarget(JCTree tree) {
   306                     return ((JCBreak)tree).target;
   307                 }
   308             },
   309             CONTINUE(JCTree.Tag.CONTINUE) {
   310                 @Override
   311                 JCTree getTarget(JCTree tree) {
   312                     return ((JCContinue)tree).target;
   313                 }
   314             };
   316             final JCTree.Tag treeTag;
   318             private JumpKind(Tag treeTag) {
   319                 this.treeTag = treeTag;
   320             }
   322             abstract JCTree getTarget(JCTree tree);
   323         }
   325         /** The currently pending exits that go from current inner blocks
   326          *  to an enclosing block, in source order.
   327          */
   328         ListBuffer<P> pendingExits;
   330         /** A pending exit.  These are the statements return, break, and
   331          *  continue.  In addition, exception-throwing expressions or
   332          *  statements are put here when not known to be caught.  This
   333          *  will typically result in an error unless it is within a
   334          *  try-finally whose finally block cannot complete normally.
   335          */
   336         static class PendingExit {
   337             JCTree tree;
   339             PendingExit(JCTree tree) {
   340                 this.tree = tree;
   341             }
   343             void resolveJump(JCTree tree) {
   344                 //do nothing
   345             }
   346         }
   348         abstract void markDead(JCTree tree);
   350         /** Record an outward transfer of control. */
   351         void recordExit(JCTree tree, P pe) {
   352             pendingExits.append(pe);
   353             markDead(tree);
   354         }
   356         /** Resolve all jumps of this statement. */
   357         private boolean resolveJump(JCTree tree,
   358                         ListBuffer<P> oldPendingExits,
   359                         JumpKind jk) {
   360             boolean resolved = false;
   361             List<P> exits = pendingExits.toList();
   362             pendingExits = oldPendingExits;
   363             for (; exits.nonEmpty(); exits = exits.tail) {
   364                 P exit = exits.head;
   365                 if (exit.tree.hasTag(jk.treeTag) &&
   366                         jk.getTarget(exit.tree) == tree) {
   367                     exit.resolveJump(tree);
   368                     resolved = true;
   369                 } else {
   370                     pendingExits.append(exit);
   371                 }
   372             }
   373             return resolved;
   374         }
   376         /** Resolve all continues of this statement. */
   377         boolean resolveContinues(JCTree tree) {
   378             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
   379         }
   381         /** Resolve all breaks of this statement. */
   382         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
   383             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   384         }
   386         @Override
   387         public void scan(JCTree tree) {
   388             if (tree != null && (
   389                     tree.type == null ||
   390                     tree.type != Type.stuckType)) {
   391                 super.scan(tree);
   392             }
   393         }
   394     }
   396     /**
   397      * This pass implements the first step of the dataflow analysis, namely
   398      * the liveness analysis check. This checks that every statement is reachable.
   399      * The output of this analysis pass are used by other analyzers. This analyzer
   400      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   401      */
   402     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
   404         /** A flag that indicates whether the last statement could
   405          *  complete normally.
   406          */
   407         private boolean alive;
   409         @Override
   410         void markDead(JCTree tree) {
   411             alive = false;
   412         }
   414     /*************************************************************************
   415      * Visitor methods for statements and definitions
   416      *************************************************************************/
   418         /** Analyze a definition.
   419          */
   420         void scanDef(JCTree tree) {
   421             scanStat(tree);
   422             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
   423                 log.error(tree.pos(),
   424                           "initializer.must.be.able.to.complete.normally");
   425             }
   426         }
   428         /** Analyze a statement. Check that statement is reachable.
   429          */
   430         void scanStat(JCTree tree) {
   431             if (!alive && tree != null) {
   432                 log.error(tree.pos(), "unreachable.stmt");
   433                 if (!tree.hasTag(SKIP)) alive = true;
   434             }
   435             scan(tree);
   436         }
   438         /** Analyze list of statements.
   439          */
   440         void scanStats(List<? extends JCStatement> trees) {
   441             if (trees != null)
   442                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
   443                     scanStat(l.head);
   444         }
   446         /* ------------ Visitor methods for various sorts of trees -------------*/
   448         public void visitClassDef(JCClassDecl tree) {
   449             if (tree.sym == null) return;
   450             boolean alivePrev = alive;
   451             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   452             Lint lintPrev = lint;
   454             pendingExits = new ListBuffer<PendingExit>();
   455             lint = lint.augment(tree.sym);
   457             try {
   458                 // process all the static initializers
   459                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   460                     if (!l.head.hasTag(METHODDEF) &&
   461                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   462                         scanDef(l.head);
   463                     }
   464                 }
   466                 // process all the instance initializers
   467                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   468                     if (!l.head.hasTag(METHODDEF) &&
   469                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   470                         scanDef(l.head);
   471                     }
   472                 }
   474                 // process all the methods
   475                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   476                     if (l.head.hasTag(METHODDEF)) {
   477                         scan(l.head);
   478                     }
   479                 }
   480             } finally {
   481                 pendingExits = pendingExitsPrev;
   482                 alive = alivePrev;
   483                 lint = lintPrev;
   484             }
   485         }
   487         public void visitMethodDef(JCMethodDecl tree) {
   488             if (tree.body == null) return;
   489             Lint lintPrev = lint;
   491             lint = lint.augment(tree.sym);
   493             Assert.check(pendingExits.isEmpty());
   495             try {
   496                 alive = true;
   497                 scanStat(tree.body);
   499                 if (alive && !tree.sym.type.getReturnType().hasTag(VOID))
   500                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   502                 List<PendingExit> exits = pendingExits.toList();
   503                 pendingExits = new ListBuffer<PendingExit>();
   504                 while (exits.nonEmpty()) {
   505                     PendingExit exit = exits.head;
   506                     exits = exits.tail;
   507                     Assert.check(exit.tree.hasTag(RETURN));
   508                 }
   509             } finally {
   510                 lint = lintPrev;
   511             }
   512         }
   514         public void visitVarDef(JCVariableDecl tree) {
   515             if (tree.init != null) {
   516                 Lint lintPrev = lint;
   517                 lint = lint.augment(tree.sym);
   518                 try{
   519                     scan(tree.init);
   520                 } finally {
   521                     lint = lintPrev;
   522                 }
   523             }
   524         }
   526         public void visitBlock(JCBlock tree) {
   527             scanStats(tree.stats);
   528         }
   530         public void visitDoLoop(JCDoWhileLoop tree) {
   531             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   532             pendingExits = new ListBuffer<PendingExit>();
   533             scanStat(tree.body);
   534             alive |= resolveContinues(tree);
   535             scan(tree.cond);
   536             alive = alive && !tree.cond.type.isTrue();
   537             alive |= resolveBreaks(tree, prevPendingExits);
   538         }
   540         public void visitWhileLoop(JCWhileLoop tree) {
   541             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   542             pendingExits = new ListBuffer<PendingExit>();
   543             scan(tree.cond);
   544             alive = !tree.cond.type.isFalse();
   545             scanStat(tree.body);
   546             alive |= resolveContinues(tree);
   547             alive = resolveBreaks(tree, prevPendingExits) ||
   548                 !tree.cond.type.isTrue();
   549         }
   551         public void visitForLoop(JCForLoop tree) {
   552             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   553             scanStats(tree.init);
   554             pendingExits = new ListBuffer<PendingExit>();
   555             if (tree.cond != null) {
   556                 scan(tree.cond);
   557                 alive = !tree.cond.type.isFalse();
   558             } else {
   559                 alive = true;
   560             }
   561             scanStat(tree.body);
   562             alive |= resolveContinues(tree);
   563             scan(tree.step);
   564             alive = resolveBreaks(tree, prevPendingExits) ||
   565                 tree.cond != null && !tree.cond.type.isTrue();
   566         }
   568         public void visitForeachLoop(JCEnhancedForLoop tree) {
   569             visitVarDef(tree.var);
   570             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   571             scan(tree.expr);
   572             pendingExits = new ListBuffer<PendingExit>();
   573             scanStat(tree.body);
   574             alive |= resolveContinues(tree);
   575             resolveBreaks(tree, prevPendingExits);
   576             alive = true;
   577         }
   579         public void visitLabelled(JCLabeledStatement tree) {
   580             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   581             pendingExits = new ListBuffer<PendingExit>();
   582             scanStat(tree.body);
   583             alive |= resolveBreaks(tree, prevPendingExits);
   584         }
   586         public void visitSwitch(JCSwitch tree) {
   587             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   588             pendingExits = new ListBuffer<PendingExit>();
   589             scan(tree.selector);
   590             boolean hasDefault = false;
   591             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   592                 alive = true;
   593                 JCCase c = l.head;
   594                 if (c.pat == null)
   595                     hasDefault = true;
   596                 else
   597                     scan(c.pat);
   598                 scanStats(c.stats);
   599                 // Warn about fall-through if lint switch fallthrough enabled.
   600                 if (alive &&
   601                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   602                     c.stats.nonEmpty() && l.tail.nonEmpty())
   603                     log.warning(Lint.LintCategory.FALLTHROUGH,
   604                                 l.tail.head.pos(),
   605                                 "possible.fall-through.into.case");
   606             }
   607             if (!hasDefault) {
   608                 alive = true;
   609             }
   610             alive |= resolveBreaks(tree, prevPendingExits);
   611         }
   613         public void visitTry(JCTry tree) {
   614             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   615             pendingExits = new ListBuffer<PendingExit>();
   616             for (JCTree resource : tree.resources) {
   617                 if (resource instanceof JCVariableDecl) {
   618                     JCVariableDecl vdecl = (JCVariableDecl) resource;
   619                     visitVarDef(vdecl);
   620                 } else if (resource instanceof JCExpression) {
   621                     scan((JCExpression) resource);
   622                 } else {
   623                     throw new AssertionError(tree);  // parser error
   624                 }
   625             }
   627             scanStat(tree.body);
   628             boolean aliveEnd = alive;
   630             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   631                 alive = true;
   632                 JCVariableDecl param = l.head.param;
   633                 scan(param);
   634                 scanStat(l.head.body);
   635                 aliveEnd |= alive;
   636             }
   637             if (tree.finalizer != null) {
   638                 ListBuffer<PendingExit> exits = pendingExits;
   639                 pendingExits = prevPendingExits;
   640                 alive = true;
   641                 scanStat(tree.finalizer);
   642                 tree.finallyCanCompleteNormally = alive;
   643                 if (!alive) {
   644                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
   645                         log.warning(Lint.LintCategory.FINALLY,
   646                                 TreeInfo.diagEndPos(tree.finalizer),
   647                                 "finally.cannot.complete");
   648                     }
   649                 } else {
   650                     while (exits.nonEmpty()) {
   651                         pendingExits.append(exits.next());
   652                     }
   653                     alive = aliveEnd;
   654                 }
   655             } else {
   656                 alive = aliveEnd;
   657                 ListBuffer<PendingExit> exits = pendingExits;
   658                 pendingExits = prevPendingExits;
   659                 while (exits.nonEmpty()) pendingExits.append(exits.next());
   660             }
   661         }
   663         @Override
   664         public void visitIf(JCIf tree) {
   665             scan(tree.cond);
   666             scanStat(tree.thenpart);
   667             if (tree.elsepart != null) {
   668                 boolean aliveAfterThen = alive;
   669                 alive = true;
   670                 scanStat(tree.elsepart);
   671                 alive = alive | aliveAfterThen;
   672             } else {
   673                 alive = true;
   674             }
   675         }
   677         public void visitBreak(JCBreak tree) {
   678             recordExit(tree, new PendingExit(tree));
   679         }
   681         public void visitContinue(JCContinue tree) {
   682             recordExit(tree, new PendingExit(tree));
   683         }
   685         public void visitReturn(JCReturn tree) {
   686             scan(tree.expr);
   687             recordExit(tree, new PendingExit(tree));
   688         }
   690         public void visitThrow(JCThrow tree) {
   691             scan(tree.expr);
   692             markDead(tree);
   693         }
   695         public void visitApply(JCMethodInvocation tree) {
   696             scan(tree.meth);
   697             scan(tree.args);
   698         }
   700         public void visitNewClass(JCNewClass tree) {
   701             scan(tree.encl);
   702             scan(tree.args);
   703             if (tree.def != null) {
   704                 scan(tree.def);
   705             }
   706         }
   708         @Override
   709         public void visitLambda(JCLambda tree) {
   710             if (tree.type != null &&
   711                     tree.type.isErroneous()) {
   712                 return;
   713             }
   715             ListBuffer<PendingExit> prevPending = pendingExits;
   716             boolean prevAlive = alive;
   717             try {
   718                 pendingExits = new ListBuffer<>();
   719                 alive = true;
   720                 scanStat(tree.body);
   721                 tree.canCompleteNormally = alive;
   722             }
   723             finally {
   724                 pendingExits = prevPending;
   725                 alive = prevAlive;
   726             }
   727         }
   729         public void visitTopLevel(JCCompilationUnit tree) {
   730             // Do nothing for TopLevel since each class is visited individually
   731         }
   733     /**************************************************************************
   734      * main method
   735      *************************************************************************/
   737         /** Perform definite assignment/unassignment analysis on a tree.
   738          */
   739         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   740             analyzeTree(env, env.tree, make);
   741         }
   742         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
   743             try {
   744                 attrEnv = env;
   745                 Flow.this.make = make;
   746                 pendingExits = new ListBuffer<PendingExit>();
   747                 alive = true;
   748                 scan(tree);
   749             } finally {
   750                 pendingExits = null;
   751                 Flow.this.make = null;
   752             }
   753         }
   754     }
   756     /**
   757      * This pass implements the second step of the dataflow analysis, namely
   758      * the exception analysis. This is to ensure that every checked exception that is
   759      * thrown is declared or caught. The analyzer uses some info that has been set by
   760      * the liveliness analyzer.
   761      */
   762     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   764         /** A flag that indicates whether the last statement could
   765          *  complete normally.
   766          */
   767         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   769         /** The current class being defined.
   770          */
   771         JCClassDecl classDef;
   773         /** The list of possibly thrown declarable exceptions.
   774          */
   775         List<Type> thrown;
   777         /** The list of exceptions that are either caught or declared to be
   778          *  thrown.
   779          */
   780         List<Type> caught;
   782         class FlowPendingExit extends BaseAnalyzer.PendingExit {
   784             Type thrown;
   786             FlowPendingExit(JCTree tree, Type thrown) {
   787                 super(tree);
   788                 this.thrown = thrown;
   789             }
   790         }
   792         @Override
   793         void markDead(JCTree tree) {
   794             //do nothing
   795         }
   797         /*-------------------- Exceptions ----------------------*/
   799         /** Complain that pending exceptions are not caught.
   800          */
   801         void errorUncaught() {
   802             for (FlowPendingExit exit = pendingExits.next();
   803                  exit != null;
   804                  exit = pendingExits.next()) {
   805                 if (classDef != null &&
   806                     classDef.pos == exit.tree.pos) {
   807                     log.error(exit.tree.pos(),
   808                             "unreported.exception.default.constructor",
   809                             exit.thrown);
   810                 } else if (exit.tree.hasTag(VARDEF) &&
   811                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   812                     log.error(exit.tree.pos(),
   813                             "unreported.exception.implicit.close",
   814                             exit.thrown,
   815                             ((JCVariableDecl)exit.tree).sym.name);
   816                 } else {
   817                     log.error(exit.tree.pos(),
   818                             "unreported.exception.need.to.catch.or.throw",
   819                             exit.thrown);
   820                 }
   821             }
   822         }
   824         /** Record that exception is potentially thrown and check that it
   825          *  is caught.
   826          */
   827         void markThrown(JCTree tree, Type exc) {
   828             if (!chk.isUnchecked(tree.pos(), exc)) {
   829                 if (!chk.isHandled(exc, caught)) {
   830                     pendingExits.append(new FlowPendingExit(tree, exc));
   831                 }
   832                 thrown = chk.incl(exc, thrown);
   833             }
   834         }
   836     /*************************************************************************
   837      * Visitor methods for statements and definitions
   838      *************************************************************************/
   840         /* ------------ Visitor methods for various sorts of trees -------------*/
   842         public void visitClassDef(JCClassDecl tree) {
   843             if (tree.sym == null) return;
   845             JCClassDecl classDefPrev = classDef;
   846             List<Type> thrownPrev = thrown;
   847             List<Type> caughtPrev = caught;
   848             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   849             Lint lintPrev = lint;
   851             pendingExits = new ListBuffer<FlowPendingExit>();
   852             if (tree.name != names.empty) {
   853                 caught = List.nil();
   854             }
   855             classDef = tree;
   856             thrown = List.nil();
   857             lint = lint.augment(tree.sym);
   859             try {
   860                 // process all the static initializers
   861                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   862                     if (!l.head.hasTag(METHODDEF) &&
   863                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   864                         scan(l.head);
   865                         errorUncaught();
   866                     }
   867                 }
   869                 // add intersection of all thrown clauses of initial constructors
   870                 // to set of caught exceptions, unless class is anonymous.
   871                 if (tree.name != names.empty) {
   872                     boolean firstConstructor = true;
   873                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   874                         if (TreeInfo.isInitialConstructor(l.head)) {
   875                             List<Type> mthrown =
   876                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
   877                             if (firstConstructor) {
   878                                 caught = mthrown;
   879                                 firstConstructor = false;
   880                             } else {
   881                                 caught = chk.intersect(mthrown, caught);
   882                             }
   883                         }
   884                     }
   885                 }
   887                 // process all the instance initializers
   888                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   889                     if (!l.head.hasTag(METHODDEF) &&
   890                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   891                         scan(l.head);
   892                         errorUncaught();
   893                     }
   894                 }
   896                 // in an anonymous class, add the set of thrown exceptions to
   897                 // the throws clause of the synthetic constructor and propagate
   898                 // outwards.
   899                 // Changing the throws clause on the fly is okay here because
   900                 // the anonymous constructor can't be invoked anywhere else,
   901                 // and its type hasn't been cached.
   902                 if (tree.name == names.empty) {
   903                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   904                         if (TreeInfo.isInitialConstructor(l.head)) {
   905                             JCMethodDecl mdef = (JCMethodDecl)l.head;
   906                             mdef.thrown = make.Types(thrown);
   907                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
   908                         }
   909                     }
   910                     thrownPrev = chk.union(thrown, thrownPrev);
   911                 }
   913                 // process all the methods
   914                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   915                     if (l.head.hasTag(METHODDEF)) {
   916                         scan(l.head);
   917                         errorUncaught();
   918                     }
   919                 }
   921                 thrown = thrownPrev;
   922             } finally {
   923                 pendingExits = pendingExitsPrev;
   924                 caught = caughtPrev;
   925                 classDef = classDefPrev;
   926                 lint = lintPrev;
   927             }
   928         }
   930         public void visitMethodDef(JCMethodDecl tree) {
   931             if (tree.body == null) return;
   933             List<Type> caughtPrev = caught;
   934             List<Type> mthrown = tree.sym.type.getThrownTypes();
   935             Lint lintPrev = lint;
   937             lint = lint.augment(tree.sym);
   939             Assert.check(pendingExits.isEmpty());
   941             try {
   942                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   943                     JCVariableDecl def = l.head;
   944                     scan(def);
   945                 }
   946                 if (TreeInfo.isInitialConstructor(tree))
   947                     caught = chk.union(caught, mthrown);
   948                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   949                     caught = mthrown;
   950                 // else we are in an instance initializer block;
   951                 // leave caught unchanged.
   953                 scan(tree.body);
   955                 List<FlowPendingExit> exits = pendingExits.toList();
   956                 pendingExits = new ListBuffer<FlowPendingExit>();
   957                 while (exits.nonEmpty()) {
   958                     FlowPendingExit exit = exits.head;
   959                     exits = exits.tail;
   960                     if (exit.thrown == null) {
   961                         Assert.check(exit.tree.hasTag(RETURN));
   962                     } else {
   963                         // uncaught throws will be reported later
   964                         pendingExits.append(exit);
   965                     }
   966                 }
   967             } finally {
   968                 caught = caughtPrev;
   969                 lint = lintPrev;
   970             }
   971         }
   973         public void visitVarDef(JCVariableDecl tree) {
   974             if (tree.init != null) {
   975                 Lint lintPrev = lint;
   976                 lint = lint.augment(tree.sym);
   977                 try{
   978                     scan(tree.init);
   979                 } finally {
   980                     lint = lintPrev;
   981                 }
   982             }
   983         }
   985         public void visitBlock(JCBlock tree) {
   986             scan(tree.stats);
   987         }
   989         public void visitDoLoop(JCDoWhileLoop tree) {
   990             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   991             pendingExits = new ListBuffer<FlowPendingExit>();
   992             scan(tree.body);
   993             resolveContinues(tree);
   994             scan(tree.cond);
   995             resolveBreaks(tree, prevPendingExits);
   996         }
   998         public void visitWhileLoop(JCWhileLoop tree) {
   999             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1000             pendingExits = new ListBuffer<FlowPendingExit>();
  1001             scan(tree.cond);
  1002             scan(tree.body);
  1003             resolveContinues(tree);
  1004             resolveBreaks(tree, prevPendingExits);
  1007         public void visitForLoop(JCForLoop tree) {
  1008             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1009             scan(tree.init);
  1010             pendingExits = new ListBuffer<FlowPendingExit>();
  1011             if (tree.cond != null) {
  1012                 scan(tree.cond);
  1014             scan(tree.body);
  1015             resolveContinues(tree);
  1016             scan(tree.step);
  1017             resolveBreaks(tree, prevPendingExits);
  1020         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1021             visitVarDef(tree.var);
  1022             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1023             scan(tree.expr);
  1024             pendingExits = new ListBuffer<FlowPendingExit>();
  1025             scan(tree.body);
  1026             resolveContinues(tree);
  1027             resolveBreaks(tree, prevPendingExits);
  1030         public void visitLabelled(JCLabeledStatement tree) {
  1031             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1032             pendingExits = new ListBuffer<FlowPendingExit>();
  1033             scan(tree.body);
  1034             resolveBreaks(tree, prevPendingExits);
  1037         public void visitSwitch(JCSwitch tree) {
  1038             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1039             pendingExits = new ListBuffer<FlowPendingExit>();
  1040             scan(tree.selector);
  1041             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1042                 JCCase c = l.head;
  1043                 if (c.pat != null) {
  1044                     scan(c.pat);
  1046                 scan(c.stats);
  1048             resolveBreaks(tree, prevPendingExits);
  1051         public void visitTry(JCTry tree) {
  1052             List<Type> caughtPrev = caught;
  1053             List<Type> thrownPrev = thrown;
  1054             thrown = List.nil();
  1055             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1056                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1057                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1058                         List.of(l.head.param.vartype);
  1059                 for (JCExpression ct : subClauses) {
  1060                     caught = chk.incl(ct.type, caught);
  1064             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1065             pendingExits = new ListBuffer<FlowPendingExit>();
  1066             for (JCTree resource : tree.resources) {
  1067                 if (resource instanceof JCVariableDecl) {
  1068                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1069                     visitVarDef(vdecl);
  1070                 } else if (resource instanceof JCExpression) {
  1071                     scan((JCExpression) resource);
  1072                 } else {
  1073                     throw new AssertionError(tree);  // parser error
  1076             for (JCTree resource : tree.resources) {
  1077                 List<Type> closeableSupertypes = resource.type.isCompound() ?
  1078                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
  1079                     List.of(resource.type);
  1080                 for (Type sup : closeableSupertypes) {
  1081                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
  1082                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
  1083                                 attrEnv,
  1084                                 sup,
  1085                                 names.close,
  1086                                 List.<Type>nil(),
  1087                                 List.<Type>nil());
  1088                         Type mt = types.memberType(resource.type, closeMethod);
  1089                         if (closeMethod.kind == MTH) {
  1090                             for (Type t : mt.getThrownTypes()) {
  1091                                 markThrown(resource, t);
  1097             scan(tree.body);
  1098             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1099                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1100                 thrown;
  1101             thrown = thrownPrev;
  1102             caught = caughtPrev;
  1104             List<Type> caughtInTry = List.nil();
  1105             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1106                 JCVariableDecl param = l.head.param;
  1107                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1108                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1109                         List.of(l.head.param.vartype);
  1110                 List<Type> ctypes = List.nil();
  1111                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
  1112                 for (JCExpression ct : subClauses) {
  1113                     Type exc = ct.type;
  1114                     if (exc != syms.unknownType) {
  1115                         ctypes = ctypes.append(exc);
  1116                         if (types.isSameType(exc, syms.objectType))
  1117                             continue;
  1118                         checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
  1119                         caughtInTry = chk.incl(exc, caughtInTry);
  1122                 scan(param);
  1123                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1124                 scan(l.head.body);
  1125                 preciseRethrowTypes.remove(param.sym);
  1127             if (tree.finalizer != null) {
  1128                 List<Type> savedThrown = thrown;
  1129                 thrown = List.nil();
  1130                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1131                 pendingExits = prevPendingExits;
  1132                 scan(tree.finalizer);
  1133                 if (!tree.finallyCanCompleteNormally) {
  1134                     // discard exits and exceptions from try and finally
  1135                     thrown = chk.union(thrown, thrownPrev);
  1136                 } else {
  1137                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1138                     thrown = chk.union(thrown, savedThrown);
  1139                     // FIX: this doesn't preserve source order of exits in catch
  1140                     // versus finally!
  1141                     while (exits.nonEmpty()) {
  1142                         pendingExits.append(exits.next());
  1145             } else {
  1146                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1147                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1148                 pendingExits = prevPendingExits;
  1149                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1153         @Override
  1154         public void visitIf(JCIf tree) {
  1155             scan(tree.cond);
  1156             scan(tree.thenpart);
  1157             if (tree.elsepart != null) {
  1158                 scan(tree.elsepart);
  1162         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1163             if (chk.subset(exc, caughtInTry)) {
  1164                 log.error(pos, "except.already.caught", exc);
  1165             } else if (!chk.isUnchecked(pos, exc) &&
  1166                     !isExceptionOrThrowable(exc) &&
  1167                     !chk.intersects(exc, thrownInTry)) {
  1168                 log.error(pos, "except.never.thrown.in.try", exc);
  1169             } else if (allowImprovedCatchAnalysis) {
  1170                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
  1171                 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
  1172                 // unchecked exception, the result list would not be empty, as the augmented
  1173                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
  1174                 // exception, that would have been covered in the branch above
  1175                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
  1176                         !isExceptionOrThrowable(exc)) {
  1177                     String key = catchableThrownTypes.length() == 1 ?
  1178                             "unreachable.catch" :
  1179                             "unreachable.catch.1";
  1180                     log.warning(pos, key, catchableThrownTypes);
  1184         //where
  1185             private boolean isExceptionOrThrowable(Type exc) {
  1186                 return exc.tsym == syms.throwableType.tsym ||
  1187                     exc.tsym == syms.exceptionType.tsym;
  1190         public void visitBreak(JCBreak tree) {
  1191             recordExit(tree, new FlowPendingExit(tree, null));
  1194         public void visitContinue(JCContinue tree) {
  1195             recordExit(tree, new FlowPendingExit(tree, null));
  1198         public void visitReturn(JCReturn tree) {
  1199             scan(tree.expr);
  1200             recordExit(tree, new FlowPendingExit(tree, null));
  1203         public void visitThrow(JCThrow tree) {
  1204             scan(tree.expr);
  1205             Symbol sym = TreeInfo.symbol(tree.expr);
  1206             if (sym != null &&
  1207                 sym.kind == VAR &&
  1208                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
  1209                 preciseRethrowTypes.get(sym) != null &&
  1210                 allowImprovedRethrowAnalysis) {
  1211                 for (Type t : preciseRethrowTypes.get(sym)) {
  1212                     markThrown(tree, t);
  1215             else {
  1216                 markThrown(tree, tree.expr.type);
  1218             markDead(tree);
  1221         public void visitApply(JCMethodInvocation tree) {
  1222             scan(tree.meth);
  1223             scan(tree.args);
  1224             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
  1225                 markThrown(tree, l.head);
  1228         public void visitNewClass(JCNewClass tree) {
  1229             scan(tree.encl);
  1230             scan(tree.args);
  1231            // scan(tree.def);
  1232             for (List<Type> l = tree.constructorType.getThrownTypes();
  1233                  l.nonEmpty();
  1234                  l = l.tail) {
  1235                 markThrown(tree, l.head);
  1237             List<Type> caughtPrev = caught;
  1238             try {
  1239                 // If the new class expression defines an anonymous class,
  1240                 // analysis of the anonymous constructor may encounter thrown
  1241                 // types which are unsubstituted type variables.
  1242                 // However, since the constructor's actual thrown types have
  1243                 // already been marked as thrown, it is safe to simply include
  1244                 // each of the constructor's formal thrown types in the set of
  1245                 // 'caught/declared to be thrown' types, for the duration of
  1246                 // the class def analysis.
  1247                 if (tree.def != null)
  1248                     for (List<Type> l = tree.constructor.type.getThrownTypes();
  1249                          l.nonEmpty();
  1250                          l = l.tail) {
  1251                         caught = chk.incl(l.head, caught);
  1253                 scan(tree.def);
  1255             finally {
  1256                 caught = caughtPrev;
  1260         @Override
  1261         public void visitLambda(JCLambda tree) {
  1262             if (tree.type != null &&
  1263                     tree.type.isErroneous()) {
  1264                 return;
  1266             List<Type> prevCaught = caught;
  1267             List<Type> prevThrown = thrown;
  1268             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1269             try {
  1270                 pendingExits = new ListBuffer<>();
  1271                 caught = tree.getDescriptorType(types).getThrownTypes();
  1272                 thrown = List.nil();
  1273                 scan(tree.body);
  1274                 List<FlowPendingExit> exits = pendingExits.toList();
  1275                 pendingExits = new ListBuffer<FlowPendingExit>();
  1276                 while (exits.nonEmpty()) {
  1277                     FlowPendingExit exit = exits.head;
  1278                     exits = exits.tail;
  1279                     if (exit.thrown == null) {
  1280                         Assert.check(exit.tree.hasTag(RETURN));
  1281                     } else {
  1282                         // uncaught throws will be reported later
  1283                         pendingExits.append(exit);
  1287                 errorUncaught();
  1288             } finally {
  1289                 pendingExits = prevPending;
  1290                 caught = prevCaught;
  1291                 thrown = prevThrown;
  1295         public void visitTopLevel(JCCompilationUnit tree) {
  1296             // Do nothing for TopLevel since each class is visited individually
  1299     /**************************************************************************
  1300      * main method
  1301      *************************************************************************/
  1303         /** Perform definite assignment/unassignment analysis on a tree.
  1304          */
  1305         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1306             analyzeTree(env, env.tree, make);
  1308         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  1309             try {
  1310                 attrEnv = env;
  1311                 Flow.this.make = make;
  1312                 pendingExits = new ListBuffer<FlowPendingExit>();
  1313                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1314                 this.thrown = this.caught = null;
  1315                 this.classDef = null;
  1316                 scan(tree);
  1317             } finally {
  1318                 pendingExits = null;
  1319                 Flow.this.make = null;
  1320                 this.thrown = this.caught = null;
  1321                 this.classDef = null;
  1326     /**
  1327      * Specialized pass that performs inference of thrown types for lambdas.
  1328      */
  1329     class LambdaFlowAnalyzer extends FlowAnalyzer {
  1330         List<Type> inferredThrownTypes;
  1331         boolean inLambda;
  1332         @Override
  1333         public void visitLambda(JCLambda tree) {
  1334             if ((tree.type != null &&
  1335                     tree.type.isErroneous()) || inLambda) {
  1336                 return;
  1338             List<Type> prevCaught = caught;
  1339             List<Type> prevThrown = thrown;
  1340             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1341             inLambda = true;
  1342             try {
  1343                 pendingExits = new ListBuffer<>();
  1344                 caught = List.of(syms.throwableType);
  1345                 thrown = List.nil();
  1346                 scan(tree.body);
  1347                 inferredThrownTypes = thrown;
  1348             } finally {
  1349                 pendingExits = prevPending;
  1350                 caught = prevCaught;
  1351                 thrown = prevThrown;
  1352                 inLambda = false;
  1355         @Override
  1356         public void visitClassDef(JCClassDecl tree) {
  1357             //skip
  1361     /**
  1362      * This pass implements (i) definite assignment analysis, which ensures that
  1363      * each variable is assigned when used and (ii) definite unassignment analysis,
  1364      * which ensures that no final variable is assigned more than once. This visitor
  1365      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1366      * effectively-final local variables/parameters.
  1367      */
  1369     public abstract static class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer.AbstractAssignPendingExit>
  1370         extends BaseAnalyzer<P> {
  1372         /** The set of definitely assigned variables.
  1373          */
  1374         protected final Bits inits;
  1376         /** The set of definitely unassigned variables.
  1377          */
  1378         final Bits uninits;
  1380         /** The set of variables that are definitely unassigned everywhere
  1381          *  in current try block. This variable is maintained lazily; it is
  1382          *  updated only when something gets removed from uninits,
  1383          *  typically by being assigned in reachable code.  To obtain the
  1384          *  correct set of variables which are definitely unassigned
  1385          *  anywhere in current try block, intersect uninitsTry and
  1386          *  uninits.
  1387          */
  1388         final Bits uninitsTry;
  1390         /** When analyzing a condition, inits and uninits are null.
  1391          *  Instead we have:
  1392          */
  1393         final Bits initsWhenTrue;
  1394         final Bits initsWhenFalse;
  1395         final Bits uninitsWhenTrue;
  1396         final Bits uninitsWhenFalse;
  1398         /** A mapping from addresses to variable symbols.
  1399          */
  1400         protected JCVariableDecl[] vardecls;
  1402         /** The current class being defined.
  1403          */
  1404         JCClassDecl classDef;
  1406         /** The first variable sequence number in this class definition.
  1407          */
  1408         int firstadr;
  1410         /** The next available variable sequence number.
  1411          */
  1412         protected int nextadr;
  1414         /** The first variable sequence number in a block that can return.
  1415          */
  1416         protected int returnadr;
  1418         /** The list of unreferenced automatic resources.
  1419          */
  1420         Scope unrefdResources;
  1422         /** Set when processing a loop body the second time for DU analysis. */
  1423         FlowKind flowKind = FlowKind.NORMAL;
  1425         /** The starting position of the analysed tree */
  1426         int startPos;
  1428         final Symtab syms;
  1430         protected Names names;
  1432         final boolean enforceThisDotInit;
  1434         public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
  1436             final Bits inits;
  1437             final Bits uninits;
  1438             final Bits exit_inits = new Bits(true);
  1439             final Bits exit_uninits = new Bits(true);
  1441             public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
  1442                 super(tree);
  1443                 this.inits = inits;
  1444                 this.uninits = uninits;
  1445                 this.exit_inits.assign(inits);
  1446                 this.exit_uninits.assign(uninits);
  1449             @Override
  1450             public void resolveJump(JCTree tree) {
  1451                 inits.andSet(exit_inits);
  1452                 uninits.andSet(exit_uninits);
  1456         public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names, boolean enforceThisDotInit) {
  1457             this.inits = inits;
  1458             uninits = new Bits();
  1459             uninitsTry = new Bits();
  1460             initsWhenTrue = new Bits(true);
  1461             initsWhenFalse = new Bits(true);
  1462             uninitsWhenTrue = new Bits(true);
  1463             uninitsWhenFalse = new Bits(true);
  1464             this.syms = syms;
  1465             this.names = names;
  1466             this.enforceThisDotInit = enforceThisDotInit;
  1469         private boolean isInitialConstructor = false;
  1471         @Override
  1472         protected void markDead(JCTree tree) {
  1473             if (!isInitialConstructor) {
  1474                 inits.inclRange(returnadr, nextadr);
  1475             } else {
  1476                 for (int address = returnadr; address < nextadr; address++) {
  1477                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
  1478                         inits.incl(address);
  1482             uninits.inclRange(returnadr, nextadr);
  1485         /*-------------- Processing variables ----------------------*/
  1487         /** Do we need to track init/uninit state of this symbol?
  1488          *  I.e. is symbol either a local or a blank final variable?
  1489          */
  1490         protected boolean trackable(VarSymbol sym) {
  1491             return
  1492                 sym.pos >= startPos &&
  1493                 ((sym.owner.kind == MTH ||
  1494                 isFinalUninitializedField(sym)));
  1497         boolean isFinalUninitializedField(VarSymbol sym) {
  1498             return sym.owner.kind == TYP &&
  1499                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1500                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
  1503         boolean isFinalUninitializedStaticField(VarSymbol sym) {
  1504             return isFinalUninitializedField(sym) && sym.isStatic();
  1507         /** Initialize new trackable variable by setting its address field
  1508          *  to the next available sequence number and entering it under that
  1509          *  index into the vars array.
  1510          */
  1511         void newVar(JCVariableDecl varDecl) {
  1512             VarSymbol sym = varDecl.sym;
  1513             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
  1514             if ((sym.flags() & FINAL) == 0) {
  1515                 sym.flags_field |= EFFECTIVELY_FINAL;
  1517             sym.adr = nextadr;
  1518             vardecls[nextadr] = varDecl;
  1519             exclVarFromInits(varDecl, nextadr);
  1520             uninits.incl(nextadr);
  1521             nextadr++;
  1524         protected void exclVarFromInits(JCTree tree, int adr) {
  1525             inits.excl(adr);
  1528         protected void assignToInits(JCTree tree, Bits bits) {
  1529             inits.assign(bits);
  1532         protected void andSetInits(JCTree tree, Bits bits) {
  1533             inits.andSet(bits);
  1536         protected void orSetInits(JCTree tree, Bits bits) {
  1537             inits.orSet(bits);
  1540         /** Record an initialization of a trackable variable.
  1541          */
  1542         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1543             if (sym.adr >= firstadr && trackable(sym)) {
  1544                 if (uninits.isMember(sym.adr)) {
  1545                     uninit(sym);
  1547                 inits.incl(sym.adr);
  1550         //where
  1551             void uninit(VarSymbol sym) {
  1552                 if (!inits.isMember(sym.adr)) {
  1553                     // reachable assignment
  1554                     uninits.excl(sym.adr);
  1555                     uninitsTry.excl(sym.adr);
  1556                 } else {
  1557                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
  1558                     uninits.excl(sym.adr);
  1562         /** If tree is either a simple name or of the form this.name or
  1563          *  C.this.name, and tree represents a trackable variable,
  1564          *  record an initialization of the variable.
  1565          */
  1566         void letInit(JCTree tree) {
  1567             tree = TreeInfo.skipParens(tree);
  1568             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  1569                 Symbol sym = TreeInfo.symbol(tree);
  1570                 if (sym.kind == VAR) {
  1571                     letInit(tree.pos(), (VarSymbol)sym);
  1576         /** Check that trackable variable is initialized.
  1577          */
  1578         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
  1579             checkInit(pos, sym, "var.might.not.have.been.initialized");
  1582         void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}
  1584         /** Utility method to reset several Bits instances.
  1585          */
  1586         private void resetBits(Bits... bits) {
  1587             for (Bits b : bits) {
  1588                 b.reset();
  1592         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
  1593          */
  1594         void split(boolean setToNull) {
  1595             initsWhenFalse.assign(inits);
  1596             uninitsWhenFalse.assign(uninits);
  1597             initsWhenTrue.assign(inits);
  1598             uninitsWhenTrue.assign(uninits);
  1599             if (setToNull) {
  1600                 resetBits(inits, uninits);
  1604         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
  1605          */
  1606         protected void merge(JCTree tree) {
  1607             inits.assign(initsWhenFalse.andSet(initsWhenTrue));
  1608             uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
  1611     /* ************************************************************************
  1612      * Visitor methods for statements and definitions
  1613      *************************************************************************/
  1615         /** Analyze an expression. Make sure to set (un)inits rather than
  1616          *  (un)initsWhenTrue(WhenFalse) on exit.
  1617          */
  1618         void scanExpr(JCTree tree) {
  1619             if (tree != null) {
  1620                 scan(tree);
  1621                 if (inits.isReset()) {
  1622                     merge(tree);
  1627         /** Analyze a list of expressions.
  1628          */
  1629         void scanExprs(List<? extends JCExpression> trees) {
  1630             if (trees != null)
  1631                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
  1632                     scanExpr(l.head);
  1635         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
  1636          *  rather than (un)inits on exit.
  1637          */
  1638         void scanCond(JCTree tree) {
  1639             if (tree.type.isFalse()) {
  1640                 if (inits.isReset()) merge(tree);
  1641                 initsWhenTrue.assign(inits);
  1642                 initsWhenTrue.inclRange(firstadr, nextadr);
  1643                 uninitsWhenTrue.assign(uninits);
  1644                 uninitsWhenTrue.inclRange(firstadr, nextadr);
  1645                 initsWhenFalse.assign(inits);
  1646                 uninitsWhenFalse.assign(uninits);
  1647             } else if (tree.type.isTrue()) {
  1648                 if (inits.isReset()) merge(tree);
  1649                 initsWhenFalse.assign(inits);
  1650                 initsWhenFalse.inclRange(firstadr, nextadr);
  1651                 uninitsWhenFalse.assign(uninits);
  1652                 uninitsWhenFalse.inclRange(firstadr, nextadr);
  1653                 initsWhenTrue.assign(inits);
  1654                 uninitsWhenTrue.assign(uninits);
  1655             } else {
  1656                 scan(tree);
  1657                 if (!inits.isReset())
  1658                     split(tree.type != syms.unknownType);
  1660             if (tree.type != syms.unknownType) {
  1661                 resetBits(inits, uninits);
  1665         /* ------------ Visitor methods for various sorts of trees -------------*/
  1667         @Override
  1668         public void visitClassDef(JCClassDecl tree) {
  1669             if (tree.sym == null) {
  1670                 return;
  1673             JCClassDecl classDefPrev = classDef;
  1674             int firstadrPrev = firstadr;
  1675             int nextadrPrev = nextadr;
  1676             ListBuffer<P> pendingExitsPrev = pendingExits;
  1678             pendingExits = new ListBuffer<P>();
  1679             if (tree.name != names.empty) {
  1680                 firstadr = nextadr;
  1682             classDef = tree;
  1683             try {
  1684                 // define all the static fields
  1685                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1686                     if (l.head.hasTag(VARDEF)) {
  1687                         JCVariableDecl def = (JCVariableDecl)l.head;
  1688                         if ((def.mods.flags & STATIC) != 0) {
  1689                             VarSymbol sym = def.sym;
  1690                             if (trackable(sym)) {
  1691                                 newVar(def);
  1697                 // process all the static initializers
  1698                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1699                     if (!l.head.hasTag(METHODDEF) &&
  1700                         (TreeInfo.flags(l.head) & STATIC) != 0) {
  1701                         scan(l.head);
  1705                 // define all the instance fields
  1706                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1707                     if (l.head.hasTag(VARDEF)) {
  1708                         JCVariableDecl def = (JCVariableDecl)l.head;
  1709                         if ((def.mods.flags & STATIC) == 0) {
  1710                             VarSymbol sym = def.sym;
  1711                             if (trackable(sym)) {
  1712                                 newVar(def);
  1718                 // process all the instance initializers
  1719                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1720                     if (!l.head.hasTag(METHODDEF) &&
  1721                         (TreeInfo.flags(l.head) & STATIC) == 0) {
  1722                         scan(l.head);
  1726                 // process all the methods
  1727                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1728                     if (l.head.hasTag(METHODDEF)) {
  1729                         scan(l.head);
  1732             } finally {
  1733                 pendingExits = pendingExitsPrev;
  1734                 nextadr = nextadrPrev;
  1735                 firstadr = firstadrPrev;
  1736                 classDef = classDefPrev;
  1740         @Override
  1741         public void visitMethodDef(JCMethodDecl tree) {
  1742             if (tree.body == null) {
  1743                 return;
  1745             /*  Ignore synthetic methods, except for translated lambda methods.
  1746              */
  1747             if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
  1748                 return;
  1751             final Bits initsPrev = new Bits(inits);
  1752             final Bits uninitsPrev = new Bits(uninits);
  1753             int nextadrPrev = nextadr;
  1754             int firstadrPrev = firstadr;
  1755             int returnadrPrev = returnadr;
  1757             Assert.check(pendingExits.isEmpty());
  1758             boolean lastInitialConstructor = isInitialConstructor;
  1759             try {
  1760                 isInitialConstructor = TreeInfo.isInitialConstructor(tree);
  1762                 if (!isInitialConstructor) {
  1763                     firstadr = nextadr;
  1765                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  1766                     JCVariableDecl def = l.head;
  1767                     scan(def);
  1768                     Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
  1769                     /*  If we are executing the code from Gen, then there can be
  1770                      *  synthetic or mandated variables, ignore them.
  1771                      */
  1772                     initParam(def);
  1774                 // else we are in an instance initializer block;
  1775                 // leave caught unchanged.
  1776                 scan(tree.body);
  1778                 if (isInitialConstructor) {
  1779                     boolean isSynthesized = (tree.sym.flags() &
  1780                                              GENERATEDCONSTR) != 0;
  1781                     for (int i = firstadr; i < nextadr; i++) {
  1782                         JCVariableDecl vardecl = vardecls[i];
  1783                         VarSymbol var = vardecl.sym;
  1784                         if (var.owner == classDef.sym) {
  1785                             // choose the diagnostic position based on whether
  1786                             // the ctor is default(synthesized) or not
  1787                             if (isSynthesized) {
  1788                                 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
  1789                                     var, "var.not.initialized.in.default.constructor");
  1790                             } else {
  1791                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
  1796                 List<P> exits = pendingExits.toList();
  1797                 pendingExits = new ListBuffer<>();
  1798                 while (exits.nonEmpty()) {
  1799                     P exit = exits.head;
  1800                     exits = exits.tail;
  1801                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1802                     if (isInitialConstructor) {
  1803                         assignToInits(exit.tree, exit.exit_inits);
  1804                         for (int i = firstadr; i < nextadr; i++) {
  1805                             checkInit(exit.tree.pos(), vardecls[i].sym);
  1809             } finally {
  1810                 assignToInits(tree, initsPrev);
  1811                 uninits.assign(uninitsPrev);
  1812                 nextadr = nextadrPrev;
  1813                 firstadr = firstadrPrev;
  1814                 returnadr = returnadrPrev;
  1815                 isInitialConstructor = lastInitialConstructor;
  1819         protected void initParam(JCVariableDecl def) {
  1820             inits.incl(def.sym.adr);
  1821             uninits.excl(def.sym.adr);
  1824         public void visitVarDef(JCVariableDecl tree) {
  1825             boolean track = trackable(tree.sym);
  1826             if (track && tree.sym.owner.kind == MTH) {
  1827                 newVar(tree);
  1829             if (tree.init != null) {
  1830                 scanExpr(tree.init);
  1831                 if (track) {
  1832                     letInit(tree.pos(), tree.sym);
  1837         public void visitBlock(JCBlock tree) {
  1838             int nextadrPrev = nextadr;
  1839             scan(tree.stats);
  1840             nextadr = nextadrPrev;
  1843         int getLogNumberOfErrors() {
  1844             return 0;
  1847         public void visitDoLoop(JCDoWhileLoop tree) {
  1848             ListBuffer<P> prevPendingExits = pendingExits;
  1849             FlowKind prevFlowKind = flowKind;
  1850             flowKind = FlowKind.NORMAL;
  1851             final Bits initsSkip = new Bits(true);
  1852             final Bits uninitsSkip = new Bits(true);
  1853             pendingExits = new ListBuffer<P>();
  1854             int prevErrors = getLogNumberOfErrors();
  1855             do {
  1856                 final Bits uninitsEntry = new Bits(uninits);
  1857                 uninitsEntry.excludeFrom(nextadr);
  1858                 scan(tree.body);
  1859                 resolveContinues(tree);
  1860                 scanCond(tree.cond);
  1861                 if (!flowKind.isFinal()) {
  1862                     initsSkip.assign(initsWhenFalse);
  1863                     uninitsSkip.assign(uninitsWhenFalse);
  1865                 if (getLogNumberOfErrors() !=  prevErrors ||
  1866                     flowKind.isFinal() ||
  1867                     new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1868                     break;
  1869                 assignToInits(tree.cond, initsWhenTrue);
  1870                 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
  1871                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1872             } while (true);
  1873             flowKind = prevFlowKind;
  1874             assignToInits(tree, initsSkip);
  1875             uninits.assign(uninitsSkip);
  1876             resolveBreaks(tree, prevPendingExits);
  1879         public void visitWhileLoop(JCWhileLoop tree) {
  1880             ListBuffer<P> prevPendingExits = pendingExits;
  1881             FlowKind prevFlowKind = flowKind;
  1882             flowKind = FlowKind.NORMAL;
  1883             final Bits initsSkip = new Bits(true);
  1884             final Bits uninitsSkip = new Bits(true);
  1885             pendingExits = new ListBuffer<>();
  1886             int prevErrors = getLogNumberOfErrors();
  1887             final Bits uninitsEntry = new Bits(uninits);
  1888             uninitsEntry.excludeFrom(nextadr);
  1889             do {
  1890                 scanCond(tree.cond);
  1891                 if (!flowKind.isFinal()) {
  1892                     initsSkip.assign(initsWhenFalse) ;
  1893                     uninitsSkip.assign(uninitsWhenFalse);
  1895                 assignToInits(tree, initsWhenTrue);
  1896                 uninits.assign(uninitsWhenTrue);
  1897                 scan(tree.body);
  1898                 resolveContinues(tree);
  1899                 if (getLogNumberOfErrors() != prevErrors ||
  1900                     flowKind.isFinal() ||
  1901                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
  1902                     break;
  1904                 uninits.assign(uninitsEntry.andSet(uninits));
  1905                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1906             } while (true);
  1907             flowKind = prevFlowKind;
  1908             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
  1909             //branch is not taken AND if it's DA/DU before any break statement
  1910             assignToInits(tree.body, initsSkip);
  1911             uninits.assign(uninitsSkip);
  1912             resolveBreaks(tree, prevPendingExits);
  1915         public void visitForLoop(JCForLoop tree) {
  1916             ListBuffer<P> prevPendingExits = pendingExits;
  1917             FlowKind prevFlowKind = flowKind;
  1918             flowKind = FlowKind.NORMAL;
  1919             int nextadrPrev = nextadr;
  1920             scan(tree.init);
  1921             final Bits initsSkip = new Bits(true);
  1922             final Bits uninitsSkip = new Bits(true);
  1923             pendingExits = new ListBuffer<P>();
  1924             int prevErrors = getLogNumberOfErrors();
  1925             do {
  1926                 final Bits uninitsEntry = new Bits(uninits);
  1927                 uninitsEntry.excludeFrom(nextadr);
  1928                 if (tree.cond != null) {
  1929                     scanCond(tree.cond);
  1930                     if (!flowKind.isFinal()) {
  1931                         initsSkip.assign(initsWhenFalse);
  1932                         uninitsSkip.assign(uninitsWhenFalse);
  1934                     assignToInits(tree.body, initsWhenTrue);
  1935                     uninits.assign(uninitsWhenTrue);
  1936                 } else if (!flowKind.isFinal()) {
  1937                     initsSkip.assign(inits);
  1938                     initsSkip.inclRange(firstadr, nextadr);
  1939                     uninitsSkip.assign(uninits);
  1940                     uninitsSkip.inclRange(firstadr, nextadr);
  1942                 scan(tree.body);
  1943                 resolveContinues(tree);
  1944                 scan(tree.step);
  1945                 if (getLogNumberOfErrors() != prevErrors ||
  1946                     flowKind.isFinal() ||
  1947                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  1948                     break;
  1949                 uninits.assign(uninitsEntry.andSet(uninits));
  1950                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1951             } while (true);
  1952             flowKind = prevFlowKind;
  1953             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
  1954             //branch is not taken AND if it's DA/DU before any break statement
  1955             assignToInits(tree.body, initsSkip);
  1956             uninits.assign(uninitsSkip);
  1957             resolveBreaks(tree, prevPendingExits);
  1958             nextadr = nextadrPrev;
  1961         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1962             visitVarDef(tree.var);
  1964             ListBuffer<P> prevPendingExits = pendingExits;
  1965             FlowKind prevFlowKind = flowKind;
  1966             flowKind = FlowKind.NORMAL;
  1967             int nextadrPrev = nextadr;
  1968             scan(tree.expr);
  1969             final Bits initsStart = new Bits(inits);
  1970             final Bits uninitsStart = new Bits(uninits);
  1972             letInit(tree.pos(), tree.var.sym);
  1973             pendingExits = new ListBuffer<P>();
  1974             int prevErrors = getLogNumberOfErrors();
  1975             do {
  1976                 final Bits uninitsEntry = new Bits(uninits);
  1977                 uninitsEntry.excludeFrom(nextadr);
  1978                 scan(tree.body);
  1979                 resolveContinues(tree);
  1980                 if (getLogNumberOfErrors() != prevErrors ||
  1981                     flowKind.isFinal() ||
  1982                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  1983                     break;
  1984                 uninits.assign(uninitsEntry.andSet(uninits));
  1985                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1986             } while (true);
  1987             flowKind = prevFlowKind;
  1988             assignToInits(tree.body, initsStart);
  1989             uninits.assign(uninitsStart.andSet(uninits));
  1990             resolveBreaks(tree, prevPendingExits);
  1991             nextadr = nextadrPrev;
  1994         public void visitLabelled(JCLabeledStatement tree) {
  1995             ListBuffer<P> prevPendingExits = pendingExits;
  1996             pendingExits = new ListBuffer<P>();
  1997             scan(tree.body);
  1998             resolveBreaks(tree, prevPendingExits);
  2001         public void visitSwitch(JCSwitch tree) {
  2002             ListBuffer<P> prevPendingExits = pendingExits;
  2003             pendingExits = new ListBuffer<>();
  2004             int nextadrPrev = nextadr;
  2005             scanExpr(tree.selector);
  2006             final Bits initsSwitch = new Bits(inits);
  2007             final Bits uninitsSwitch = new Bits(uninits);
  2008             boolean hasDefault = false;
  2009             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  2010                 assignToInits(l.head, initsSwitch);
  2011                 uninits.assign(uninits.andSet(uninitsSwitch));
  2012                 JCCase c = l.head;
  2013                 if (c.pat == null) {
  2014                     hasDefault = true;
  2015                 } else {
  2016                     scanExpr(c.pat);
  2018                 if (hasDefault) {
  2019                     assignToInits(null, initsSwitch);
  2020                     uninits.assign(uninits.andSet(uninitsSwitch));
  2022                 scan(c.stats);
  2023                 addVars(c.stats, initsSwitch, uninitsSwitch);
  2024                 if (!hasDefault) {
  2025                     assignToInits(l.head.stats.last(), initsSwitch);
  2026                     uninits.assign(uninits.andSet(uninitsSwitch));
  2028                 // Warn about fall-through if lint switch fallthrough enabled.
  2030             if (!hasDefault) {
  2031                 andSetInits(null, initsSwitch);
  2033             resolveBreaks(tree, prevPendingExits);
  2034             nextadr = nextadrPrev;
  2036         // where
  2037             /** Add any variables defined in stats to inits and uninits. */
  2038             private void addVars(List<JCStatement> stats, final Bits inits,
  2039                                         final Bits uninits) {
  2040                 for (;stats.nonEmpty(); stats = stats.tail) {
  2041                     JCTree stat = stats.head;
  2042                     if (stat.hasTag(VARDEF)) {
  2043                         int adr = ((JCVariableDecl) stat).sym.adr;
  2044                         inits.excl(adr);
  2045                         uninits.incl(adr);
  2050         boolean isEnabled(Lint.LintCategory lc) {
  2051             return false;
  2054         void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {}
  2056         public void visitTry(JCTry tree) {
  2057             ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
  2058             final Bits uninitsTryPrev = new Bits(uninitsTry);
  2059             ListBuffer<P> prevPendingExits = pendingExits;
  2060             pendingExits = new ListBuffer<>();
  2061             final Bits initsTry = new Bits(inits);
  2062             uninitsTry.assign(uninits);
  2063             for (JCTree resource : tree.resources) {
  2064                 if (resource instanceof JCVariableDecl) {
  2065                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  2066                     visitVarDef(vdecl);
  2067                     unrefdResources.enter(vdecl.sym);
  2068                     resourceVarDecls.append(vdecl);
  2069                 } else if (resource instanceof JCExpression) {
  2070                     scanExpr((JCExpression) resource);
  2071                 } else {
  2072                     throw new AssertionError(tree);  // parser error
  2075             scan(tree.body);
  2076             uninitsTry.andSet(uninits);
  2077             final Bits initsEnd = new Bits(inits);
  2078             final Bits uninitsEnd = new Bits(uninits);
  2079             int nextadrCatch = nextadr;
  2081             if (!resourceVarDecls.isEmpty() &&
  2082                     isEnabled(Lint.LintCategory.TRY)) {
  2083                 for (JCVariableDecl resVar : resourceVarDecls) {
  2084                     if (unrefdResources.includes(resVar.sym)) {
  2085                         reportWarning(Lint.LintCategory.TRY, resVar.pos(),
  2086                                     "try.resource.not.referenced", resVar.sym);
  2087                         unrefdResources.remove(resVar.sym);
  2092             /*  The analysis of each catch should be independent.
  2093              *  Each one should have the same initial values of inits and
  2094              *  uninits.
  2095              */
  2096             final Bits initsCatchPrev = new Bits(initsTry);
  2097             final Bits uninitsCatchPrev = new Bits(uninitsTry);
  2099             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  2100                 JCVariableDecl param = l.head.param;
  2101                 assignToInits(tree.body, initsCatchPrev);
  2102                 uninits.assign(uninitsCatchPrev);
  2103                 scan(param);
  2104                 /* If this is a TWR and we are executing the code from Gen,
  2105                  * then there can be synthetic variables, ignore them.
  2106                  */
  2107                 initParam(param);
  2108                 scan(l.head.body);
  2109                 initsEnd.andSet(inits);
  2110                 uninitsEnd.andSet(uninits);
  2111                 nextadr = nextadrCatch;
  2113             if (tree.finalizer != null) {
  2114                 assignToInits(tree.finalizer, initsTry);
  2115                 uninits.assign(uninitsTry);
  2116                 ListBuffer<P> exits = pendingExits;
  2117                 pendingExits = prevPendingExits;
  2118                 scan(tree.finalizer);
  2119                 if (!tree.finallyCanCompleteNormally) {
  2120                     // discard exits and exceptions from try and finally
  2121                 } else {
  2122                     uninits.andSet(uninitsEnd);
  2123                     // FIX: this doesn't preserve source order of exits in catch
  2124                     // versus finally!
  2125                     while (exits.nonEmpty()) {
  2126                         P exit = exits.next();
  2127                         if (exit.exit_inits != null) {
  2128                             exit.exit_inits.orSet(inits);
  2129                             exit.exit_uninits.andSet(uninits);
  2131                         pendingExits.append(exit);
  2133                     orSetInits(tree, initsEnd);
  2135             } else {
  2136                 assignToInits(tree, initsEnd);
  2137                 uninits.assign(uninitsEnd);
  2138                 ListBuffer<P> exits = pendingExits;
  2139                 pendingExits = prevPendingExits;
  2140                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  2142             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  2145         public void visitConditional(JCConditional tree) {
  2146             scanCond(tree.cond);
  2147             final Bits initsBeforeElse = new Bits(initsWhenFalse);
  2148             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
  2149             assignToInits(tree.cond, initsWhenTrue);
  2150             uninits.assign(uninitsWhenTrue);
  2151             if (tree.truepart.type.hasTag(BOOLEAN) &&
  2152                 tree.falsepart.type.hasTag(BOOLEAN)) {
  2153                 // if b and c are boolean valued, then
  2154                 // v is (un)assigned after a?b:c when true iff
  2155                 //    v is (un)assigned after b when true and
  2156                 //    v is (un)assigned after c when true
  2157                 scanCond(tree.truepart);
  2158                 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
  2159                 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
  2160                 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
  2161                 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
  2162                 assignToInits(tree.truepart, initsBeforeElse);
  2163                 uninits.assign(uninitsBeforeElse);
  2164                 scanCond(tree.falsepart);
  2165                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
  2166                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
  2167                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
  2168                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
  2169             } else {
  2170                 scanExpr(tree.truepart);
  2171                 final Bits initsAfterThen = new Bits(inits);
  2172                 final Bits uninitsAfterThen = new Bits(uninits);
  2173                 assignToInits(tree.truepart, initsBeforeElse);
  2174                 uninits.assign(uninitsBeforeElse);
  2175                 scanExpr(tree.falsepart);
  2176                 andSetInits(tree.falsepart, initsAfterThen);
  2177                 uninits.andSet(uninitsAfterThen);
  2181         public void visitIf(JCIf tree) {
  2182             scanCond(tree.cond);
  2183             final Bits initsBeforeElse = new Bits(initsWhenFalse);
  2184             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
  2185             assignToInits(tree.cond, initsWhenTrue);
  2186             uninits.assign(uninitsWhenTrue);
  2187             scan(tree.thenpart);
  2188             if (tree.elsepart != null) {
  2189                 final Bits initsAfterThen = new Bits(inits);
  2190                 final Bits uninitsAfterThen = new Bits(uninits);
  2191                 assignToInits(tree.thenpart, initsBeforeElse);
  2192                 uninits.assign(uninitsBeforeElse);
  2193                 scan(tree.elsepart);
  2194                 andSetInits(tree.elsepart, initsAfterThen);
  2195                 uninits.andSet(uninitsAfterThen);
  2196             } else {
  2197                 andSetInits(tree.thenpart, initsBeforeElse);
  2198                 uninits.andSet(uninitsBeforeElse);
  2202         protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
  2203             return null;
  2206         @Override
  2207         public void visitBreak(JCBreak tree) {
  2208             recordExit(tree, createNewPendingExit(tree, inits, uninits));
  2211         @Override
  2212         public void visitContinue(JCContinue tree) {
  2213             recordExit(tree, createNewPendingExit(tree, inits, uninits));
  2216         @Override
  2217         public void visitReturn(JCReturn tree) {
  2218             scanExpr(tree.expr);
  2219             recordExit(tree, createNewPendingExit(tree, inits, uninits));
  2222         public void visitThrow(JCThrow tree) {
  2223             scanExpr(tree.expr);
  2224             markDead(tree.expr);
  2227         public void visitApply(JCMethodInvocation tree) {
  2228             scanExpr(tree.meth);
  2229             scanExprs(tree.args);
  2232         public void visitNewClass(JCNewClass tree) {
  2233             scanExpr(tree.encl);
  2234             scanExprs(tree.args);
  2235             scan(tree.def);
  2238         @Override
  2239         public void visitLambda(JCLambda tree) {
  2240             final Bits prevUninits = new Bits(uninits);
  2241             final Bits prevInits = new Bits(inits);
  2242             int returnadrPrev = returnadr;
  2243             ListBuffer<P> prevPending = pendingExits;
  2244             try {
  2245                 returnadr = nextadr;
  2246                 pendingExits = new ListBuffer<P>();
  2247                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  2248                     JCVariableDecl def = l.head;
  2249                     scan(def);
  2250                     inits.incl(def.sym.adr);
  2251                     uninits.excl(def.sym.adr);
  2253                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
  2254                     scanExpr(tree.body);
  2255                 } else {
  2256                     scan(tree.body);
  2259             finally {
  2260                 returnadr = returnadrPrev;
  2261                 uninits.assign(prevUninits);
  2262                 assignToInits(tree, prevInits);
  2263                 pendingExits = prevPending;
  2267         public void visitNewArray(JCNewArray tree) {
  2268             scanExprs(tree.dims);
  2269             scanExprs(tree.elems);
  2272         public void visitAssert(JCAssert tree) {
  2273             final Bits initsExit = new Bits(inits);
  2274             final Bits uninitsExit = new Bits(uninits);
  2275             scanCond(tree.cond);
  2276             uninitsExit.andSet(uninitsWhenTrue);
  2277             if (tree.detail != null) {
  2278                 assignToInits(tree, initsWhenFalse);
  2279                 uninits.assign(uninitsWhenFalse);
  2280                 scanExpr(tree.detail);
  2282             assignToInits(tree, initsExit);
  2283             uninits.assign(uninitsExit);
  2286         public void visitAssign(JCAssign tree) {
  2287             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2288             if (!isIdentOrThisDotIdent(lhs))
  2289                 scanExpr(lhs);
  2290             scanExpr(tree.rhs);
  2291             letInit(lhs);
  2293         private boolean isIdentOrThisDotIdent(JCTree lhs) {
  2294             if (lhs.hasTag(IDENT))
  2295                 return true;
  2296             if (!lhs.hasTag(SELECT))
  2297                 return false;
  2299             JCFieldAccess fa = (JCFieldAccess)lhs;
  2300             return fa.selected.hasTag(IDENT) &&
  2301                    ((JCIdent)fa.selected).name == names._this;
  2304         // check fields accessed through this.<field> are definitely
  2305         // assigned before reading their value
  2306         public void visitSelect(JCFieldAccess tree) {
  2307             super.visitSelect(tree);
  2308             if (enforceThisDotInit &&
  2309                 tree.selected.hasTag(IDENT) &&
  2310                 ((JCIdent)tree.selected).name == names._this &&
  2311                 tree.sym.kind == VAR)
  2313                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2317         public void visitAssignop(JCAssignOp tree) {
  2318             scanExpr(tree.lhs);
  2319             scanExpr(tree.rhs);
  2320             letInit(tree.lhs);
  2323         public void visitUnary(JCUnary tree) {
  2324             switch (tree.getTag()) {
  2325             case NOT:
  2326                 scanCond(tree.arg);
  2327                 final Bits t = new Bits(initsWhenFalse);
  2328                 initsWhenFalse.assign(initsWhenTrue);
  2329                 initsWhenTrue.assign(t);
  2330                 t.assign(uninitsWhenFalse);
  2331                 uninitsWhenFalse.assign(uninitsWhenTrue);
  2332                 uninitsWhenTrue.assign(t);
  2333                 break;
  2334             case PREINC: case POSTINC:
  2335             case PREDEC: case POSTDEC:
  2336                 scanExpr(tree.arg);
  2337                 letInit(tree.arg);
  2338                 break;
  2339             default:
  2340                 scanExpr(tree.arg);
  2344         public void visitBinary(JCBinary tree) {
  2345             switch (tree.getTag()) {
  2346             case AND:
  2347                 scanCond(tree.lhs);
  2348                 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
  2349                 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
  2350                 assignToInits(tree.lhs, initsWhenTrue);
  2351                 uninits.assign(uninitsWhenTrue);
  2352                 scanCond(tree.rhs);
  2353                 initsWhenFalse.andSet(initsWhenFalseLeft);
  2354                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
  2355                 break;
  2356             case OR:
  2357                 scanCond(tree.lhs);
  2358                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
  2359                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
  2360                 assignToInits(tree.lhs, initsWhenFalse);
  2361                 uninits.assign(uninitsWhenFalse);
  2362                 scanCond(tree.rhs);
  2363                 initsWhenTrue.andSet(initsWhenTrueLeft);
  2364                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
  2365                 break;
  2366             default:
  2367                 scanExpr(tree.lhs);
  2368                 scanExpr(tree.rhs);
  2372         public void visitIdent(JCIdent tree) {
  2373             if (tree.sym.kind == VAR) {
  2374                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2375                 referenced(tree.sym);
  2379         void referenced(Symbol sym) {
  2380             unrefdResources.remove(sym);
  2383         public void visitAnnotatedType(JCAnnotatedType tree) {
  2384             // annotations don't get scanned
  2385             tree.underlyingType.accept(this);
  2388         public void visitTopLevel(JCCompilationUnit tree) {
  2389             // Do nothing for TopLevel since each class is visited individually
  2392     /**************************************************************************
  2393      * main method
  2394      *************************************************************************/
  2396         /** Perform definite assignment/unassignment analysis on a tree.
  2397          */
  2398         public void analyzeTree(Env<?> env) {
  2399             analyzeTree(env, env.tree);
  2402         public void analyzeTree(Env<?> env, JCTree tree) {
  2403             try {
  2404                 startPos = tree.pos().getStartPosition();
  2406                 if (vardecls == null)
  2407                     vardecls = new JCVariableDecl[32];
  2408                 else
  2409                     for (int i=0; i<vardecls.length; i++)
  2410                         vardecls[i] = null;
  2411                 firstadr = 0;
  2412                 nextadr = 0;
  2413                 pendingExits = new ListBuffer<>();
  2414                 this.classDef = null;
  2415                 unrefdResources = new Scope(env.enclClass.sym);
  2416                 scan(tree);
  2417             } finally {
  2418                 // note that recursive invocations of this method fail hard
  2419                 startPos = -1;
  2420                 resetBits(inits, uninits, uninitsTry, initsWhenTrue,
  2421                         initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
  2422                 if (vardecls != null) {
  2423                     for (int i=0; i<vardecls.length; i++)
  2424                         vardecls[i] = null;
  2426                 firstadr = 0;
  2427                 nextadr = 0;
  2428                 pendingExits = null;
  2429                 this.classDef = null;
  2430                 unrefdResources = null;
  2435     public static class AssignAnalyzer
  2436         extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> {
  2438         Log log;
  2439         Lint lint;
  2441         public static class AssignPendingExit
  2442             extends AbstractAssignAnalyzer.AbstractAssignPendingExit {
  2444             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
  2445                 super(tree, inits, uninits);
  2449         public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names, boolean enforceThisDotInit) {
  2450             super(new Bits(), syms, names, enforceThisDotInit);
  2451             this.log = log;
  2452             this.lint = lint;
  2455         @Override
  2456         protected AssignPendingExit createNewPendingExit(JCTree tree,
  2457             Bits inits, Bits uninits) {
  2458             return new AssignPendingExit(tree, inits, uninits);
  2461         /** Record an initialization of a trackable variable.
  2462          */
  2463         @Override
  2464         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  2465             if (sym.adr >= firstadr && trackable(sym)) {
  2466                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
  2467                     if (!uninits.isMember(sym.adr)) {
  2468                         //assignment targeting an effectively final variable
  2469                         //makes the variable lose its status of effectively final
  2470                         //if the variable is _not_ definitively unassigned
  2471                         sym.flags_field &= ~EFFECTIVELY_FINAL;
  2472                     } else {
  2473                         uninit(sym);
  2476                 else if ((sym.flags() & FINAL) != 0) {
  2477                     if ((sym.flags() & PARAMETER) != 0) {
  2478                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  2479                             log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
  2481                         else {
  2482                             log.error(pos, "final.parameter.may.not.be.assigned",
  2483                                   sym);
  2485                     } else if (!uninits.isMember(sym.adr)) {
  2486                         log.error(pos, flowKind.errKey, sym);
  2487                     } else {
  2488                         uninit(sym);
  2491                 inits.incl(sym.adr);
  2492             } else if ((sym.flags() & FINAL) != 0) {
  2493                 log.error(pos, "var.might.already.be.assigned", sym);
  2497         @Override
  2498         void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
  2499             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  2500                 trackable(sym) &&
  2501                 !inits.isMember(sym.adr)) {
  2502                 log.error(pos, errkey, sym);
  2503                 inits.incl(sym.adr);
  2507         @Override
  2508         void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
  2509             String key, Object ... args) {
  2510             log.warning(lc, pos, key, args);
  2513         @Override
  2514         int getLogNumberOfErrors() {
  2515             return log.nerrors;
  2518         @Override
  2519         boolean isEnabled(Lint.LintCategory lc) {
  2520             return lint.isEnabled(lc);
  2523         @Override
  2524         public void visitClassDef(JCClassDecl tree) {
  2525             if (tree.sym == null) {
  2526                 return;
  2529             Lint lintPrev = lint;
  2530             lint = lint.augment(tree.sym);
  2531             try {
  2532                 super.visitClassDef(tree);
  2533             } finally {
  2534                 lint = lintPrev;
  2538         @Override
  2539         public void visitMethodDef(JCMethodDecl tree) {
  2540             if (tree.body == null) {
  2541                 return;
  2544             /*  MemberEnter can generate synthetic methods ignore them
  2545              */
  2546             if ((tree.sym.flags() & SYNTHETIC) != 0) {
  2547                 return;
  2550             Lint lintPrev = lint;
  2551             lint = lint.augment(tree.sym);
  2552             try {
  2553                 super.visitMethodDef(tree);
  2554             } finally {
  2555                 lint = lintPrev;
  2559         @Override
  2560         public void visitVarDef(JCVariableDecl tree) {
  2561             if (tree.init == null) {
  2562                 super.visitVarDef(tree);
  2563             } else {
  2564                 Lint lintPrev = lint;
  2565                 lint = lint.augment(tree.sym);
  2566                 try{
  2567                     super.visitVarDef(tree);
  2568                 } finally {
  2569                     lint = lintPrev;
  2576     /**
  2577      * This pass implements the last step of the dataflow analysis, namely
  2578      * the effectively-final analysis check. This checks that every local variable
  2579      * reference from a lambda body/local inner class is either final or effectively final.
  2580      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2581      * AssignAnalyzer.
  2582      */
  2583     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
  2585         JCTree currentTree; //local class or lambda
  2587         @Override
  2588         void markDead(JCTree tree) {
  2589             //do nothing
  2592         @SuppressWarnings("fallthrough")
  2593         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
  2594             if (currentTree != null &&
  2595                     sym.owner.kind == MTH &&
  2596                     sym.pos < currentTree.getStartPosition()) {
  2597                 switch (currentTree.getTag()) {
  2598                     case CLASSDEF:
  2599                         if (!allowEffectivelyFinalInInnerClasses) {
  2600                             if ((sym.flags() & FINAL) == 0) {
  2601                                 reportInnerClsNeedsFinalError(pos, sym);
  2603                             break;
  2605                     case LAMBDA:
  2606                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
  2607                            reportEffectivelyFinalError(pos, sym);
  2613         @SuppressWarnings("fallthrough")
  2614         void letInit(JCTree tree) {
  2615             tree = TreeInfo.skipParens(tree);
  2616             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  2617                 Symbol sym = TreeInfo.symbol(tree);
  2618                 if (currentTree != null &&
  2619                         sym.kind == VAR &&
  2620                         sym.owner.kind == MTH &&
  2621                         ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
  2622                     switch (currentTree.getTag()) {
  2623                         case CLASSDEF:
  2624                             if (!allowEffectivelyFinalInInnerClasses) {
  2625                                 reportInnerClsNeedsFinalError(tree, sym);
  2626                                 break;
  2628                         case LAMBDA:
  2629                             reportEffectivelyFinalError(tree, sym);
  2635         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
  2636             String subKey = currentTree.hasTag(LAMBDA) ?
  2637                   "lambda"  : "inner.cls";
  2638             log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
  2641         void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
  2642             log.error(pos,
  2643                     "local.var.accessed.from.icls.needs.final",
  2644                     sym);
  2647     /*************************************************************************
  2648      * Visitor methods for statements and definitions
  2649      *************************************************************************/
  2651         /* ------------ Visitor methods for various sorts of trees -------------*/
  2653         public void visitClassDef(JCClassDecl tree) {
  2654             JCTree prevTree = currentTree;
  2655             try {
  2656                 currentTree = tree.sym.isLocal() ? tree : null;
  2657                 super.visitClassDef(tree);
  2658             } finally {
  2659                 currentTree = prevTree;
  2663         @Override
  2664         public void visitLambda(JCLambda tree) {
  2665             JCTree prevTree = currentTree;
  2666             try {
  2667                 currentTree = tree;
  2668                 super.visitLambda(tree);
  2669             } finally {
  2670                 currentTree = prevTree;
  2674         @Override
  2675         public void visitIdent(JCIdent tree) {
  2676             if (tree.sym.kind == VAR) {
  2677                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
  2681         public void visitAssign(JCAssign tree) {
  2682             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2683             if (!(lhs instanceof JCIdent)) {
  2684                 scan(lhs);
  2686             scan(tree.rhs);
  2687             letInit(lhs);
  2690         public void visitAssignop(JCAssignOp tree) {
  2691             scan(tree.lhs);
  2692             scan(tree.rhs);
  2693             letInit(tree.lhs);
  2696         public void visitUnary(JCUnary tree) {
  2697             switch (tree.getTag()) {
  2698                 case PREINC: case POSTINC:
  2699                 case PREDEC: case POSTDEC:
  2700                     scan(tree.arg);
  2701                     letInit(tree.arg);
  2702                     break;
  2703                 default:
  2704                     scan(tree.arg);
  2708         public void visitTopLevel(JCCompilationUnit tree) {
  2709             // Do nothing for TopLevel since each class is visited individually
  2712     /**************************************************************************
  2713      * main method
  2714      *************************************************************************/
  2716         /** Perform definite assignment/unassignment analysis on a tree.
  2717          */
  2718         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2719             analyzeTree(env, env.tree, make);
  2721         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2722             try {
  2723                 attrEnv = env;
  2724                 Flow.this.make = make;
  2725                 pendingExits = new ListBuffer<PendingExit>();
  2726                 scan(tree);
  2727             } finally {
  2728                 pendingExits = null;
  2729                 Flow.this.make = null;

mercurial