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

Tue, 09 Sep 2014 10:43:06 -0700

author
vromero
date
Tue, 09 Sep 2014 10:43:06 -0700
changeset 2566
58e7e71b302e
parent 2408
716f2466ddd0
child 2591
fc1b69dce787
permissions
-rw-r--r--

8042347: javac, Gen.LVTAssignAnalyzer should be refactored, it shouldn't be a static class
Reviewed-by: mcimadamore, jjg, 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().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(final Env<AttrContext> env,
   236             JCLambda that, TreeMaker make) {
   237         //we need to disable diagnostics temporarily; the problem is that if
   238         //a lambda expression contains e.g. an unreachable statement, an error
   239         //message will be reported and will cause compilation to skip the flow analyis
   240         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
   241         //related errors, which will allow for more errors to be detected
   242         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
   243         try {
   244             new AssignAnalyzer() {
   245                 @Override
   246                 protected boolean trackable(VarSymbol sym) {
   247                     return !env.info.scope.includes(sym) &&
   248                            sym.owner.kind == MTH;
   249                 }
   250             }.analyzeTree(env);
   251             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
   252             flowAnalyzer.analyzeTree(env, that, make);
   253             return flowAnalyzer.inferredThrownTypes;
   254         } finally {
   255             log.popDiagnosticHandler(diagHandler);
   256         }
   257     }
   259     /**
   260      * Definite assignment scan mode
   261      */
   262     enum FlowKind {
   263         /**
   264          * This is the normal DA/DU analysis mode
   265          */
   266         NORMAL("var.might.already.be.assigned", false),
   267         /**
   268          * This is the speculative DA/DU analysis mode used to speculatively
   269          * derive assertions within loop bodies
   270          */
   271         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
   273         final String errKey;
   274         final boolean isFinal;
   276         FlowKind(String errKey, boolean isFinal) {
   277             this.errKey = errKey;
   278             this.isFinal = isFinal;
   279         }
   281         boolean isFinal() {
   282             return isFinal;
   283         }
   284     }
   286     protected Flow(Context context) {
   287         context.put(flowKey, this);
   288         names = Names.instance(context);
   289         log = Log.instance(context);
   290         syms = Symtab.instance(context);
   291         types = Types.instance(context);
   292         chk = Check.instance(context);
   293         lint = Lint.instance(context);
   294         rs = Resolve.instance(context);
   295         diags = JCDiagnostic.Factory.instance(context);
   296         Source source = Source.instance(context);
   297         allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
   298         allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
   299         allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
   300         enforceThisDotInit = source.enforceThisDotInit();
   301     }
   303     /**
   304      * Base visitor class for all visitors implementing dataflow analysis logic.
   305      * This class define the shared logic for handling jumps (break/continue statements).
   306      */
   307     static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
   309         enum JumpKind {
   310             BREAK(JCTree.Tag.BREAK) {
   311                 @Override
   312                 JCTree getTarget(JCTree tree) {
   313                     return ((JCBreak)tree).target;
   314                 }
   315             },
   316             CONTINUE(JCTree.Tag.CONTINUE) {
   317                 @Override
   318                 JCTree getTarget(JCTree tree) {
   319                     return ((JCContinue)tree).target;
   320                 }
   321             };
   323             final JCTree.Tag treeTag;
   325             private JumpKind(Tag treeTag) {
   326                 this.treeTag = treeTag;
   327             }
   329             abstract JCTree getTarget(JCTree tree);
   330         }
   332         /** The currently pending exits that go from current inner blocks
   333          *  to an enclosing block, in source order.
   334          */
   335         ListBuffer<P> pendingExits;
   337         /** A pending exit.  These are the statements return, break, and
   338          *  continue.  In addition, exception-throwing expressions or
   339          *  statements are put here when not known to be caught.  This
   340          *  will typically result in an error unless it is within a
   341          *  try-finally whose finally block cannot complete normally.
   342          */
   343         static class PendingExit {
   344             JCTree tree;
   346             PendingExit(JCTree tree) {
   347                 this.tree = tree;
   348             }
   350             void resolveJump(JCTree tree) {
   351                 //do nothing
   352             }
   353         }
   355         abstract void markDead(JCTree tree);
   357         /** Record an outward transfer of control. */
   358         void recordExit(JCTree tree, P pe) {
   359             pendingExits.append(pe);
   360             markDead(tree);
   361         }
   363         /** Resolve all jumps of this statement. */
   364         private boolean resolveJump(JCTree tree,
   365                         ListBuffer<P> oldPendingExits,
   366                         JumpKind jk) {
   367             boolean resolved = false;
   368             List<P> exits = pendingExits.toList();
   369             pendingExits = oldPendingExits;
   370             for (; exits.nonEmpty(); exits = exits.tail) {
   371                 P exit = exits.head;
   372                 if (exit.tree.hasTag(jk.treeTag) &&
   373                         jk.getTarget(exit.tree) == tree) {
   374                     exit.resolveJump(tree);
   375                     resolved = true;
   376                 } else {
   377                     pendingExits.append(exit);
   378                 }
   379             }
   380             return resolved;
   381         }
   383         /** Resolve all continues of this statement. */
   384         boolean resolveContinues(JCTree tree) {
   385             return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
   386         }
   388         /** Resolve all breaks of this statement. */
   389         boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
   390             return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
   391         }
   393         @Override
   394         public void scan(JCTree tree) {
   395             if (tree != null && (
   396                     tree.type == null ||
   397                     tree.type != Type.stuckType)) {
   398                 super.scan(tree);
   399             }
   400         }
   401     }
   403     /**
   404      * This pass implements the first step of the dataflow analysis, namely
   405      * the liveness analysis check. This checks that every statement is reachable.
   406      * The output of this analysis pass are used by other analyzers. This analyzer
   407      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
   408      */
   409     class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
   411         /** A flag that indicates whether the last statement could
   412          *  complete normally.
   413          */
   414         private boolean alive;
   416         @Override
   417         void markDead(JCTree tree) {
   418             alive = false;
   419         }
   421     /*************************************************************************
   422      * Visitor methods for statements and definitions
   423      *************************************************************************/
   425         /** Analyze a definition.
   426          */
   427         void scanDef(JCTree tree) {
   428             scanStat(tree);
   429             if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
   430                 log.error(tree.pos(),
   431                           "initializer.must.be.able.to.complete.normally");
   432             }
   433         }
   435         /** Analyze a statement. Check that statement is reachable.
   436          */
   437         void scanStat(JCTree tree) {
   438             if (!alive && tree != null) {
   439                 log.error(tree.pos(), "unreachable.stmt");
   440                 if (!tree.hasTag(SKIP)) alive = true;
   441             }
   442             scan(tree);
   443         }
   445         /** Analyze list of statements.
   446          */
   447         void scanStats(List<? extends JCStatement> trees) {
   448             if (trees != null)
   449                 for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
   450                     scanStat(l.head);
   451         }
   453         /* ------------ Visitor methods for various sorts of trees -------------*/
   455         public void visitClassDef(JCClassDecl tree) {
   456             if (tree.sym == null) return;
   457             boolean alivePrev = alive;
   458             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
   459             Lint lintPrev = lint;
   461             pendingExits = new ListBuffer<PendingExit>();
   462             lint = lint.augment(tree.sym);
   464             try {
   465                 // process all the static initializers
   466                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   467                     if (!l.head.hasTag(METHODDEF) &&
   468                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   469                         scanDef(l.head);
   470                     }
   471                 }
   473                 // process all the instance initializers
   474                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   475                     if (!l.head.hasTag(METHODDEF) &&
   476                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   477                         scanDef(l.head);
   478                     }
   479                 }
   481                 // process all the methods
   482                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   483                     if (l.head.hasTag(METHODDEF)) {
   484                         scan(l.head);
   485                     }
   486                 }
   487             } finally {
   488                 pendingExits = pendingExitsPrev;
   489                 alive = alivePrev;
   490                 lint = lintPrev;
   491             }
   492         }
   494         public void visitMethodDef(JCMethodDecl tree) {
   495             if (tree.body == null) return;
   496             Lint lintPrev = lint;
   498             lint = lint.augment(tree.sym);
   500             Assert.check(pendingExits.isEmpty());
   502             try {
   503                 alive = true;
   504                 scanStat(tree.body);
   506                 if (alive && !tree.sym.type.getReturnType().hasTag(VOID))
   507                     log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
   509                 List<PendingExit> exits = pendingExits.toList();
   510                 pendingExits = new ListBuffer<PendingExit>();
   511                 while (exits.nonEmpty()) {
   512                     PendingExit exit = exits.head;
   513                     exits = exits.tail;
   514                     Assert.check(exit.tree.hasTag(RETURN));
   515                 }
   516             } finally {
   517                 lint = lintPrev;
   518             }
   519         }
   521         public void visitVarDef(JCVariableDecl tree) {
   522             if (tree.init != null) {
   523                 Lint lintPrev = lint;
   524                 lint = lint.augment(tree.sym);
   525                 try{
   526                     scan(tree.init);
   527                 } finally {
   528                     lint = lintPrev;
   529                 }
   530             }
   531         }
   533         public void visitBlock(JCBlock tree) {
   534             scanStats(tree.stats);
   535         }
   537         public void visitDoLoop(JCDoWhileLoop tree) {
   538             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   539             pendingExits = new ListBuffer<PendingExit>();
   540             scanStat(tree.body);
   541             alive |= resolveContinues(tree);
   542             scan(tree.cond);
   543             alive = alive && !tree.cond.type.isTrue();
   544             alive |= resolveBreaks(tree, prevPendingExits);
   545         }
   547         public void visitWhileLoop(JCWhileLoop tree) {
   548             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   549             pendingExits = new ListBuffer<PendingExit>();
   550             scan(tree.cond);
   551             alive = !tree.cond.type.isFalse();
   552             scanStat(tree.body);
   553             alive |= resolveContinues(tree);
   554             alive = resolveBreaks(tree, prevPendingExits) ||
   555                 !tree.cond.type.isTrue();
   556         }
   558         public void visitForLoop(JCForLoop tree) {
   559             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   560             scanStats(tree.init);
   561             pendingExits = new ListBuffer<PendingExit>();
   562             if (tree.cond != null) {
   563                 scan(tree.cond);
   564                 alive = !tree.cond.type.isFalse();
   565             } else {
   566                 alive = true;
   567             }
   568             scanStat(tree.body);
   569             alive |= resolveContinues(tree);
   570             scan(tree.step);
   571             alive = resolveBreaks(tree, prevPendingExits) ||
   572                 tree.cond != null && !tree.cond.type.isTrue();
   573         }
   575         public void visitForeachLoop(JCEnhancedForLoop tree) {
   576             visitVarDef(tree.var);
   577             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   578             scan(tree.expr);
   579             pendingExits = new ListBuffer<PendingExit>();
   580             scanStat(tree.body);
   581             alive |= resolveContinues(tree);
   582             resolveBreaks(tree, prevPendingExits);
   583             alive = true;
   584         }
   586         public void visitLabelled(JCLabeledStatement tree) {
   587             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   588             pendingExits = new ListBuffer<PendingExit>();
   589             scanStat(tree.body);
   590             alive |= resolveBreaks(tree, prevPendingExits);
   591         }
   593         public void visitSwitch(JCSwitch tree) {
   594             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   595             pendingExits = new ListBuffer<PendingExit>();
   596             scan(tree.selector);
   597             boolean hasDefault = false;
   598             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
   599                 alive = true;
   600                 JCCase c = l.head;
   601                 if (c.pat == null)
   602                     hasDefault = true;
   603                 else
   604                     scan(c.pat);
   605                 scanStats(c.stats);
   606                 // Warn about fall-through if lint switch fallthrough enabled.
   607                 if (alive &&
   608                     lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
   609                     c.stats.nonEmpty() && l.tail.nonEmpty())
   610                     log.warning(Lint.LintCategory.FALLTHROUGH,
   611                                 l.tail.head.pos(),
   612                                 "possible.fall-through.into.case");
   613             }
   614             if (!hasDefault) {
   615                 alive = true;
   616             }
   617             alive |= resolveBreaks(tree, prevPendingExits);
   618         }
   620         public void visitTry(JCTry tree) {
   621             ListBuffer<PendingExit> prevPendingExits = pendingExits;
   622             pendingExits = new ListBuffer<PendingExit>();
   623             for (JCTree resource : tree.resources) {
   624                 if (resource instanceof JCVariableDecl) {
   625                     JCVariableDecl vdecl = (JCVariableDecl) resource;
   626                     visitVarDef(vdecl);
   627                 } else if (resource instanceof JCExpression) {
   628                     scan((JCExpression) resource);
   629                 } else {
   630                     throw new AssertionError(tree);  // parser error
   631                 }
   632             }
   634             scanStat(tree.body);
   635             boolean aliveEnd = alive;
   637             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
   638                 alive = true;
   639                 JCVariableDecl param = l.head.param;
   640                 scan(param);
   641                 scanStat(l.head.body);
   642                 aliveEnd |= alive;
   643             }
   644             if (tree.finalizer != null) {
   645                 ListBuffer<PendingExit> exits = pendingExits;
   646                 pendingExits = prevPendingExits;
   647                 alive = true;
   648                 scanStat(tree.finalizer);
   649                 tree.finallyCanCompleteNormally = alive;
   650                 if (!alive) {
   651                     if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
   652                         log.warning(Lint.LintCategory.FINALLY,
   653                                 TreeInfo.diagEndPos(tree.finalizer),
   654                                 "finally.cannot.complete");
   655                     }
   656                 } else {
   657                     while (exits.nonEmpty()) {
   658                         pendingExits.append(exits.next());
   659                     }
   660                     alive = aliveEnd;
   661                 }
   662             } else {
   663                 alive = aliveEnd;
   664                 ListBuffer<PendingExit> exits = pendingExits;
   665                 pendingExits = prevPendingExits;
   666                 while (exits.nonEmpty()) pendingExits.append(exits.next());
   667             }
   668         }
   670         @Override
   671         public void visitIf(JCIf tree) {
   672             scan(tree.cond);
   673             scanStat(tree.thenpart);
   674             if (tree.elsepart != null) {
   675                 boolean aliveAfterThen = alive;
   676                 alive = true;
   677                 scanStat(tree.elsepart);
   678                 alive = alive | aliveAfterThen;
   679             } else {
   680                 alive = true;
   681             }
   682         }
   684         public void visitBreak(JCBreak tree) {
   685             recordExit(tree, new PendingExit(tree));
   686         }
   688         public void visitContinue(JCContinue tree) {
   689             recordExit(tree, new PendingExit(tree));
   690         }
   692         public void visitReturn(JCReturn tree) {
   693             scan(tree.expr);
   694             recordExit(tree, new PendingExit(tree));
   695         }
   697         public void visitThrow(JCThrow tree) {
   698             scan(tree.expr);
   699             markDead(tree);
   700         }
   702         public void visitApply(JCMethodInvocation tree) {
   703             scan(tree.meth);
   704             scan(tree.args);
   705         }
   707         public void visitNewClass(JCNewClass tree) {
   708             scan(tree.encl);
   709             scan(tree.args);
   710             if (tree.def != null) {
   711                 scan(tree.def);
   712             }
   713         }
   715         @Override
   716         public void visitLambda(JCLambda tree) {
   717             if (tree.type != null &&
   718                     tree.type.isErroneous()) {
   719                 return;
   720             }
   722             ListBuffer<PendingExit> prevPending = pendingExits;
   723             boolean prevAlive = alive;
   724             try {
   725                 pendingExits = new ListBuffer<>();
   726                 alive = true;
   727                 scanStat(tree.body);
   728                 tree.canCompleteNormally = alive;
   729             }
   730             finally {
   731                 pendingExits = prevPending;
   732                 alive = prevAlive;
   733             }
   734         }
   736         public void visitTopLevel(JCCompilationUnit tree) {
   737             // Do nothing for TopLevel since each class is visited individually
   738         }
   740     /**************************************************************************
   741      * main method
   742      *************************************************************************/
   744         /** Perform definite assignment/unassignment analysis on a tree.
   745          */
   746         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
   747             analyzeTree(env, env.tree, make);
   748         }
   749         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
   750             try {
   751                 attrEnv = env;
   752                 Flow.this.make = make;
   753                 pendingExits = new ListBuffer<PendingExit>();
   754                 alive = true;
   755                 scan(tree);
   756             } finally {
   757                 pendingExits = null;
   758                 Flow.this.make = null;
   759             }
   760         }
   761     }
   763     /**
   764      * This pass implements the second step of the dataflow analysis, namely
   765      * the exception analysis. This is to ensure that every checked exception that is
   766      * thrown is declared or caught. The analyzer uses some info that has been set by
   767      * the liveliness analyzer.
   768      */
   769     class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
   771         /** A flag that indicates whether the last statement could
   772          *  complete normally.
   773          */
   774         HashMap<Symbol, List<Type>> preciseRethrowTypes;
   776         /** The current class being defined.
   777          */
   778         JCClassDecl classDef;
   780         /** The list of possibly thrown declarable exceptions.
   781          */
   782         List<Type> thrown;
   784         /** The list of exceptions that are either caught or declared to be
   785          *  thrown.
   786          */
   787         List<Type> caught;
   789         class FlowPendingExit extends BaseAnalyzer.PendingExit {
   791             Type thrown;
   793             FlowPendingExit(JCTree tree, Type thrown) {
   794                 super(tree);
   795                 this.thrown = thrown;
   796             }
   797         }
   799         @Override
   800         void markDead(JCTree tree) {
   801             //do nothing
   802         }
   804         /*-------------------- Exceptions ----------------------*/
   806         /** Complain that pending exceptions are not caught.
   807          */
   808         void errorUncaught() {
   809             for (FlowPendingExit exit = pendingExits.next();
   810                  exit != null;
   811                  exit = pendingExits.next()) {
   812                 if (classDef != null &&
   813                     classDef.pos == exit.tree.pos) {
   814                     log.error(exit.tree.pos(),
   815                             "unreported.exception.default.constructor",
   816                             exit.thrown);
   817                 } else if (exit.tree.hasTag(VARDEF) &&
   818                         ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
   819                     log.error(exit.tree.pos(),
   820                             "unreported.exception.implicit.close",
   821                             exit.thrown,
   822                             ((JCVariableDecl)exit.tree).sym.name);
   823                 } else {
   824                     log.error(exit.tree.pos(),
   825                             "unreported.exception.need.to.catch.or.throw",
   826                             exit.thrown);
   827                 }
   828             }
   829         }
   831         /** Record that exception is potentially thrown and check that it
   832          *  is caught.
   833          */
   834         void markThrown(JCTree tree, Type exc) {
   835             if (!chk.isUnchecked(tree.pos(), exc)) {
   836                 if (!chk.isHandled(exc, caught)) {
   837                     pendingExits.append(new FlowPendingExit(tree, exc));
   838                 }
   839                 thrown = chk.incl(exc, thrown);
   840             }
   841         }
   843     /*************************************************************************
   844      * Visitor methods for statements and definitions
   845      *************************************************************************/
   847         /* ------------ Visitor methods for various sorts of trees -------------*/
   849         public void visitClassDef(JCClassDecl tree) {
   850             if (tree.sym == null) return;
   852             JCClassDecl classDefPrev = classDef;
   853             List<Type> thrownPrev = thrown;
   854             List<Type> caughtPrev = caught;
   855             ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
   856             Lint lintPrev = lint;
   858             pendingExits = new ListBuffer<FlowPendingExit>();
   859             if (tree.name != names.empty) {
   860                 caught = List.nil();
   861             }
   862             classDef = tree;
   863             thrown = List.nil();
   864             lint = lint.augment(tree.sym);
   866             try {
   867                 // process all the static initializers
   868                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   869                     if (!l.head.hasTag(METHODDEF) &&
   870                         (TreeInfo.flags(l.head) & STATIC) != 0) {
   871                         scan(l.head);
   872                         errorUncaught();
   873                     }
   874                 }
   876                 // add intersection of all thrown clauses of initial constructors
   877                 // to set of caught exceptions, unless class is anonymous.
   878                 if (tree.name != names.empty) {
   879                     boolean firstConstructor = true;
   880                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   881                         if (TreeInfo.isInitialConstructor(l.head)) {
   882                             List<Type> mthrown =
   883                                 ((JCMethodDecl) l.head).sym.type.getThrownTypes();
   884                             if (firstConstructor) {
   885                                 caught = mthrown;
   886                                 firstConstructor = false;
   887                             } else {
   888                                 caught = chk.intersect(mthrown, caught);
   889                             }
   890                         }
   891                     }
   892                 }
   894                 // process all the instance initializers
   895                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   896                     if (!l.head.hasTag(METHODDEF) &&
   897                         (TreeInfo.flags(l.head) & STATIC) == 0) {
   898                         scan(l.head);
   899                         errorUncaught();
   900                     }
   901                 }
   903                 // in an anonymous class, add the set of thrown exceptions to
   904                 // the throws clause of the synthetic constructor and propagate
   905                 // outwards.
   906                 // Changing the throws clause on the fly is okay here because
   907                 // the anonymous constructor can't be invoked anywhere else,
   908                 // and its type hasn't been cached.
   909                 if (tree.name == names.empty) {
   910                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   911                         if (TreeInfo.isInitialConstructor(l.head)) {
   912                             JCMethodDecl mdef = (JCMethodDecl)l.head;
   913                             mdef.thrown = make.Types(thrown);
   914                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
   915                         }
   916                     }
   917                     thrownPrev = chk.union(thrown, thrownPrev);
   918                 }
   920                 // process all the methods
   921                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
   922                     if (l.head.hasTag(METHODDEF)) {
   923                         scan(l.head);
   924                         errorUncaught();
   925                     }
   926                 }
   928                 thrown = thrownPrev;
   929             } finally {
   930                 pendingExits = pendingExitsPrev;
   931                 caught = caughtPrev;
   932                 classDef = classDefPrev;
   933                 lint = lintPrev;
   934             }
   935         }
   937         public void visitMethodDef(JCMethodDecl tree) {
   938             if (tree.body == null) return;
   940             List<Type> caughtPrev = caught;
   941             List<Type> mthrown = tree.sym.type.getThrownTypes();
   942             Lint lintPrev = lint;
   944             lint = lint.augment(tree.sym);
   946             Assert.check(pendingExits.isEmpty());
   948             try {
   949                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
   950                     JCVariableDecl def = l.head;
   951                     scan(def);
   952                 }
   953                 if (TreeInfo.isInitialConstructor(tree))
   954                     caught = chk.union(caught, mthrown);
   955                 else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
   956                     caught = mthrown;
   957                 // else we are in an instance initializer block;
   958                 // leave caught unchanged.
   960                 scan(tree.body);
   962                 List<FlowPendingExit> exits = pendingExits.toList();
   963                 pendingExits = new ListBuffer<FlowPendingExit>();
   964                 while (exits.nonEmpty()) {
   965                     FlowPendingExit exit = exits.head;
   966                     exits = exits.tail;
   967                     if (exit.thrown == null) {
   968                         Assert.check(exit.tree.hasTag(RETURN));
   969                     } else {
   970                         // uncaught throws will be reported later
   971                         pendingExits.append(exit);
   972                     }
   973                 }
   974             } finally {
   975                 caught = caughtPrev;
   976                 lint = lintPrev;
   977             }
   978         }
   980         public void visitVarDef(JCVariableDecl tree) {
   981             if (tree.init != null) {
   982                 Lint lintPrev = lint;
   983                 lint = lint.augment(tree.sym);
   984                 try{
   985                     scan(tree.init);
   986                 } finally {
   987                     lint = lintPrev;
   988                 }
   989             }
   990         }
   992         public void visitBlock(JCBlock tree) {
   993             scan(tree.stats);
   994         }
   996         public void visitDoLoop(JCDoWhileLoop tree) {
   997             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
   998             pendingExits = new ListBuffer<FlowPendingExit>();
   999             scan(tree.body);
  1000             resolveContinues(tree);
  1001             scan(tree.cond);
  1002             resolveBreaks(tree, prevPendingExits);
  1005         public void visitWhileLoop(JCWhileLoop tree) {
  1006             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1007             pendingExits = new ListBuffer<FlowPendingExit>();
  1008             scan(tree.cond);
  1009             scan(tree.body);
  1010             resolveContinues(tree);
  1011             resolveBreaks(tree, prevPendingExits);
  1014         public void visitForLoop(JCForLoop tree) {
  1015             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1016             scan(tree.init);
  1017             pendingExits = new ListBuffer<FlowPendingExit>();
  1018             if (tree.cond != null) {
  1019                 scan(tree.cond);
  1021             scan(tree.body);
  1022             resolveContinues(tree);
  1023             scan(tree.step);
  1024             resolveBreaks(tree, prevPendingExits);
  1027         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1028             visitVarDef(tree.var);
  1029             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1030             scan(tree.expr);
  1031             pendingExits = new ListBuffer<FlowPendingExit>();
  1032             scan(tree.body);
  1033             resolveContinues(tree);
  1034             resolveBreaks(tree, prevPendingExits);
  1037         public void visitLabelled(JCLabeledStatement tree) {
  1038             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1039             pendingExits = new ListBuffer<FlowPendingExit>();
  1040             scan(tree.body);
  1041             resolveBreaks(tree, prevPendingExits);
  1044         public void visitSwitch(JCSwitch tree) {
  1045             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1046             pendingExits = new ListBuffer<FlowPendingExit>();
  1047             scan(tree.selector);
  1048             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  1049                 JCCase c = l.head;
  1050                 if (c.pat != null) {
  1051                     scan(c.pat);
  1053                 scan(c.stats);
  1055             resolveBreaks(tree, prevPendingExits);
  1058         public void visitTry(JCTry tree) {
  1059             List<Type> caughtPrev = caught;
  1060             List<Type> thrownPrev = thrown;
  1061             thrown = List.nil();
  1062             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1063                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1064                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1065                         List.of(l.head.param.vartype);
  1066                 for (JCExpression ct : subClauses) {
  1067                     caught = chk.incl(ct.type, caught);
  1071             ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
  1072             pendingExits = new ListBuffer<FlowPendingExit>();
  1073             for (JCTree resource : tree.resources) {
  1074                 if (resource instanceof JCVariableDecl) {
  1075                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  1076                     visitVarDef(vdecl);
  1077                 } else if (resource instanceof JCExpression) {
  1078                     scan((JCExpression) resource);
  1079                 } else {
  1080                     throw new AssertionError(tree);  // parser error
  1083             for (JCTree resource : tree.resources) {
  1084                 List<Type> closeableSupertypes = resource.type.isCompound() ?
  1085                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
  1086                     List.of(resource.type);
  1087                 for (Type sup : closeableSupertypes) {
  1088                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
  1089                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
  1090                                 attrEnv,
  1091                                 sup,
  1092                                 names.close,
  1093                                 List.<Type>nil(),
  1094                                 List.<Type>nil());
  1095                         Type mt = types.memberType(resource.type, closeMethod);
  1096                         if (closeMethod.kind == MTH) {
  1097                             for (Type t : mt.getThrownTypes()) {
  1098                                 markThrown(resource, t);
  1104             scan(tree.body);
  1105             List<Type> thrownInTry = allowImprovedCatchAnalysis ?
  1106                 chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
  1107                 thrown;
  1108             thrown = thrownPrev;
  1109             caught = caughtPrev;
  1111             List<Type> caughtInTry = List.nil();
  1112             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  1113                 JCVariableDecl param = l.head.param;
  1114                 List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
  1115                         ((JCTypeUnion)l.head.param.vartype).alternatives :
  1116                         List.of(l.head.param.vartype);
  1117                 List<Type> ctypes = List.nil();
  1118                 List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
  1119                 for (JCExpression ct : subClauses) {
  1120                     Type exc = ct.type;
  1121                     if (exc != syms.unknownType) {
  1122                         ctypes = ctypes.append(exc);
  1123                         if (types.isSameType(exc, syms.objectType))
  1124                             continue;
  1125                         checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
  1126                         caughtInTry = chk.incl(exc, caughtInTry);
  1129                 scan(param);
  1130                 preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
  1131                 scan(l.head.body);
  1132                 preciseRethrowTypes.remove(param.sym);
  1134             if (tree.finalizer != null) {
  1135                 List<Type> savedThrown = thrown;
  1136                 thrown = List.nil();
  1137                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1138                 pendingExits = prevPendingExits;
  1139                 scan(tree.finalizer);
  1140                 if (!tree.finallyCanCompleteNormally) {
  1141                     // discard exits and exceptions from try and finally
  1142                     thrown = chk.union(thrown, thrownPrev);
  1143                 } else {
  1144                     thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1145                     thrown = chk.union(thrown, savedThrown);
  1146                     // FIX: this doesn't preserve source order of exits in catch
  1147                     // versus finally!
  1148                     while (exits.nonEmpty()) {
  1149                         pendingExits.append(exits.next());
  1152             } else {
  1153                 thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
  1154                 ListBuffer<FlowPendingExit> exits = pendingExits;
  1155                 pendingExits = prevPendingExits;
  1156                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  1160         @Override
  1161         public void visitIf(JCIf tree) {
  1162             scan(tree.cond);
  1163             scan(tree.thenpart);
  1164             if (tree.elsepart != null) {
  1165                 scan(tree.elsepart);
  1169         void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
  1170             if (chk.subset(exc, caughtInTry)) {
  1171                 log.error(pos, "except.already.caught", exc);
  1172             } else if (!chk.isUnchecked(pos, exc) &&
  1173                     !isExceptionOrThrowable(exc) &&
  1174                     !chk.intersects(exc, thrownInTry)) {
  1175                 log.error(pos, "except.never.thrown.in.try", exc);
  1176             } else if (allowImprovedCatchAnalysis) {
  1177                 List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
  1178                 // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
  1179                 // unchecked exception, the result list would not be empty, as the augmented
  1180                 // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
  1181                 // exception, that would have been covered in the branch above
  1182                 if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
  1183                         !isExceptionOrThrowable(exc)) {
  1184                     String key = catchableThrownTypes.length() == 1 ?
  1185                             "unreachable.catch" :
  1186                             "unreachable.catch.1";
  1187                     log.warning(pos, key, catchableThrownTypes);
  1191         //where
  1192             private boolean isExceptionOrThrowable(Type exc) {
  1193                 return exc.tsym == syms.throwableType.tsym ||
  1194                     exc.tsym == syms.exceptionType.tsym;
  1197         public void visitBreak(JCBreak tree) {
  1198             recordExit(tree, new FlowPendingExit(tree, null));
  1201         public void visitContinue(JCContinue tree) {
  1202             recordExit(tree, new FlowPendingExit(tree, null));
  1205         public void visitReturn(JCReturn tree) {
  1206             scan(tree.expr);
  1207             recordExit(tree, new FlowPendingExit(tree, null));
  1210         public void visitThrow(JCThrow tree) {
  1211             scan(tree.expr);
  1212             Symbol sym = TreeInfo.symbol(tree.expr);
  1213             if (sym != null &&
  1214                 sym.kind == VAR &&
  1215                 (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
  1216                 preciseRethrowTypes.get(sym) != null &&
  1217                 allowImprovedRethrowAnalysis) {
  1218                 for (Type t : preciseRethrowTypes.get(sym)) {
  1219                     markThrown(tree, t);
  1222             else {
  1223                 markThrown(tree, tree.expr.type);
  1225             markDead(tree);
  1228         public void visitApply(JCMethodInvocation tree) {
  1229             scan(tree.meth);
  1230             scan(tree.args);
  1231             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
  1232                 markThrown(tree, l.head);
  1235         public void visitNewClass(JCNewClass tree) {
  1236             scan(tree.encl);
  1237             scan(tree.args);
  1238            // scan(tree.def);
  1239             for (List<Type> l = tree.constructorType.getThrownTypes();
  1240                  l.nonEmpty();
  1241                  l = l.tail) {
  1242                 markThrown(tree, l.head);
  1244             List<Type> caughtPrev = caught;
  1245             try {
  1246                 // If the new class expression defines an anonymous class,
  1247                 // analysis of the anonymous constructor may encounter thrown
  1248                 // types which are unsubstituted type variables.
  1249                 // However, since the constructor's actual thrown types have
  1250                 // already been marked as thrown, it is safe to simply include
  1251                 // each of the constructor's formal thrown types in the set of
  1252                 // 'caught/declared to be thrown' types, for the duration of
  1253                 // the class def analysis.
  1254                 if (tree.def != null)
  1255                     for (List<Type> l = tree.constructor.type.getThrownTypes();
  1256                          l.nonEmpty();
  1257                          l = l.tail) {
  1258                         caught = chk.incl(l.head, caught);
  1260                 scan(tree.def);
  1262             finally {
  1263                 caught = caughtPrev;
  1267         @Override
  1268         public void visitLambda(JCLambda tree) {
  1269             if (tree.type != null &&
  1270                     tree.type.isErroneous()) {
  1271                 return;
  1273             List<Type> prevCaught = caught;
  1274             List<Type> prevThrown = thrown;
  1275             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1276             try {
  1277                 pendingExits = new ListBuffer<>();
  1278                 caught = tree.getDescriptorType(types).getThrownTypes();
  1279                 thrown = List.nil();
  1280                 scan(tree.body);
  1281                 List<FlowPendingExit> exits = pendingExits.toList();
  1282                 pendingExits = new ListBuffer<FlowPendingExit>();
  1283                 while (exits.nonEmpty()) {
  1284                     FlowPendingExit exit = exits.head;
  1285                     exits = exits.tail;
  1286                     if (exit.thrown == null) {
  1287                         Assert.check(exit.tree.hasTag(RETURN));
  1288                     } else {
  1289                         // uncaught throws will be reported later
  1290                         pendingExits.append(exit);
  1294                 errorUncaught();
  1295             } finally {
  1296                 pendingExits = prevPending;
  1297                 caught = prevCaught;
  1298                 thrown = prevThrown;
  1302         public void visitTopLevel(JCCompilationUnit tree) {
  1303             // Do nothing for TopLevel since each class is visited individually
  1306     /**************************************************************************
  1307      * main method
  1308      *************************************************************************/
  1310         /** Perform definite assignment/unassignment analysis on a tree.
  1311          */
  1312         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  1313             analyzeTree(env, env.tree, make);
  1315         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  1316             try {
  1317                 attrEnv = env;
  1318                 Flow.this.make = make;
  1319                 pendingExits = new ListBuffer<FlowPendingExit>();
  1320                 preciseRethrowTypes = new HashMap<Symbol, List<Type>>();
  1321                 this.thrown = this.caught = null;
  1322                 this.classDef = null;
  1323                 scan(tree);
  1324             } finally {
  1325                 pendingExits = null;
  1326                 Flow.this.make = null;
  1327                 this.thrown = this.caught = null;
  1328                 this.classDef = null;
  1333     /**
  1334      * Specialized pass that performs inference of thrown types for lambdas.
  1335      */
  1336     class LambdaFlowAnalyzer extends FlowAnalyzer {
  1337         List<Type> inferredThrownTypes;
  1338         boolean inLambda;
  1339         @Override
  1340         public void visitLambda(JCLambda tree) {
  1341             if ((tree.type != null &&
  1342                     tree.type.isErroneous()) || inLambda) {
  1343                 return;
  1345             List<Type> prevCaught = caught;
  1346             List<Type> prevThrown = thrown;
  1347             ListBuffer<FlowPendingExit> prevPending = pendingExits;
  1348             inLambda = true;
  1349             try {
  1350                 pendingExits = new ListBuffer<>();
  1351                 caught = List.of(syms.throwableType);
  1352                 thrown = List.nil();
  1353                 scan(tree.body);
  1354                 inferredThrownTypes = thrown;
  1355             } finally {
  1356                 pendingExits = prevPending;
  1357                 caught = prevCaught;
  1358                 thrown = prevThrown;
  1359                 inLambda = false;
  1362         @Override
  1363         public void visitClassDef(JCClassDecl tree) {
  1364             //skip
  1368     /**
  1369      * This pass implements (i) definite assignment analysis, which ensures that
  1370      * each variable is assigned when used and (ii) definite unassignment analysis,
  1371      * which ensures that no final variable is assigned more than once. This visitor
  1372      * depends on the results of the liveliness analyzer. This pass is also used to mark
  1373      * effectively-final local variables/parameters.
  1374      */
  1376     public abstract class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer<P>.AbstractAssignPendingExit>
  1377         extends BaseAnalyzer<P> {
  1379         /** The set of definitely assigned variables.
  1380          */
  1381         protected Bits inits;
  1383         /** The set of definitely unassigned variables.
  1384          */
  1385         final Bits uninits;
  1387         /** The set of variables that are definitely unassigned everywhere
  1388          *  in current try block. This variable is maintained lazily; it is
  1389          *  updated only when something gets removed from uninits,
  1390          *  typically by being assigned in reachable code.  To obtain the
  1391          *  correct set of variables which are definitely unassigned
  1392          *  anywhere in current try block, intersect uninitsTry and
  1393          *  uninits.
  1394          */
  1395         final Bits uninitsTry;
  1397         /** When analyzing a condition, inits and uninits are null.
  1398          *  Instead we have:
  1399          */
  1400         final Bits initsWhenTrue;
  1401         final Bits initsWhenFalse;
  1402         final Bits uninitsWhenTrue;
  1403         final Bits uninitsWhenFalse;
  1405         /** A mapping from addresses to variable symbols.
  1406          */
  1407         protected JCVariableDecl[] vardecls;
  1409         /** The current class being defined.
  1410          */
  1411         JCClassDecl classDef;
  1413         /** The first variable sequence number in this class definition.
  1414          */
  1415         int firstadr;
  1417         /** The next available variable sequence number.
  1418          */
  1419         protected int nextadr;
  1421         /** The first variable sequence number in a block that can return.
  1422          */
  1423         protected int returnadr;
  1425         /** The list of unreferenced automatic resources.
  1426          */
  1427         Scope unrefdResources;
  1429         /** Set when processing a loop body the second time for DU analysis. */
  1430         FlowKind flowKind = FlowKind.NORMAL;
  1432         /** The starting position of the analysed tree */
  1433         int startPos;
  1435         public class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
  1437             final Bits inits;
  1438             final Bits uninits;
  1439             final Bits exit_inits = new Bits(true);
  1440             final Bits exit_uninits = new Bits(true);
  1442             public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
  1443                 super(tree);
  1444                 this.inits = inits;
  1445                 this.uninits = uninits;
  1446                 this.exit_inits.assign(inits);
  1447                 this.exit_uninits.assign(uninits);
  1450             @Override
  1451             public void resolveJump(JCTree tree) {
  1452                 inits.andSet(exit_inits);
  1453                 uninits.andSet(exit_uninits);
  1457         public AbstractAssignAnalyzer() {
  1458             this.inits = new Bits();
  1459             uninits = new Bits();
  1460             uninitsTry = new Bits();
  1461             initsWhenTrue = new Bits(true);
  1462             initsWhenFalse = new Bits(true);
  1463             uninitsWhenTrue = new Bits(true);
  1464             uninitsWhenFalse = new Bits(true);
  1467         private boolean isInitialConstructor = false;
  1469         @Override
  1470         protected void markDead(JCTree tree) {
  1471             if (!isInitialConstructor) {
  1472                 inits.inclRange(returnadr, nextadr);
  1473             } else {
  1474                 for (int address = returnadr; address < nextadr; address++) {
  1475                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
  1476                         inits.incl(address);
  1480             uninits.inclRange(returnadr, nextadr);
  1483         /*-------------- Processing variables ----------------------*/
  1485         /** Do we need to track init/uninit state of this symbol?
  1486          *  I.e. is symbol either a local or a blank final variable?
  1487          */
  1488         protected boolean trackable(VarSymbol sym) {
  1489             return
  1490                 sym.pos >= startPos &&
  1491                 ((sym.owner.kind == MTH ||
  1492                 isFinalUninitializedField(sym)));
  1495         boolean isFinalUninitializedField(VarSymbol sym) {
  1496             return sym.owner.kind == TYP &&
  1497                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
  1498                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
  1501         boolean isFinalUninitializedStaticField(VarSymbol sym) {
  1502             return isFinalUninitializedField(sym) && sym.isStatic();
  1505         /** Initialize new trackable variable by setting its address field
  1506          *  to the next available sequence number and entering it under that
  1507          *  index into the vars array.
  1508          */
  1509         void newVar(JCVariableDecl varDecl) {
  1510             VarSymbol sym = varDecl.sym;
  1511             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
  1512             if ((sym.flags() & FINAL) == 0) {
  1513                 sym.flags_field |= EFFECTIVELY_FINAL;
  1515             sym.adr = nextadr;
  1516             vardecls[nextadr] = varDecl;
  1517             exclVarFromInits(varDecl, nextadr);
  1518             uninits.incl(nextadr);
  1519             nextadr++;
  1522         protected void exclVarFromInits(JCTree tree, int adr) {
  1523             inits.excl(adr);
  1526         protected void assignToInits(JCTree tree, Bits bits) {
  1527             inits.assign(bits);
  1530         protected void andSetInits(JCTree tree, Bits bits) {
  1531             inits.andSet(bits);
  1534         protected void orSetInits(JCTree tree, Bits bits) {
  1535             inits.orSet(bits);
  1538         /** Record an initialization of a trackable variable.
  1539          */
  1540         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  1541             if (sym.adr >= firstadr && trackable(sym)) {
  1542                 if (uninits.isMember(sym.adr)) {
  1543                     uninit(sym);
  1545                 inits.incl(sym.adr);
  1548         //where
  1549             void uninit(VarSymbol sym) {
  1550                 if (!inits.isMember(sym.adr)) {
  1551                     // reachable assignment
  1552                     uninits.excl(sym.adr);
  1553                     uninitsTry.excl(sym.adr);
  1554                 } else {
  1555                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
  1556                     uninits.excl(sym.adr);
  1560         /** If tree is either a simple name or of the form this.name or
  1561          *  C.this.name, and tree represents a trackable variable,
  1562          *  record an initialization of the variable.
  1563          */
  1564         void letInit(JCTree tree) {
  1565             tree = TreeInfo.skipParens(tree);
  1566             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  1567                 Symbol sym = TreeInfo.symbol(tree);
  1568                 if (sym.kind == VAR) {
  1569                     letInit(tree.pos(), (VarSymbol)sym);
  1574         /** Check that trackable variable is initialized.
  1575          */
  1576         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
  1577             checkInit(pos, sym, "var.might.not.have.been.initialized");
  1580         void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}
  1582         /** Utility method to reset several Bits instances.
  1583          */
  1584         private void resetBits(Bits... bits) {
  1585             for (Bits b : bits) {
  1586                 b.reset();
  1590         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
  1591          */
  1592         void split(boolean setToNull) {
  1593             initsWhenFalse.assign(inits);
  1594             uninitsWhenFalse.assign(uninits);
  1595             initsWhenTrue.assign(inits);
  1596             uninitsWhenTrue.assign(uninits);
  1597             if (setToNull) {
  1598                 resetBits(inits, uninits);
  1602         /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
  1603          */
  1604         protected void merge(JCTree tree) {
  1605             inits.assign(initsWhenFalse.andSet(initsWhenTrue));
  1606             uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
  1609     /* ************************************************************************
  1610      * Visitor methods for statements and definitions
  1611      *************************************************************************/
  1613         /** Analyze an expression. Make sure to set (un)inits rather than
  1614          *  (un)initsWhenTrue(WhenFalse) on exit.
  1615          */
  1616         void scanExpr(JCTree tree) {
  1617             if (tree != null) {
  1618                 scan(tree);
  1619                 if (inits.isReset()) {
  1620                     merge(tree);
  1625         /** Analyze a list of expressions.
  1626          */
  1627         void scanExprs(List<? extends JCExpression> trees) {
  1628             if (trees != null)
  1629                 for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
  1630                     scanExpr(l.head);
  1633         /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
  1634          *  rather than (un)inits on exit.
  1635          */
  1636         void scanCond(JCTree tree) {
  1637             if (tree.type.isFalse()) {
  1638                 if (inits.isReset()) merge(tree);
  1639                 initsWhenTrue.assign(inits);
  1640                 initsWhenTrue.inclRange(firstadr, nextadr);
  1641                 uninitsWhenTrue.assign(uninits);
  1642                 uninitsWhenTrue.inclRange(firstadr, nextadr);
  1643                 initsWhenFalse.assign(inits);
  1644                 uninitsWhenFalse.assign(uninits);
  1645             } else if (tree.type.isTrue()) {
  1646                 if (inits.isReset()) merge(tree);
  1647                 initsWhenFalse.assign(inits);
  1648                 initsWhenFalse.inclRange(firstadr, nextadr);
  1649                 uninitsWhenFalse.assign(uninits);
  1650                 uninitsWhenFalse.inclRange(firstadr, nextadr);
  1651                 initsWhenTrue.assign(inits);
  1652                 uninitsWhenTrue.assign(uninits);
  1653             } else {
  1654                 scan(tree);
  1655                 if (!inits.isReset())
  1656                     split(tree.type != syms.unknownType);
  1658             if (tree.type != syms.unknownType) {
  1659                 resetBits(inits, uninits);
  1663         /* ------------ Visitor methods for various sorts of trees -------------*/
  1665         @Override
  1666         public void visitClassDef(JCClassDecl tree) {
  1667             if (tree.sym == null) {
  1668                 return;
  1671             JCClassDecl classDefPrev = classDef;
  1672             int firstadrPrev = firstadr;
  1673             int nextadrPrev = nextadr;
  1674             ListBuffer<P> pendingExitsPrev = pendingExits;
  1676             pendingExits = new ListBuffer<P>();
  1677             if (tree.name != names.empty) {
  1678                 firstadr = nextadr;
  1680             classDef = tree;
  1681             try {
  1682                 // define all the static fields
  1683                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1684                     if (l.head.hasTag(VARDEF)) {
  1685                         JCVariableDecl def = (JCVariableDecl)l.head;
  1686                         if ((def.mods.flags & STATIC) != 0) {
  1687                             VarSymbol sym = def.sym;
  1688                             if (trackable(sym)) {
  1689                                 newVar(def);
  1695                 // process all the static initializers
  1696                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1697                     if (!l.head.hasTag(METHODDEF) &&
  1698                         (TreeInfo.flags(l.head) & STATIC) != 0) {
  1699                         scan(l.head);
  1703                 // define all the instance fields
  1704                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1705                     if (l.head.hasTag(VARDEF)) {
  1706                         JCVariableDecl def = (JCVariableDecl)l.head;
  1707                         if ((def.mods.flags & STATIC) == 0) {
  1708                             VarSymbol sym = def.sym;
  1709                             if (trackable(sym)) {
  1710                                 newVar(def);
  1716                 // process all the instance initializers
  1717                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1718                     if (!l.head.hasTag(METHODDEF) &&
  1719                         (TreeInfo.flags(l.head) & STATIC) == 0) {
  1720                         scan(l.head);
  1724                 // process all the methods
  1725                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
  1726                     if (l.head.hasTag(METHODDEF)) {
  1727                         scan(l.head);
  1730             } finally {
  1731                 pendingExits = pendingExitsPrev;
  1732                 nextadr = nextadrPrev;
  1733                 firstadr = firstadrPrev;
  1734                 classDef = classDefPrev;
  1738         @Override
  1739         public void visitMethodDef(JCMethodDecl tree) {
  1740             if (tree.body == null) {
  1741                 return;
  1743             /*  Ignore synthetic methods, except for translated lambda methods.
  1744              */
  1745             if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
  1746                 return;
  1749             final Bits initsPrev = new Bits(inits);
  1750             final Bits uninitsPrev = new Bits(uninits);
  1751             int nextadrPrev = nextadr;
  1752             int firstadrPrev = firstadr;
  1753             int returnadrPrev = returnadr;
  1755             Assert.check(pendingExits.isEmpty());
  1756             boolean lastInitialConstructor = isInitialConstructor;
  1757             try {
  1758                 isInitialConstructor = TreeInfo.isInitialConstructor(tree);
  1760                 if (!isInitialConstructor) {
  1761                     firstadr = nextadr;
  1763                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  1764                     JCVariableDecl def = l.head;
  1765                     scan(def);
  1766                     Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
  1767                     /*  If we are executing the code from Gen, then there can be
  1768                      *  synthetic or mandated variables, ignore them.
  1769                      */
  1770                     initParam(def);
  1772                 // else we are in an instance initializer block;
  1773                 // leave caught unchanged.
  1774                 scan(tree.body);
  1776                 if (isInitialConstructor) {
  1777                     boolean isSynthesized = (tree.sym.flags() &
  1778                                              GENERATEDCONSTR) != 0;
  1779                     for (int i = firstadr; i < nextadr; i++) {
  1780                         JCVariableDecl vardecl = vardecls[i];
  1781                         VarSymbol var = vardecl.sym;
  1782                         if (var.owner == classDef.sym) {
  1783                             // choose the diagnostic position based on whether
  1784                             // the ctor is default(synthesized) or not
  1785                             if (isSynthesized) {
  1786                                 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
  1787                                     var, "var.not.initialized.in.default.constructor");
  1788                             } else {
  1789                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
  1794                 List<P> exits = pendingExits.toList();
  1795                 pendingExits = new ListBuffer<>();
  1796                 while (exits.nonEmpty()) {
  1797                     P exit = exits.head;
  1798                     exits = exits.tail;
  1799                     Assert.check(exit.tree.hasTag(RETURN), exit.tree);
  1800                     if (isInitialConstructor) {
  1801                         assignToInits(exit.tree, exit.exit_inits);
  1802                         for (int i = firstadr; i < nextadr; i++) {
  1803                             checkInit(exit.tree.pos(), vardecls[i].sym);
  1807             } finally {
  1808                 assignToInits(tree, initsPrev);
  1809                 uninits.assign(uninitsPrev);
  1810                 nextadr = nextadrPrev;
  1811                 firstadr = firstadrPrev;
  1812                 returnadr = returnadrPrev;
  1813                 isInitialConstructor = lastInitialConstructor;
  1817         protected void initParam(JCVariableDecl def) {
  1818             inits.incl(def.sym.adr);
  1819             uninits.excl(def.sym.adr);
  1822         public void visitVarDef(JCVariableDecl tree) {
  1823             boolean track = trackable(tree.sym);
  1824             if (track && tree.sym.owner.kind == MTH) {
  1825                 newVar(tree);
  1827             if (tree.init != null) {
  1828                 scanExpr(tree.init);
  1829                 if (track) {
  1830                     letInit(tree.pos(), tree.sym);
  1835         public void visitBlock(JCBlock tree) {
  1836             int nextadrPrev = nextadr;
  1837             scan(tree.stats);
  1838             nextadr = nextadrPrev;
  1841         int getLogNumberOfErrors() {
  1842             return 0;
  1845         public void visitDoLoop(JCDoWhileLoop tree) {
  1846             ListBuffer<P> prevPendingExits = pendingExits;
  1847             FlowKind prevFlowKind = flowKind;
  1848             flowKind = FlowKind.NORMAL;
  1849             final Bits initsSkip = new Bits(true);
  1850             final Bits uninitsSkip = new Bits(true);
  1851             pendingExits = new ListBuffer<P>();
  1852             int prevErrors = getLogNumberOfErrors();
  1853             do {
  1854                 final Bits uninitsEntry = new Bits(uninits);
  1855                 uninitsEntry.excludeFrom(nextadr);
  1856                 scan(tree.body);
  1857                 resolveContinues(tree);
  1858                 scanCond(tree.cond);
  1859                 if (!flowKind.isFinal()) {
  1860                     initsSkip.assign(initsWhenFalse);
  1861                     uninitsSkip.assign(uninitsWhenFalse);
  1863                 if (getLogNumberOfErrors() !=  prevErrors ||
  1864                     flowKind.isFinal() ||
  1865                     new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
  1866                     break;
  1867                 assignToInits(tree.cond, initsWhenTrue);
  1868                 uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
  1869                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1870             } while (true);
  1871             flowKind = prevFlowKind;
  1872             assignToInits(tree, initsSkip);
  1873             uninits.assign(uninitsSkip);
  1874             resolveBreaks(tree, prevPendingExits);
  1877         public void visitWhileLoop(JCWhileLoop tree) {
  1878             ListBuffer<P> prevPendingExits = pendingExits;
  1879             FlowKind prevFlowKind = flowKind;
  1880             flowKind = FlowKind.NORMAL;
  1881             final Bits initsSkip = new Bits(true);
  1882             final Bits uninitsSkip = new Bits(true);
  1883             pendingExits = new ListBuffer<>();
  1884             int prevErrors = getLogNumberOfErrors();
  1885             final Bits uninitsEntry = new Bits(uninits);
  1886             uninitsEntry.excludeFrom(nextadr);
  1887             do {
  1888                 scanCond(tree.cond);
  1889                 if (!flowKind.isFinal()) {
  1890                     initsSkip.assign(initsWhenFalse) ;
  1891                     uninitsSkip.assign(uninitsWhenFalse);
  1893                 assignToInits(tree, initsWhenTrue);
  1894                 uninits.assign(uninitsWhenTrue);
  1895                 scan(tree.body);
  1896                 resolveContinues(tree);
  1897                 if (getLogNumberOfErrors() != prevErrors ||
  1898                     flowKind.isFinal() ||
  1899                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
  1900                     break;
  1902                 uninits.assign(uninitsEntry.andSet(uninits));
  1903                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1904             } while (true);
  1905             flowKind = prevFlowKind;
  1906             //a variable is DA/DU after the while statement, if it's DA/DU assuming the
  1907             //branch is not taken AND if it's DA/DU before any break statement
  1908             assignToInits(tree.body, initsSkip);
  1909             uninits.assign(uninitsSkip);
  1910             resolveBreaks(tree, prevPendingExits);
  1913         public void visitForLoop(JCForLoop tree) {
  1914             ListBuffer<P> prevPendingExits = pendingExits;
  1915             FlowKind prevFlowKind = flowKind;
  1916             flowKind = FlowKind.NORMAL;
  1917             int nextadrPrev = nextadr;
  1918             scan(tree.init);
  1919             final Bits initsSkip = new Bits(true);
  1920             final Bits uninitsSkip = new Bits(true);
  1921             pendingExits = new ListBuffer<P>();
  1922             int prevErrors = getLogNumberOfErrors();
  1923             do {
  1924                 final Bits uninitsEntry = new Bits(uninits);
  1925                 uninitsEntry.excludeFrom(nextadr);
  1926                 if (tree.cond != null) {
  1927                     scanCond(tree.cond);
  1928                     if (!flowKind.isFinal()) {
  1929                         initsSkip.assign(initsWhenFalse);
  1930                         uninitsSkip.assign(uninitsWhenFalse);
  1932                     assignToInits(tree.body, initsWhenTrue);
  1933                     uninits.assign(uninitsWhenTrue);
  1934                 } else if (!flowKind.isFinal()) {
  1935                     initsSkip.assign(inits);
  1936                     initsSkip.inclRange(firstadr, nextadr);
  1937                     uninitsSkip.assign(uninits);
  1938                     uninitsSkip.inclRange(firstadr, nextadr);
  1940                 scan(tree.body);
  1941                 resolveContinues(tree);
  1942                 scan(tree.step);
  1943                 if (getLogNumberOfErrors() != prevErrors ||
  1944                     flowKind.isFinal() ||
  1945                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  1946                     break;
  1947                 uninits.assign(uninitsEntry.andSet(uninits));
  1948                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1949             } while (true);
  1950             flowKind = prevFlowKind;
  1951             //a variable is DA/DU after a for loop, if it's DA/DU assuming the
  1952             //branch is not taken AND if it's DA/DU before any break statement
  1953             assignToInits(tree.body, initsSkip);
  1954             uninits.assign(uninitsSkip);
  1955             resolveBreaks(tree, prevPendingExits);
  1956             nextadr = nextadrPrev;
  1959         public void visitForeachLoop(JCEnhancedForLoop tree) {
  1960             visitVarDef(tree.var);
  1962             ListBuffer<P> prevPendingExits = pendingExits;
  1963             FlowKind prevFlowKind = flowKind;
  1964             flowKind = FlowKind.NORMAL;
  1965             int nextadrPrev = nextadr;
  1966             scan(tree.expr);
  1967             final Bits initsStart = new Bits(inits);
  1968             final Bits uninitsStart = new Bits(uninits);
  1970             letInit(tree.pos(), tree.var.sym);
  1971             pendingExits = new ListBuffer<P>();
  1972             int prevErrors = getLogNumberOfErrors();
  1973             do {
  1974                 final Bits uninitsEntry = new Bits(uninits);
  1975                 uninitsEntry.excludeFrom(nextadr);
  1976                 scan(tree.body);
  1977                 resolveContinues(tree);
  1978                 if (getLogNumberOfErrors() != prevErrors ||
  1979                     flowKind.isFinal() ||
  1980                     new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
  1981                     break;
  1982                 uninits.assign(uninitsEntry.andSet(uninits));
  1983                 flowKind = FlowKind.SPECULATIVE_LOOP;
  1984             } while (true);
  1985             flowKind = prevFlowKind;
  1986             assignToInits(tree.body, initsStart);
  1987             uninits.assign(uninitsStart.andSet(uninits));
  1988             resolveBreaks(tree, prevPendingExits);
  1989             nextadr = nextadrPrev;
  1992         public void visitLabelled(JCLabeledStatement tree) {
  1993             ListBuffer<P> prevPendingExits = pendingExits;
  1994             pendingExits = new ListBuffer<P>();
  1995             scan(tree.body);
  1996             resolveBreaks(tree, prevPendingExits);
  1999         public void visitSwitch(JCSwitch tree) {
  2000             ListBuffer<P> prevPendingExits = pendingExits;
  2001             pendingExits = new ListBuffer<>();
  2002             int nextadrPrev = nextadr;
  2003             scanExpr(tree.selector);
  2004             final Bits initsSwitch = new Bits(inits);
  2005             final Bits uninitsSwitch = new Bits(uninits);
  2006             boolean hasDefault = false;
  2007             for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
  2008                 assignToInits(l.head, initsSwitch);
  2009                 uninits.assign(uninits.andSet(uninitsSwitch));
  2010                 JCCase c = l.head;
  2011                 if (c.pat == null) {
  2012                     hasDefault = true;
  2013                 } else {
  2014                     scanExpr(c.pat);
  2016                 if (hasDefault) {
  2017                     assignToInits(null, initsSwitch);
  2018                     uninits.assign(uninits.andSet(uninitsSwitch));
  2020                 scan(c.stats);
  2021                 addVars(c.stats, initsSwitch, uninitsSwitch);
  2022                 if (!hasDefault) {
  2023                     assignToInits(l.head.stats.last(), initsSwitch);
  2024                     uninits.assign(uninits.andSet(uninitsSwitch));
  2026                 // Warn about fall-through if lint switch fallthrough enabled.
  2028             if (!hasDefault) {
  2029                 andSetInits(null, initsSwitch);
  2031             resolveBreaks(tree, prevPendingExits);
  2032             nextadr = nextadrPrev;
  2034         // where
  2035             /** Add any variables defined in stats to inits and uninits. */
  2036             private void addVars(List<JCStatement> stats, final Bits inits,
  2037                                         final Bits uninits) {
  2038                 for (;stats.nonEmpty(); stats = stats.tail) {
  2039                     JCTree stat = stats.head;
  2040                     if (stat.hasTag(VARDEF)) {
  2041                         int adr = ((JCVariableDecl) stat).sym.adr;
  2042                         inits.excl(adr);
  2043                         uninits.incl(adr);
  2048         boolean isEnabled(Lint.LintCategory lc) {
  2049             return false;
  2052         void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {}
  2054         public void visitTry(JCTry tree) {
  2055             ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
  2056             final Bits uninitsTryPrev = new Bits(uninitsTry);
  2057             ListBuffer<P> prevPendingExits = pendingExits;
  2058             pendingExits = new ListBuffer<>();
  2059             final Bits initsTry = new Bits(inits);
  2060             uninitsTry.assign(uninits);
  2061             for (JCTree resource : tree.resources) {
  2062                 if (resource instanceof JCVariableDecl) {
  2063                     JCVariableDecl vdecl = (JCVariableDecl) resource;
  2064                     visitVarDef(vdecl);
  2065                     unrefdResources.enter(vdecl.sym);
  2066                     resourceVarDecls.append(vdecl);
  2067                 } else if (resource instanceof JCExpression) {
  2068                     scanExpr((JCExpression) resource);
  2069                 } else {
  2070                     throw new AssertionError(tree);  // parser error
  2073             scan(tree.body);
  2074             uninitsTry.andSet(uninits);
  2075             final Bits initsEnd = new Bits(inits);
  2076             final Bits uninitsEnd = new Bits(uninits);
  2077             int nextadrCatch = nextadr;
  2079             if (!resourceVarDecls.isEmpty() &&
  2080                     isEnabled(Lint.LintCategory.TRY)) {
  2081                 for (JCVariableDecl resVar : resourceVarDecls) {
  2082                     if (unrefdResources.includes(resVar.sym)) {
  2083                         reportWarning(Lint.LintCategory.TRY, resVar.pos(),
  2084                                     "try.resource.not.referenced", resVar.sym);
  2085                         unrefdResources.remove(resVar.sym);
  2090             /*  The analysis of each catch should be independent.
  2091              *  Each one should have the same initial values of inits and
  2092              *  uninits.
  2093              */
  2094             final Bits initsCatchPrev = new Bits(initsTry);
  2095             final Bits uninitsCatchPrev = new Bits(uninitsTry);
  2097             for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
  2098                 JCVariableDecl param = l.head.param;
  2099                 assignToInits(tree.body, initsCatchPrev);
  2100                 uninits.assign(uninitsCatchPrev);
  2101                 scan(param);
  2102                 /* If this is a TWR and we are executing the code from Gen,
  2103                  * then there can be synthetic variables, ignore them.
  2104                  */
  2105                 initParam(param);
  2106                 scan(l.head.body);
  2107                 initsEnd.andSet(inits);
  2108                 uninitsEnd.andSet(uninits);
  2109                 nextadr = nextadrCatch;
  2111             if (tree.finalizer != null) {
  2112                 assignToInits(tree.finalizer, initsTry);
  2113                 uninits.assign(uninitsTry);
  2114                 ListBuffer<P> exits = pendingExits;
  2115                 pendingExits = prevPendingExits;
  2116                 scan(tree.finalizer);
  2117                 if (!tree.finallyCanCompleteNormally) {
  2118                     // discard exits and exceptions from try and finally
  2119                 } else {
  2120                     uninits.andSet(uninitsEnd);
  2121                     // FIX: this doesn't preserve source order of exits in catch
  2122                     // versus finally!
  2123                     while (exits.nonEmpty()) {
  2124                         P exit = exits.next();
  2125                         if (exit.exit_inits != null) {
  2126                             exit.exit_inits.orSet(inits);
  2127                             exit.exit_uninits.andSet(uninits);
  2129                         pendingExits.append(exit);
  2131                     orSetInits(tree, initsEnd);
  2133             } else {
  2134                 assignToInits(tree, initsEnd);
  2135                 uninits.assign(uninitsEnd);
  2136                 ListBuffer<P> exits = pendingExits;
  2137                 pendingExits = prevPendingExits;
  2138                 while (exits.nonEmpty()) pendingExits.append(exits.next());
  2140             uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
  2143         public void visitConditional(JCConditional tree) {
  2144             scanCond(tree.cond);
  2145             final Bits initsBeforeElse = new Bits(initsWhenFalse);
  2146             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
  2147             assignToInits(tree.cond, initsWhenTrue);
  2148             uninits.assign(uninitsWhenTrue);
  2149             if (tree.truepart.type.hasTag(BOOLEAN) &&
  2150                 tree.falsepart.type.hasTag(BOOLEAN)) {
  2151                 // if b and c are boolean valued, then
  2152                 // v is (un)assigned after a?b:c when true iff
  2153                 //    v is (un)assigned after b when true and
  2154                 //    v is (un)assigned after c when true
  2155                 scanCond(tree.truepart);
  2156                 final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
  2157                 final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
  2158                 final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
  2159                 final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
  2160                 assignToInits(tree.truepart, initsBeforeElse);
  2161                 uninits.assign(uninitsBeforeElse);
  2162                 scanCond(tree.falsepart);
  2163                 initsWhenTrue.andSet(initsAfterThenWhenTrue);
  2164                 initsWhenFalse.andSet(initsAfterThenWhenFalse);
  2165                 uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
  2166                 uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
  2167             } else {
  2168                 scanExpr(tree.truepart);
  2169                 final Bits initsAfterThen = new Bits(inits);
  2170                 final Bits uninitsAfterThen = new Bits(uninits);
  2171                 assignToInits(tree.truepart, initsBeforeElse);
  2172                 uninits.assign(uninitsBeforeElse);
  2173                 scanExpr(tree.falsepart);
  2174                 andSetInits(tree.falsepart, initsAfterThen);
  2175                 uninits.andSet(uninitsAfterThen);
  2179         public void visitIf(JCIf tree) {
  2180             scanCond(tree.cond);
  2181             final Bits initsBeforeElse = new Bits(initsWhenFalse);
  2182             final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
  2183             assignToInits(tree.cond, initsWhenTrue);
  2184             uninits.assign(uninitsWhenTrue);
  2185             scan(tree.thenpart);
  2186             if (tree.elsepart != null) {
  2187                 final Bits initsAfterThen = new Bits(inits);
  2188                 final Bits uninitsAfterThen = new Bits(uninits);
  2189                 assignToInits(tree.thenpart, initsBeforeElse);
  2190                 uninits.assign(uninitsBeforeElse);
  2191                 scan(tree.elsepart);
  2192                 andSetInits(tree.elsepart, initsAfterThen);
  2193                 uninits.andSet(uninitsAfterThen);
  2194             } else {
  2195                 andSetInits(tree.thenpart, initsBeforeElse);
  2196                 uninits.andSet(uninitsBeforeElse);
  2200         protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
  2201             return null;
  2204         @Override
  2205         public void visitBreak(JCBreak tree) {
  2206             recordExit(tree, createNewPendingExit(tree, inits, uninits));
  2209         @Override
  2210         public void visitContinue(JCContinue tree) {
  2211             recordExit(tree, createNewPendingExit(tree, inits, uninits));
  2214         @Override
  2215         public void visitReturn(JCReturn tree) {
  2216             scanExpr(tree.expr);
  2217             recordExit(tree, createNewPendingExit(tree, inits, uninits));
  2220         public void visitThrow(JCThrow tree) {
  2221             scanExpr(tree.expr);
  2222             markDead(tree.expr);
  2225         public void visitApply(JCMethodInvocation tree) {
  2226             scanExpr(tree.meth);
  2227             scanExprs(tree.args);
  2230         public void visitNewClass(JCNewClass tree) {
  2231             scanExpr(tree.encl);
  2232             scanExprs(tree.args);
  2233             scan(tree.def);
  2236         @Override
  2237         public void visitLambda(JCLambda tree) {
  2238             final Bits prevUninits = new Bits(uninits);
  2239             final Bits prevInits = new Bits(inits);
  2240             int returnadrPrev = returnadr;
  2241             ListBuffer<P> prevPending = pendingExits;
  2242             try {
  2243                 returnadr = nextadr;
  2244                 pendingExits = new ListBuffer<P>();
  2245                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
  2246                     JCVariableDecl def = l.head;
  2247                     scan(def);
  2248                     inits.incl(def.sym.adr);
  2249                     uninits.excl(def.sym.adr);
  2251                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
  2252                     scanExpr(tree.body);
  2253                 } else {
  2254                     scan(tree.body);
  2257             finally {
  2258                 returnadr = returnadrPrev;
  2259                 uninits.assign(prevUninits);
  2260                 assignToInits(tree, prevInits);
  2261                 pendingExits = prevPending;
  2265         public void visitNewArray(JCNewArray tree) {
  2266             scanExprs(tree.dims);
  2267             scanExprs(tree.elems);
  2270         public void visitAssert(JCAssert tree) {
  2271             final Bits initsExit = new Bits(inits);
  2272             final Bits uninitsExit = new Bits(uninits);
  2273             scanCond(tree.cond);
  2274             uninitsExit.andSet(uninitsWhenTrue);
  2275             if (tree.detail != null) {
  2276                 assignToInits(tree, initsWhenFalse);
  2277                 uninits.assign(uninitsWhenFalse);
  2278                 scanExpr(tree.detail);
  2280             assignToInits(tree, initsExit);
  2281             uninits.assign(uninitsExit);
  2284         public void visitAssign(JCAssign tree) {
  2285             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2286             if (!isIdentOrThisDotIdent(lhs))
  2287                 scanExpr(lhs);
  2288             scanExpr(tree.rhs);
  2289             letInit(lhs);
  2291         private boolean isIdentOrThisDotIdent(JCTree lhs) {
  2292             if (lhs.hasTag(IDENT))
  2293                 return true;
  2294             if (!lhs.hasTag(SELECT))
  2295                 return false;
  2297             JCFieldAccess fa = (JCFieldAccess)lhs;
  2298             return fa.selected.hasTag(IDENT) &&
  2299                    ((JCIdent)fa.selected).name == names._this;
  2302         // check fields accessed through this.<field> are definitely
  2303         // assigned before reading their value
  2304         public void visitSelect(JCFieldAccess tree) {
  2305             super.visitSelect(tree);
  2306             if (enforceThisDotInit &&
  2307                 tree.selected.hasTag(IDENT) &&
  2308                 ((JCIdent)tree.selected).name == names._this &&
  2309                 tree.sym.kind == VAR)
  2311                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2315         public void visitAssignop(JCAssignOp tree) {
  2316             scanExpr(tree.lhs);
  2317             scanExpr(tree.rhs);
  2318             letInit(tree.lhs);
  2321         public void visitUnary(JCUnary tree) {
  2322             switch (tree.getTag()) {
  2323             case NOT:
  2324                 scanCond(tree.arg);
  2325                 final Bits t = new Bits(initsWhenFalse);
  2326                 initsWhenFalse.assign(initsWhenTrue);
  2327                 initsWhenTrue.assign(t);
  2328                 t.assign(uninitsWhenFalse);
  2329                 uninitsWhenFalse.assign(uninitsWhenTrue);
  2330                 uninitsWhenTrue.assign(t);
  2331                 break;
  2332             case PREINC: case POSTINC:
  2333             case PREDEC: case POSTDEC:
  2334                 scanExpr(tree.arg);
  2335                 letInit(tree.arg);
  2336                 break;
  2337             default:
  2338                 scanExpr(tree.arg);
  2342         public void visitBinary(JCBinary tree) {
  2343             switch (tree.getTag()) {
  2344             case AND:
  2345                 scanCond(tree.lhs);
  2346                 final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
  2347                 final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
  2348                 assignToInits(tree.lhs, initsWhenTrue);
  2349                 uninits.assign(uninitsWhenTrue);
  2350                 scanCond(tree.rhs);
  2351                 initsWhenFalse.andSet(initsWhenFalseLeft);
  2352                 uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
  2353                 break;
  2354             case OR:
  2355                 scanCond(tree.lhs);
  2356                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
  2357                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
  2358                 assignToInits(tree.lhs, initsWhenFalse);
  2359                 uninits.assign(uninitsWhenFalse);
  2360                 scanCond(tree.rhs);
  2361                 initsWhenTrue.andSet(initsWhenTrueLeft);
  2362                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
  2363                 break;
  2364             default:
  2365                 scanExpr(tree.lhs);
  2366                 scanExpr(tree.rhs);
  2370         public void visitIdent(JCIdent tree) {
  2371             if (tree.sym.kind == VAR) {
  2372                 checkInit(tree.pos(), (VarSymbol)tree.sym);
  2373                 referenced(tree.sym);
  2377         void referenced(Symbol sym) {
  2378             unrefdResources.remove(sym);
  2381         public void visitAnnotatedType(JCAnnotatedType tree) {
  2382             // annotations don't get scanned
  2383             tree.underlyingType.accept(this);
  2386         public void visitTopLevel(JCCompilationUnit tree) {
  2387             // Do nothing for TopLevel since each class is visited individually
  2390     /**************************************************************************
  2391      * main method
  2392      *************************************************************************/
  2394         /** Perform definite assignment/unassignment analysis on a tree.
  2395          */
  2396         public void analyzeTree(Env<?> env) {
  2397             analyzeTree(env, env.tree);
  2400         public void analyzeTree(Env<?> env, JCTree tree) {
  2401             try {
  2402                 startPos = tree.pos().getStartPosition();
  2404                 if (vardecls == null)
  2405                     vardecls = new JCVariableDecl[32];
  2406                 else
  2407                     for (int i=0; i<vardecls.length; i++)
  2408                         vardecls[i] = null;
  2409                 firstadr = 0;
  2410                 nextadr = 0;
  2411                 pendingExits = new ListBuffer<>();
  2412                 this.classDef = null;
  2413                 unrefdResources = new Scope(env.enclClass.sym);
  2414                 scan(tree);
  2415             } finally {
  2416                 // note that recursive invocations of this method fail hard
  2417                 startPos = -1;
  2418                 resetBits(inits, uninits, uninitsTry, initsWhenTrue,
  2419                         initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
  2420                 if (vardecls != null) {
  2421                     for (int i=0; i<vardecls.length; i++)
  2422                         vardecls[i] = null;
  2424                 firstadr = 0;
  2425                 nextadr = 0;
  2426                 pendingExits = null;
  2427                 this.classDef = null;
  2428                 unrefdResources = null;
  2433     public class AssignAnalyzer extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> {
  2435         public class AssignPendingExit extends AbstractAssignAnalyzer<AssignPendingExit>.AbstractAssignPendingExit {
  2437             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
  2438                 super(tree, inits, uninits);
  2442         @Override
  2443         protected AssignPendingExit createNewPendingExit(JCTree tree,
  2444             Bits inits, Bits uninits) {
  2445             return new AssignPendingExit(tree, inits, uninits);
  2448         /** Record an initialization of a trackable variable.
  2449          */
  2450         @Override
  2451         void letInit(DiagnosticPosition pos, VarSymbol sym) {
  2452             if (sym.adr >= firstadr && trackable(sym)) {
  2453                 if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
  2454                     if (!uninits.isMember(sym.adr)) {
  2455                         //assignment targeting an effectively final variable
  2456                         //makes the variable lose its status of effectively final
  2457                         //if the variable is _not_ definitively unassigned
  2458                         sym.flags_field &= ~EFFECTIVELY_FINAL;
  2459                     } else {
  2460                         uninit(sym);
  2463                 else if ((sym.flags() & FINAL) != 0) {
  2464                     if ((sym.flags() & PARAMETER) != 0) {
  2465                         if ((sym.flags() & UNION) != 0) { //multi-catch parameter
  2466                             log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
  2468                         else {
  2469                             log.error(pos, "final.parameter.may.not.be.assigned",
  2470                                   sym);
  2472                     } else if (!uninits.isMember(sym.adr)) {
  2473                         log.error(pos, flowKind.errKey, sym);
  2474                     } else {
  2475                         uninit(sym);
  2478                 inits.incl(sym.adr);
  2479             } else if ((sym.flags() & FINAL) != 0) {
  2480                 log.error(pos, "var.might.already.be.assigned", sym);
  2484         @Override
  2485         void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
  2486             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
  2487                 trackable(sym) &&
  2488                 !inits.isMember(sym.adr)) {
  2489                 log.error(pos, errkey, sym);
  2490                 inits.incl(sym.adr);
  2494         @Override
  2495         void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
  2496             String key, Object ... args) {
  2497             log.warning(lc, pos, key, args);
  2500         @Override
  2501         int getLogNumberOfErrors() {
  2502             return log.nerrors;
  2505         @Override
  2506         boolean isEnabled(Lint.LintCategory lc) {
  2507             return lint.isEnabled(lc);
  2510         @Override
  2511         public void visitClassDef(JCClassDecl tree) {
  2512             if (tree.sym == null) {
  2513                 return;
  2516             Lint lintPrev = lint;
  2517             lint = lint.augment(tree.sym);
  2518             try {
  2519                 super.visitClassDef(tree);
  2520             } finally {
  2521                 lint = lintPrev;
  2525         @Override
  2526         public void visitMethodDef(JCMethodDecl tree) {
  2527             if (tree.body == null) {
  2528                 return;
  2531             /*  MemberEnter can generate synthetic methods ignore them
  2532              */
  2533             if ((tree.sym.flags() & SYNTHETIC) != 0) {
  2534                 return;
  2537             Lint lintPrev = lint;
  2538             lint = lint.augment(tree.sym);
  2539             try {
  2540                 super.visitMethodDef(tree);
  2541             } finally {
  2542                 lint = lintPrev;
  2546         @Override
  2547         public void visitVarDef(JCVariableDecl tree) {
  2548             if (tree.init == null) {
  2549                 super.visitVarDef(tree);
  2550             } else {
  2551                 Lint lintPrev = lint;
  2552                 lint = lint.augment(tree.sym);
  2553                 try{
  2554                     super.visitVarDef(tree);
  2555                 } finally {
  2556                     lint = lintPrev;
  2563     /**
  2564      * This pass implements the last step of the dataflow analysis, namely
  2565      * the effectively-final analysis check. This checks that every local variable
  2566      * reference from a lambda body/local inner class is either final or effectively final.
  2567      * As effectively final variables are marked as such during DA/DU, this pass must run after
  2568      * AssignAnalyzer.
  2569      */
  2570     class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
  2572         JCTree currentTree; //local class or lambda
  2574         @Override
  2575         void markDead(JCTree tree) {
  2576             //do nothing
  2579         @SuppressWarnings("fallthrough")
  2580         void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
  2581             if (currentTree != null &&
  2582                     sym.owner.kind == MTH &&
  2583                     sym.pos < currentTree.getStartPosition()) {
  2584                 switch (currentTree.getTag()) {
  2585                     case CLASSDEF:
  2586                         if (!allowEffectivelyFinalInInnerClasses) {
  2587                             if ((sym.flags() & FINAL) == 0) {
  2588                                 reportInnerClsNeedsFinalError(pos, sym);
  2590                             break;
  2592                     case LAMBDA:
  2593                         if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
  2594                            reportEffectivelyFinalError(pos, sym);
  2600         @SuppressWarnings("fallthrough")
  2601         void letInit(JCTree tree) {
  2602             tree = TreeInfo.skipParens(tree);
  2603             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
  2604                 Symbol sym = TreeInfo.symbol(tree);
  2605                 if (currentTree != null &&
  2606                         sym.kind == VAR &&
  2607                         sym.owner.kind == MTH &&
  2608                         ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
  2609                     switch (currentTree.getTag()) {
  2610                         case CLASSDEF:
  2611                             if (!allowEffectivelyFinalInInnerClasses) {
  2612                                 reportInnerClsNeedsFinalError(tree, sym);
  2613                                 break;
  2615                         case LAMBDA:
  2616                             reportEffectivelyFinalError(tree, sym);
  2622         void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
  2623             String subKey = currentTree.hasTag(LAMBDA) ?
  2624                   "lambda"  : "inner.cls";
  2625             log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
  2628         void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
  2629             log.error(pos,
  2630                     "local.var.accessed.from.icls.needs.final",
  2631                     sym);
  2634     /*************************************************************************
  2635      * Visitor methods for statements and definitions
  2636      *************************************************************************/
  2638         /* ------------ Visitor methods for various sorts of trees -------------*/
  2640         public void visitClassDef(JCClassDecl tree) {
  2641             JCTree prevTree = currentTree;
  2642             try {
  2643                 currentTree = tree.sym.isLocal() ? tree : null;
  2644                 super.visitClassDef(tree);
  2645             } finally {
  2646                 currentTree = prevTree;
  2650         @Override
  2651         public void visitLambda(JCLambda tree) {
  2652             JCTree prevTree = currentTree;
  2653             try {
  2654                 currentTree = tree;
  2655                 super.visitLambda(tree);
  2656             } finally {
  2657                 currentTree = prevTree;
  2661         @Override
  2662         public void visitIdent(JCIdent tree) {
  2663             if (tree.sym.kind == VAR) {
  2664                 checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
  2668         public void visitAssign(JCAssign tree) {
  2669             JCTree lhs = TreeInfo.skipParens(tree.lhs);
  2670             if (!(lhs instanceof JCIdent)) {
  2671                 scan(lhs);
  2673             scan(tree.rhs);
  2674             letInit(lhs);
  2677         public void visitAssignop(JCAssignOp tree) {
  2678             scan(tree.lhs);
  2679             scan(tree.rhs);
  2680             letInit(tree.lhs);
  2683         public void visitUnary(JCUnary tree) {
  2684             switch (tree.getTag()) {
  2685                 case PREINC: case POSTINC:
  2686                 case PREDEC: case POSTDEC:
  2687                     scan(tree.arg);
  2688                     letInit(tree.arg);
  2689                     break;
  2690                 default:
  2691                     scan(tree.arg);
  2695         public void visitTopLevel(JCCompilationUnit tree) {
  2696             // Do nothing for TopLevel since each class is visited individually
  2699     /**************************************************************************
  2700      * main method
  2701      *************************************************************************/
  2703         /** Perform definite assignment/unassignment analysis on a tree.
  2704          */
  2705         public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
  2706             analyzeTree(env, env.tree, make);
  2708         public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
  2709             try {
  2710                 attrEnv = env;
  2711                 Flow.this.make = make;
  2712                 pendingExits = new ListBuffer<PendingExit>();
  2713                 scan(tree);
  2714             } finally {
  2715                 pendingExits = null;
  2716                 Flow.this.make = null;

mercurial