Flow.java revision 2723:0b467b70ad82
1139825Simp/*
21541Srgrimes * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
31541Srgrimes * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
41541Srgrimes *
51541Srgrimes * This code is free software; you can redistribute it and/or modify it
61541Srgrimes * under the terms of the GNU General Public License version 2 only, as
71541Srgrimes * published by the Free Software Foundation.  Oracle designates this
81541Srgrimes * particular file as subject to the "Classpath" exception as provided
91541Srgrimes * by Oracle in the LICENSE file that accompanied this code.
101541Srgrimes *
111541Srgrimes * This code is distributed in the hope that it will be useful, but WITHOUT
121541Srgrimes * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
131541Srgrimes * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
141541Srgrimes * version 2 for more details (a copy is included in the LICENSE file that
151541Srgrimes * accompanied this code).
161541Srgrimes *
171541Srgrimes * You should have received a copy of the GNU General Public License version
181541Srgrimes * 2 along with this work; if not, write to the Free Software Foundation,
191541Srgrimes * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
201541Srgrimes *
211541Srgrimes * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
221541Srgrimes * or visit www.oracle.com if you need additional information or have any
231541Srgrimes * questions.
241541Srgrimes */
251541Srgrimes
261541Srgrimes//todo: one might eliminate uninits.andSets when monotonic
271541Srgrimes
281541Srgrimespackage com.sun.tools.javac.comp;
291541Srgrimes
301541Srgrimesimport java.util.HashMap;
311541Srgrimes
321541Srgrimesimport com.sun.tools.javac.code.*;
3350477Speterimport com.sun.tools.javac.code.Scope.WriteableScope;
341541Srgrimesimport com.sun.tools.javac.tree.*;
351541Srgrimesimport com.sun.tools.javac.util.*;
361541Srgrimesimport com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
371541Srgrimes
381541Srgrimesimport com.sun.tools.javac.code.Symbol.*;
3950520Sphkimport com.sun.tools.javac.tree.JCTree.*;
4034925Sdufault
4183366Sjulianimport static com.sun.tools.javac.code.Flags.*;
421541Srgrimesimport static com.sun.tools.javac.code.Flags.BLOCK;
431541Srgrimesimport static com.sun.tools.javac.code.Kinds.Kind.*;
441541Srgrimesimport static com.sun.tools.javac.code.TypeTag.BOOLEAN;
451541Srgrimesimport static com.sun.tools.javac.code.TypeTag.VOID;
461541Srgrimesimport static com.sun.tools.javac.tree.JCTree.Tag.*;
471541Srgrimes
481541Srgrimes/** This pass implements dataflow analysis for Java programs though
491541Srgrimes *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
501541Srgrimes *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
51126293Sdes *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
521541Srgrimes *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
531541Srgrimes *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
541541Srgrimes *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
558876Srgrimes *  determines that local variables accessed within the scope of an inner class/lambda
561541Srgrimes *  are either final or effectively-final.
571541Srgrimes *
58122707Strhodes *  <p>The JLS has a number of problems in the
591541Srgrimes *  specification of these flow analysis problems. This implementation
601541Srgrimes *  attempts to address those issues.
611541Srgrimes *
621541Srgrimes *  <p>First, there is no accommodation for a finally clause that cannot
631541Srgrimes *  complete normally. For liveness analysis, an intervening finally
6411863Sphk *  clause can cause a break, continue, or return not to reach its
6511865Sphk *  target.  For exception analysis, an intervening finally clause can
661541Srgrimes *  cause any exception to be "caught".  For DA/DU analysis, the finally
671541Srgrimes *  clause can prevent a transfer of control from propagating DA/DU
681541Srgrimes *  state to the target.  In addition, code in the finally clause can
691541Srgrimes *  affect the DA/DU status of variables.
7011863Sphk *
7111863Sphk *  <p>For try statements, we introduce the idea of a variable being
7278435Spirzyk *  definitely unassigned "everywhere" in a block.  A variable V is
7378435Spirzyk *  "unassigned everywhere" in a block iff it is unassigned at the
7478435Spirzyk *  beginning of the block and there is no reachable assignment to V
751541Srgrimes *  in the block.  An assignment V=e is reachable iff V is not DA
7611863Sphk *  after e.  Then we can say that V is DU at the beginning of the
7711863Sphk *  catch block iff V is DU everywhere in the try block.  Similarly, V
7811863Sphk *  is DU at the beginning of the finally block iff V is DU everywhere
7911865Sphk *  in the try block and in every catch block.  Specifically, the
8012910Sphk *  following bullet is added to 16.2.2
8141728Struckman *  <pre>
8246155Sphk *      V is <em>unassigned everywhere</em> in a block if it is
8363212Sabial *      unassigned before the block and there is no reachable
84101650Smux *      assignment to V within the block.
85109246Sdillon *  </pre>
86121305Ssilby *  <p>In 16.2.15, the third bullet (and all of its sub-bullets) for all
87121305Ssilby *  try blocks is changed to
8811863Sphk *  <pre>
8919268Sjulian *      V is definitely unassigned before a catch block iff V is
90109246Sdillon *      definitely unassigned everywhere in the try block.
91109246Sdillon *  </pre>
92109246Sdillon *  <p>The last bullet (and all of its sub-bullets) for try blocks that
93109246Sdillon *  have a finally block is changed to
94109246Sdillon *  <pre>
95109246Sdillon *      V is definitely unassigned before the finally block iff
96109246Sdillon *      V is definitely unassigned everywhere in the try block
97109246Sdillon *      and everywhere in each catch block of the try statement.
98109246Sdillon *  </pre>
99109246Sdillon *  <p>In addition,
10019268Sjulian *  <pre>
10119268Sjulian *      V is definitely assigned at the end of a constructor iff
10219268Sjulian *      V is definitely assigned after the block that is the body
10334925Sdufault *      of the constructor and V is definitely assigned at every
10419268Sjulian *      return that can return from the constructor.
10519268Sjulian *  </pre>
10612582Sphk *  <p>In addition, each continue statement with the loop as its target
10712582Sphk *  is treated as a jump to the end of the loop body, and "intervening"
10880339Sroam *  finally clauses are treated as follows: V is DA "due to the
10980339Sroam *  continue" iff V is DA before the continue statement or V is DA at
11080339Sroam *  the end of any intervening finally block.  V is DU "due to the
11180339Sroam *  continue" iff any intervening finally cannot complete normally or V
11280339Sroam *  is DU at the end of every intervening finally block.  This "due to
11380339Sroam *  the continue" concept is then used in the spec for the loops.
11455205Speter *
11562454Sphk *  <p>Similarly, break statements must consider intervening finally
11662454Sphk *  blocks.  For liveness analysis, a break statement for which any
11711863Sphk *  intervening finally cannot complete normally is not considered to
118120781Sbms *  cause the target statement to be able to complete normally. Then
119120781Sbms *  we say V is DA "due to the break" iff V is DA before the break or
120120781Sbms *  V is DA at the end of any intervening finally block.  V is DU "due
121120781Sbms *  to the break" iff any intervening finally cannot complete normally
122120781Sbms *  or V is DU at the break and at the end of every intervening
123136404Speter *  finally block.  (I suspect this latter condition can be
124136404Speter *  simplified.)  This "due to the break" is then used in the spec for
125136404Speter *  all statements that can be "broken".
126136404Speter *
127136404Speter *  <p>The return statement is treated similarly.  V is DA "due to a
12812243Sphk *  return statement" iff V is DA before the return statement or V is
12912243Sphk *  DA at the end of any intervening finally block.  Note that we
13012243Sphk *  don't have to worry about the return expression because this
13112243Sphk *  concept is only used for construcrors.
13212243Sphk *
13386183Srwatson *  <p>There is no spec in the JLS for when a variable is definitely
134120781Sbms *  assigned at the end of a constructor, which is needed for final
13512243Sphk *  fields (8.3.1.2).  We implement the rule that V is DA at the end
13638517Sdfr *  of the constructor iff it is DA and the end of the body of the
13738517Sdfr *  constructor and V is DA "due to" every return of the constructor.
13838517Sdfr *
13912243Sphk *  <p>Intervening finally blocks similarly affect exception analysis.  An
14038517Sdfr *  intervening finally that cannot complete normally allows us to ignore
14138517Sdfr *  an otherwise uncaught exception.
14238517Sdfr *
143127052Struckman *  <p>To implement the semantics of intervening finally clauses, all
144136404Speter *  nonlocal transfers (break, continue, return, throw, method call that
14512243Sphk *  can throw a checked exception, and a constructor invocation that can
14612243Sphk *  thrown a checked exception) are recorded in a queue, and removed
14760938Sjake *  from the queue when we complete processing the target of the
14844078Sdfr *  nonlocal transfer.  This allows us to modify the queue in accordance
14912243Sphk *  with the above rules when we encounter a finally clause.  The only
15012243Sphk *  exception to this [no pun intended] is that checked exceptions that
15112243Sphk *  are known to be caught or declared to be caught in the enclosing
15212243Sphk *  method are not recorded in the queue, but instead are recorded in a
15311863Sphk *  global variable "{@code Set<Type> thrown}" that records the type of all
15444078Sdfr *  exceptions that can be thrown.
15560938Sjake *
15611863Sphk *  <p>Other minor issues the treatment of members of other classes
157100113Smarkm *  (always considered DA except that within an anonymous class
15811863Sphk *  constructor, where DA status from the enclosing scope is
15911863Sphk *  preserved), treatment of the case expression (V is DA before the
16012623Sphk *  case expression iff V is DA after the switch expression),
16162573Sphk *  treatment of variables declared in a switch block (the implied
16212623Sphk *  DA/DU status after the switch expression is DU and not DA for
16363212Sabial *  variables defined in a switch block), the treatment of boolean ?:
164100113Smarkm *  expressions (The JLS rules only handle b and c non-boolean; the
16511863Sphk *  new rule is that if b and c are boolean valued, then V is
16611863Sphk *  (un)assigned after a?b:c when true/false iff V is (un)assigned
16712243Sphk *  after b when true/false and V is (un)assigned after c when
16812243Sphk *  true/false).
16912243Sphk *
17062573Sphk *  <p>There is the remaining question of what syntactic forms constitute a
17162573Sphk *  reference to a variable.  It is conventional to allow this.x on the
17262573Sphk *  left-hand-side to initialize a final instance field named x, yet
17362573Sphk *  this.x isn't considered a "use" when appearing on a right-hand-side
17462573Sphk *  in most implementations.  Should parentheses affect what is
17511865Sphk *  considered a variable reference?  The simplest rule would be to
17644078Sdfr *  allow unqualified forms only, parentheses optional, and phase out
17744078Sdfr *  support for assigning to a final field via this.x.
17844078Sdfr *
17944078Sdfr *  <p><b>This is NOT part of any supported API.
18044078Sdfr *  If you write code that depends on this, you do so at your own risk.
18144078Sdfr *  This code and its internal interfaces are subject to change or
18263212Sabial *  deletion without notice.</b>
18344078Sdfr */
18444078Sdfrpublic class Flow {
18544078Sdfr    protected static final Context.Key<Flow> flowKey = new Context.Key<>();
18663212Sabial
18763212Sabial    private final Names names;
18863212Sabial    private final Log log;
189132784Skan    private final Symtab syms;
190132784Skan    private final Types types;
19163212Sabial    private final Check chk;
19263212Sabial    private       TreeMaker make;
19363212Sabial    private final Resolve rs;
19463212Sabial    private final JCDiagnostic.Factory diags;
19563212Sabial    private Env<AttrContext> attrEnv;
19663212Sabial    private       Lint lint;
19763212Sabial    private final boolean allowImprovedRethrowAnalysis;
19863212Sabial    private final boolean allowImprovedCatchAnalysis;
19963212Sabial    private final boolean allowEffectivelyFinalInInnerClasses;
20063212Sabial    private final boolean enforceThisDotInit;
20163212Sabial
20263212Sabial    public static Flow instance(Context context) {
20363212Sabial        Flow instance = context.get(flowKey);
204108649Sjake        if (instance == null)
205108649Sjake            instance = new Flow(context);
206108649Sjake        return instance;
20738859Sbde    }
20812623Sphk
20944078Sdfr    public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
21044078Sdfr        new AliveAnalyzer().analyzeTree(env, make);
21188006Sluigi        new AssignAnalyzer().analyzeTree(env);
212100113Smarkm        new FlowAnalyzer().analyzeTree(env, make);
21311863Sphk        new CaptureAnalyzer().analyzeTree(env, make);
21463212Sabial    }
215100113Smarkm
21663212Sabial    public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
21738859Sbde        Log.DiagnosticHandler diagHandler = null;
21844078Sdfr        //we need to disable diagnostics temporarily; the problem is that if
219108649Sjake        //a lambda expression contains e.g. an unreachable statement, an error
220105582Sphk        //message will be reported and will cause compilation to skip the flow analyis
221108649Sjake        //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
222100113Smarkm        //related errors, which will allow for more errors to be detected
22311863Sphk        if (!speculative) {
22463212Sabial            diagHandler = new Log.DiscardDiagnosticHandler(log);
225105582Sphk        }
226100113Smarkm        try {
22763212Sabial            new AliveAnalyzer().analyzeTree(env, that, make);
22838859Sbde        } finally {
22912623Sphk            if (!speculative) {
230105582Sphk                log.popDiagnosticHandler(diagHandler);
23129210Sbde            }
23211863Sphk        }
23363212Sabial    }
234105582Sphk
235100113Smarkm    public List<Type> analyzeLambdaThrownTypes(final Env<AttrContext> env,
23663212Sabial            JCLambda that, TreeMaker make) {
23738859Sbde        //we need to disable diagnostics temporarily; the problem is that if
23812623Sphk        //a lambda expression contains e.g. an unreachable statement, an error
239105582Sphk        //message will be reported and will cause compilation to skip the flow analyis
24029210Sbde        //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
24111863Sphk        //related errors, which will allow for more errors to be detected
24263212Sabial        Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
243105582Sphk        try {
244100113Smarkm            new AssignAnalyzer() {
24563212Sabial                WriteableScope enclosedSymbols = WriteableScope.create(env.enclClass.sym);
24662622Sjhb                @Override
24762622Sjhb                public void visitVarDef(JCVariableDecl tree) {
248105582Sphk                    enclosedSymbols.enter(tree.sym);
24962622Sjhb                    super.visitVarDef(tree);
25062622Sjhb                }
25163212Sabial                @Override
252105582Sphk                protected boolean trackable(VarSymbol sym) {
253100113Smarkm                    return enclosedSymbols.includes(sym) &&
25463212Sabial                           sym.owner.kind == MTH;
25542095Sdfr                }
25662622Sjhb            }.analyzeTree(env, that);
257105582Sphk            LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
25862622Sjhb            flowAnalyzer.analyzeTree(env, that, make);
25938517Sdfr            return flowAnalyzer.inferredThrownTypes;
26063212Sabial        } finally {
261105582Sphk            log.popDiagnosticHandler(diagHandler);
262100113Smarkm        }
26363212Sabial    }
264112744Srobert
26562622Sjhb    /**
266105582Sphk     * Definite assignment scan mode
26762622Sjhb     */
26862622Sjhb    enum FlowKind {
26963212Sabial        /**
270105582Sphk         * This is the normal DA/DU analysis mode
271100113Smarkm         */
27263212Sabial        NORMAL("var.might.already.be.assigned", false),
27338859Sbde        /**
27412705Sphk         * This is the speculative DA/DU analysis mode used to speculatively
275105582Sphk         * derive assertions within loop bodies
27629210Sbde         */
27711863Sphk        SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
27863212Sabial
279105582Sphk        final String errKey;
280100113Smarkm        final boolean isFinal;
28163212Sabial
28238859Sbde        FlowKind(String errKey, boolean isFinal) {
28312623Sphk            this.errKey = errKey;
284105582Sphk            this.isFinal = isFinal;
28512623Sphk        }
28629210Sbde
28711863Sphk        boolean isFinal() {
28863212Sabial            return isFinal;
289105582Sphk        }
290100113Smarkm    }
29163212Sabial
29238859Sbde    protected Flow(Context context) {
29312623Sphk        context.put(flowKey, this);
294105582Sphk        names = Names.instance(context);
29529210Sbde        log = Log.instance(context);
29663212Sabial        syms = Symtab.instance(context);
29763212Sabial        types = Types.instance(context);
298105582Sphk        chk = Check.instance(context);
299100113Smarkm        lint = Lint.instance(context);
30063212Sabial        rs = Resolve.instance(context);
30155205Speter        diags = JCDiagnostic.Factory.instance(context);
30211863Sphk        Source source = Source.instance(context);
3031541Srgrimes        allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
3041541Srgrimes        allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
3051541Srgrimes        allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
3061541Srgrimes        enforceThisDotInit = source.enforceThisDotInit();
3071541Srgrimes    }
3081541Srgrimes
30996755Strhodes    /**
3101541Srgrimes     * Base visitor class for all visitors implementing dataflow analysis logic.
3111541Srgrimes     * This class define the shared logic for handling jumps (break/continue statements).
3121541Srgrimes     */
3131541Srgrimes    static abstract class BaseAnalyzer<P extends BaseAnalyzer.PendingExit> extends TreeScanner {
3141541Srgrimes
31534925Sdufault        enum JumpKind {
31634030Sdufault            BREAK(JCTree.Tag.BREAK) {
31734030Sdufault                @Override
3181541Srgrimes                JCTree getTarget(JCTree tree) {
3191541Srgrimes                    return ((JCBreak)tree).target;
3201541Srgrimes                }
3211541Srgrimes            },
32214498Shsu            CONTINUE(JCTree.Tag.CONTINUE) {
3231541Srgrimes                @Override
3241541Srgrimes                JCTree getTarget(JCTree tree) {
3251541Srgrimes                    return ((JCContinue)tree).target;
3261541Srgrimes                }
3271541Srgrimes            };
32834925Sdufault
3291541Srgrimes            final JCTree.Tag treeTag;
3301541Srgrimes
3311541Srgrimes            private JumpKind(Tag treeTag) {
3321541Srgrimes                this.treeTag = treeTag;
3331541Srgrimes            }
3341541Srgrimes
3351541Srgrimes            abstract JCTree getTarget(JCTree tree);
3361541Srgrimes        }
3371541Srgrimes
3381541Srgrimes        /** The currently pending exits that go from current inner blocks
3391541Srgrimes         *  to an enclosing block, in source order.
3401541Srgrimes         */
3411541Srgrimes        ListBuffer<P> pendingExits;
3421541Srgrimes
3431541Srgrimes        /** A pending exit.  These are the statements return, break, and
3441541Srgrimes         *  continue.  In addition, exception-throwing expressions or
3451541Srgrimes         *  statements are put here when not known to be caught.  This
3461541Srgrimes         *  will typically result in an error unless it is within a
3471541Srgrimes         *  try-finally whose finally block cannot complete normally.
3481541Srgrimes         */
3491541Srgrimes        static class PendingExit {
3501541Srgrimes            JCTree tree;
3511541Srgrimes
3521541Srgrimes            PendingExit(JCTree tree) {
3531541Srgrimes                this.tree = tree;
3541541Srgrimes            }
35517281Swollman
3561952Swollman            void resolveJump(JCTree tree) {
357119212Seivind                //do nothing
3582858Swollman            }
3593038Swollman        }
3606577Sguido
3616577Sguido        abstract void markDead(JCTree tree);
362130585Sphk
36323083Swollman        /** Record an outward transfer of control. */
36423083Swollman        void recordExit(JCTree tree, P pe) {
36514235Speter            pendingExits.append(pe);
36614235Speter            markDead(tree);
36737931Sjoerg        }
36878431Swollman
369116090Sjmallett        /** Resolve all jumps of this statement. */
3701541Srgrimes        private boolean resolveJump(JCTree tree,
3711541Srgrimes                        ListBuffer<P> oldPendingExits,
3721541Srgrimes                        JumpKind jk) {
3731541Srgrimes            boolean resolved = false;
3741541Srgrimes            List<P> exits = pendingExits.toList();
3751541Srgrimes            pendingExits = oldPendingExits;
3761541Srgrimes            for (; exits.nonEmpty(); exits = exits.tail) {
3771541Srgrimes                P exit = exits.head;
3781541Srgrimes                if (exit.tree.hasTag(jk.treeTag) &&
3791541Srgrimes                        jk.getTarget(exit.tree) == tree) {
3801541Srgrimes                    exit.resolveJump(tree);
3811541Srgrimes                    resolved = true;
3821541Srgrimes                } else {
38378435Spirzyk                    pendingExits.append(exit);
3841541Srgrimes                }
3851541Srgrimes            }
3861541Srgrimes            return resolved;
3871541Srgrimes        }
3881541Srgrimes
3891541Srgrimes        /** Resolve all continues of this statement. */
3901541Srgrimes        boolean resolveContinues(JCTree tree) {
3911541Srgrimes            return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
3921541Srgrimes        }
3931541Srgrimes
39417281Swollman        /** Resolve all breaks of this statement. */
3951952Swollman        boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
3962004Swollman            return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
39772857Sjhb        }
3983038Swollman
3996577Sguido        @Override
4006577Sguido        public void scan(JCTree tree) {
40123083Swollman            if (tree != null && (
40223083Swollman                    tree.type == null ||
40314235Speter                    tree.type != Type.stuckType)) {
40414235Speter                super.scan(tree);
40537931Sjoerg            }
40678431Swollman        }
4071541Srgrimes
4081541Srgrimes        public void visitPackageDef(JCPackageDecl tree) {
4092946Swollman            // Do nothing for PackageDecl
41014498Shsu        }
4112946Swollman    }
41214498Shsu
4132946Swollman    /**
4142946Swollman     * This pass implements the first step of the dataflow analysis, namely
4152946Swollman     * the liveness analysis check. This checks that every statement is reachable.
4168876Srgrimes     * The output of this analysis pass are used by other analyzers. This analyzer
4171541Srgrimes     * sets the 'finallyCanCompleteNormally' field in the JCTry class.
4181541Srgrimes     */
4191541Srgrimes    class AliveAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
4201541Srgrimes
4211541Srgrimes        /** A flag that indicates whether the last statement could
4221541Srgrimes         *  complete normally.
4231541Srgrimes         */
4241541Srgrimes        private boolean alive;
4251541Srgrimes
42653239Sphk        @Override
427116261Sscottl        void markDead(JCTree tree) {
428117464Srobert            alive = false;
429129597Sgad        }
430130725Sgad
431126125Sdeischen    /*************************************************************************
432126125Sdeischen     * Visitor methods for statements and definitions
433130725Sgad     *************************************************************************/
434126125Sdeischen
4351541Srgrimes        /** Analyze a definition.
4368876Srgrimes         */
43723083Swollman        void scanDef(JCTree tree) {
43823083Swollman            scanStat(tree);
43923083Swollman            if (tree != null && tree.hasTag(JCTree.Tag.BLOCK) && !alive) {
44023083Swollman                log.error(tree.pos(),
44123083Swollman                          "initializer.must.be.able.to.complete.normally");
44223083Swollman            }
44323083Swollman        }
44423083Swollman
44523083Swollman        /** Analyze a statement. Check that statement is reachable.
44623083Swollman         */
44723083Swollman        void scanStat(JCTree tree) {
4481541Srgrimes            if (!alive && tree != null) {
4491541Srgrimes                log.error(tree.pos(), "unreachable.stmt");
4501541Srgrimes                if (!tree.hasTag(SKIP)) alive = true;
4511541Srgrimes            }
4521541Srgrimes            scan(tree);
4531541Srgrimes        }
4541541Srgrimes
4551541Srgrimes        /** Analyze list of statements.
4561541Srgrimes         */
4571541Srgrimes        void scanStats(List<? extends JCStatement> trees) {
4581541Srgrimes            if (trees != null)
4592631Swollman                for (List<? extends JCStatement> l = trees; l.nonEmpty(); l = l.tail)
46028885Skato                    scanStat(l.head);
46128885Skato        }
4621541Srgrimes
4631541Srgrimes        /* ------------ Visitor methods for various sorts of trees -------------*/
4641541Srgrimes
4651541Srgrimes        public void visitClassDef(JCClassDecl tree) {
4661541Srgrimes            if (tree.sym == null) return;
4671541Srgrimes            boolean alivePrev = alive;
4681541Srgrimes            ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
46978435Spirzyk            Lint lintPrev = lint;
47078435Spirzyk
4711541Srgrimes            pendingExits = new ListBuffer<>();
4721541Srgrimes            lint = lint.augment(tree.sym);
4731541Srgrimes
4742631Swollman            try {
4751541Srgrimes                // process all the static initializers
4761541Srgrimes                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
4771541Srgrimes                    if (!l.head.hasTag(METHODDEF) &&
4781541Srgrimes                        (TreeInfo.flags(l.head) & STATIC) != 0) {
4791541Srgrimes                        scanDef(l.head);
4801541Srgrimes                    }
4811541Srgrimes                }
4821541Srgrimes
4831541Srgrimes                // process all the instance initializers
4841541Srgrimes                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
4851541Srgrimes                    if (!l.head.hasTag(METHODDEF) &&
4861541Srgrimes                        (TreeInfo.flags(l.head) & STATIC) == 0) {
4871541Srgrimes                        scanDef(l.head);
4881541Srgrimes                    }
4891541Srgrimes                }
4901541Srgrimes
4911541Srgrimes                // process all the methods
4921541Srgrimes                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
4931541Srgrimes                    if (l.head.hasTag(METHODDEF)) {
4941541Srgrimes                        scan(l.head);
4951541Srgrimes                    }
4961541Srgrimes                }
4971541Srgrimes            } finally {
4981541Srgrimes                pendingExits = pendingExitsPrev;
4991541Srgrimes                alive = alivePrev;
5001541Srgrimes                lint = lintPrev;
5011541Srgrimes            }
5021541Srgrimes        }
5031541Srgrimes
5041541Srgrimes        public void visitMethodDef(JCMethodDecl tree) {
5051541Srgrimes            if (tree.body == null) return;
5061541Srgrimes            Lint lintPrev = lint;
5071541Srgrimes
5081541Srgrimes            lint = lint.augment(tree.sym);
5091541Srgrimes
5101541Srgrimes            Assert.check(pendingExits.isEmpty());
5111541Srgrimes
5121541Srgrimes            try {
5131541Srgrimes                alive = true;
5141541Srgrimes                scanStat(tree.body);
5151541Srgrimes
5161541Srgrimes                if (alive && !tree.sym.type.getReturnType().hasTag(VOID))
5171541Srgrimes                    log.error(TreeInfo.diagEndPos(tree.body), "missing.ret.stmt");
5181541Srgrimes
5191541Srgrimes                List<PendingExit> exits = pendingExits.toList();
5201541Srgrimes                pendingExits = new ListBuffer<>();
5211541Srgrimes                while (exits.nonEmpty()) {
5221541Srgrimes                    PendingExit exit = exits.head;
5231541Srgrimes                    exits = exits.tail;
5241541Srgrimes                    Assert.check(exit.tree.hasTag(RETURN));
5251541Srgrimes                }
52634925Sdufault            } finally {
52734925Sdufault                lint = lintPrev;
52834925Sdufault            }
52934925Sdufault        }
53034925Sdufault
53134925Sdufault        public void visitVarDef(JCVariableDecl tree) {
53234925Sdufault            if (tree.init != null) {
53334925Sdufault                Lint lintPrev = lint;
53434925Sdufault                lint = lint.augment(tree.sym);
53534925Sdufault                try{
53634925Sdufault                    scan(tree.init);
53734925Sdufault                } finally {
53834925Sdufault                    lint = lintPrev;
53934925Sdufault                }
54034925Sdufault            }
54134925Sdufault        }
54234925Sdufault
54334925Sdufault        public void visitBlock(JCBlock tree) {
54434925Sdufault            scanStats(tree.stats);
54534925Sdufault        }
54634925Sdufault
54734925Sdufault        public void visitDoLoop(JCDoWhileLoop tree) {
54834925Sdufault            ListBuffer<PendingExit> prevPendingExits = pendingExits;
54934925Sdufault            pendingExits = new ListBuffer<>();
55034925Sdufault            scanStat(tree.body);
55134925Sdufault            alive |= resolveContinues(tree);
55234925Sdufault            scan(tree.cond);
55334925Sdufault            alive = alive && !tree.cond.type.isTrue();
55434925Sdufault            alive |= resolveBreaks(tree, prevPendingExits);
55534925Sdufault        }
55634925Sdufault
55734925Sdufault        public void visitWhileLoop(JCWhileLoop tree) {
55834925Sdufault            ListBuffer<PendingExit> prevPendingExits = pendingExits;
55934925Sdufault            pendingExits = new ListBuffer<>();
56034925Sdufault            scan(tree.cond);
56134925Sdufault            alive = !tree.cond.type.isFalse();
56234925Sdufault            scanStat(tree.body);
56334925Sdufault            alive |= resolveContinues(tree);
56434925Sdufault            alive = resolveBreaks(tree, prevPendingExits) ||
56534925Sdufault                !tree.cond.type.isTrue();
56634925Sdufault        }
56734925Sdufault
56834925Sdufault        public void visitForLoop(JCForLoop tree) {
56934925Sdufault            ListBuffer<PendingExit> prevPendingExits = pendingExits;
57034925Sdufault            scanStats(tree.init);
57134925Sdufault            pendingExits = new ListBuffer<>();
57234925Sdufault            if (tree.cond != null) {
57334925Sdufault                scan(tree.cond);
57434925Sdufault                alive = !tree.cond.type.isFalse();
57534925Sdufault            } else {
57634925Sdufault                alive = true;
57734925Sdufault            }
57834925Sdufault            scanStat(tree.body);
57934925Sdufault            alive |= resolveContinues(tree);
58034925Sdufault            scan(tree.step);
58134925Sdufault            alive = resolveBreaks(tree, prevPendingExits) ||
58234925Sdufault                tree.cond != null && !tree.cond.type.isTrue();
58355205Speter        }
5841541Srgrimes
58544078Sdfr        public void visitForeachLoop(JCEnhancedForLoop tree) {
58644078Sdfr            visitVarDef(tree.var);
58744078Sdfr            ListBuffer<PendingExit> prevPendingExits = pendingExits;
58844078Sdfr            scan(tree.expr);
58944078Sdfr            pendingExits = new ListBuffer<>();
59044078Sdfr            scanStat(tree.body);
59144078Sdfr            alive |= resolveContinues(tree);
59244078Sdfr            resolveBreaks(tree, prevPendingExits);
59344078Sdfr            alive = true;
59444078Sdfr        }
59591687Sphk
59644078Sdfr        public void visitLabelled(JCLabeledStatement tree) {
59744078Sdfr            ListBuffer<PendingExit> prevPendingExits = pendingExits;
59844078Sdfr            pendingExits = new ListBuffer<>();
59950465Smarcel            scanStat(tree.body);
60044078Sdfr            alive |= resolveBreaks(tree, prevPendingExits);
6017090Sbde        }
6027090Sbde
6037090Sbde        public void visitSwitch(JCSwitch tree) {
604116105Sjmallett            ListBuffer<PendingExit> prevPendingExits = pendingExits;
6057090Sbde            pendingExits = new ListBuffer<>();
60663212Sabial            scan(tree.selector);
60763212Sabial            boolean hasDefault = false;
60870679Sjhb            for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
60963212Sabial                alive = true;
61063212Sabial                JCCase c = l.head;
61170679Sjhb                if (c.pat == null)
612126319Sdes                    hasDefault = true;
613126319Sdes                else
61463212Sabial                    scan(c.pat);
61563212Sabial                scanStats(c.stats);
61663212Sabial                // Warn about fall-through if lint switch fallthrough enabled.
61763212Sabial                if (alive &&
61863212Sabial                    lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
61963212Sabial                    c.stats.nonEmpty() && l.tail.nonEmpty())
62063212Sabial                    log.warning(Lint.LintCategory.FALLTHROUGH,
62163212Sabial                                l.tail.head.pos(),
62263212Sabial                                "possible.fall-through.into.case");
62363212Sabial            }
62483366Sjulian            if (!hasDefault) {
62538859Sbde                alive = true;
626136404Speter            }
62783366Sjulian            alive |= resolveBreaks(tree, prevPendingExits);
62876834Sjlemon        }
629136404Speter
63083366Sjulian        public void visitTry(JCTry tree) {
63138859Sbde            ListBuffer<PendingExit> prevPendingExits = pendingExits;
632136404Speter            pendingExits = new ListBuffer<>();
63353977Sgreen            for (JCTree resource : tree.resources) {
63453977Sgreen                if (resource instanceof JCVariableDecl) {
635126253Struckman                    JCVariableDecl vdecl = (JCVariableDecl) resource;
6363421Sphk                    visitVarDef(vdecl);
63755205Speter                } else if (resource instanceof JCExpression) {
6381541Srgrimes                    scan((JCExpression) resource);
6391541Srgrimes                } else {
6401541Srgrimes                    throw new AssertionError(tree);  // parser error
64192719Salfred                }
64292719Salfred            }
64392719Salfred
6441541Srgrimes            scanStat(tree.body);
64555205Speter            boolean aliveEnd = alive;
6464468Sbde
6471541Srgrimes            for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
648                alive = true;
649                JCVariableDecl param = l.head.param;
650                scan(param);
651                scanStat(l.head.body);
652                aliveEnd |= alive;
653            }
654            if (tree.finalizer != null) {
655                ListBuffer<PendingExit> exits = pendingExits;
656                pendingExits = prevPendingExits;
657                alive = true;
658                scanStat(tree.finalizer);
659                tree.finallyCanCompleteNormally = alive;
660                if (!alive) {
661                    if (lint.isEnabled(Lint.LintCategory.FINALLY)) {
662                        log.warning(Lint.LintCategory.FINALLY,
663                                TreeInfo.diagEndPos(tree.finalizer),
664                                "finally.cannot.complete");
665                    }
666                } else {
667                    while (exits.nonEmpty()) {
668                        pendingExits.append(exits.next());
669                    }
670                    alive = aliveEnd;
671                }
672            } else {
673                alive = aliveEnd;
674                ListBuffer<PendingExit> exits = pendingExits;
675                pendingExits = prevPendingExits;
676                while (exits.nonEmpty()) pendingExits.append(exits.next());
677            }
678        }
679
680        @Override
681        public void visitIf(JCIf tree) {
682            scan(tree.cond);
683            scanStat(tree.thenpart);
684            if (tree.elsepart != null) {
685                boolean aliveAfterThen = alive;
686                alive = true;
687                scanStat(tree.elsepart);
688                alive = alive | aliveAfterThen;
689            } else {
690                alive = true;
691            }
692        }
693
694        public void visitBreak(JCBreak tree) {
695            recordExit(tree, new PendingExit(tree));
696        }
697
698        public void visitContinue(JCContinue tree) {
699            recordExit(tree, new PendingExit(tree));
700        }
701
702        public void visitReturn(JCReturn tree) {
703            scan(tree.expr);
704            recordExit(tree, new PendingExit(tree));
705        }
706
707        public void visitThrow(JCThrow tree) {
708            scan(tree.expr);
709            markDead(tree);
710        }
711
712        public void visitApply(JCMethodInvocation tree) {
713            scan(tree.meth);
714            scan(tree.args);
715        }
716
717        public void visitNewClass(JCNewClass tree) {
718            scan(tree.encl);
719            scan(tree.args);
720            if (tree.def != null) {
721                scan(tree.def);
722            }
723        }
724
725        @Override
726        public void visitLambda(JCLambda tree) {
727            if (tree.type != null &&
728                    tree.type.isErroneous()) {
729                return;
730            }
731
732            ListBuffer<PendingExit> prevPending = pendingExits;
733            boolean prevAlive = alive;
734            try {
735                pendingExits = new ListBuffer<>();
736                alive = true;
737                scanStat(tree.body);
738                tree.canCompleteNormally = alive;
739            }
740            finally {
741                pendingExits = prevPending;
742                alive = prevAlive;
743            }
744        }
745
746    /**************************************************************************
747     * main method
748     *************************************************************************/
749
750        /** Perform definite assignment/unassignment analysis on a tree.
751         */
752        public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
753            analyzeTree(env, env.tree, make);
754        }
755        public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
756            try {
757                attrEnv = env;
758                Flow.this.make = make;
759                pendingExits = new ListBuffer<>();
760                alive = true;
761                scan(tree);
762            } finally {
763                pendingExits = null;
764                Flow.this.make = null;
765            }
766        }
767    }
768
769    /**
770     * This pass implements the second step of the dataflow analysis, namely
771     * the exception analysis. This is to ensure that every checked exception that is
772     * thrown is declared or caught. The analyzer uses some info that has been set by
773     * the liveliness analyzer.
774     */
775    class FlowAnalyzer extends BaseAnalyzer<FlowAnalyzer.FlowPendingExit> {
776
777        /** A flag that indicates whether the last statement could
778         *  complete normally.
779         */
780        HashMap<Symbol, List<Type>> preciseRethrowTypes;
781
782        /** The current class being defined.
783         */
784        JCClassDecl classDef;
785
786        /** The list of possibly thrown declarable exceptions.
787         */
788        List<Type> thrown;
789
790        /** The list of exceptions that are either caught or declared to be
791         *  thrown.
792         */
793        List<Type> caught;
794
795        class FlowPendingExit extends BaseAnalyzer.PendingExit {
796
797            Type thrown;
798
799            FlowPendingExit(JCTree tree, Type thrown) {
800                super(tree);
801                this.thrown = thrown;
802            }
803        }
804
805        @Override
806        void markDead(JCTree tree) {
807            //do nothing
808        }
809
810        /*-------------------- Exceptions ----------------------*/
811
812        /** Complain that pending exceptions are not caught.
813         */
814        void errorUncaught() {
815            for (FlowPendingExit exit = pendingExits.next();
816                 exit != null;
817                 exit = pendingExits.next()) {
818                if (classDef != null &&
819                    classDef.pos == exit.tree.pos) {
820                    log.error(exit.tree.pos(),
821                            "unreported.exception.default.constructor",
822                            exit.thrown);
823                } else if (exit.tree.hasTag(VARDEF) &&
824                        ((JCVariableDecl)exit.tree).sym.isResourceVariable()) {
825                    log.error(exit.tree.pos(),
826                            "unreported.exception.implicit.close",
827                            exit.thrown,
828                            ((JCVariableDecl)exit.tree).sym.name);
829                } else {
830                    log.error(exit.tree.pos(),
831                            "unreported.exception.need.to.catch.or.throw",
832                            exit.thrown);
833                }
834            }
835        }
836
837        /** Record that exception is potentially thrown and check that it
838         *  is caught.
839         */
840        void markThrown(JCTree tree, Type exc) {
841            if (!chk.isUnchecked(tree.pos(), exc)) {
842                if (!chk.isHandled(exc, caught)) {
843                    pendingExits.append(new FlowPendingExit(tree, exc));
844                }
845                thrown = chk.incl(exc, thrown);
846            }
847        }
848
849    /*************************************************************************
850     * Visitor methods for statements and definitions
851     *************************************************************************/
852
853        /* ------------ Visitor methods for various sorts of trees -------------*/
854
855        public void visitClassDef(JCClassDecl tree) {
856            if (tree.sym == null) return;
857
858            JCClassDecl classDefPrev = classDef;
859            List<Type> thrownPrev = thrown;
860            List<Type> caughtPrev = caught;
861            ListBuffer<FlowPendingExit> pendingExitsPrev = pendingExits;
862            Lint lintPrev = lint;
863
864            pendingExits = new ListBuffer<>();
865            if (tree.name != names.empty) {
866                caught = List.nil();
867            }
868            classDef = tree;
869            thrown = List.nil();
870            lint = lint.augment(tree.sym);
871
872            try {
873                // process all the static initializers
874                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
875                    if (!l.head.hasTag(METHODDEF) &&
876                        (TreeInfo.flags(l.head) & STATIC) != 0) {
877                        scan(l.head);
878                        errorUncaught();
879                    }
880                }
881
882                // add intersection of all thrown clauses of initial constructors
883                // to set of caught exceptions, unless class is anonymous.
884                if (tree.name != names.empty) {
885                    boolean firstConstructor = true;
886                    for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
887                        if (TreeInfo.isInitialConstructor(l.head)) {
888                            List<Type> mthrown =
889                                ((JCMethodDecl) l.head).sym.type.getThrownTypes();
890                            if (firstConstructor) {
891                                caught = mthrown;
892                                firstConstructor = false;
893                            } else {
894                                caught = chk.intersect(mthrown, caught);
895                            }
896                        }
897                    }
898                }
899
900                // process all the instance initializers
901                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
902                    if (!l.head.hasTag(METHODDEF) &&
903                        (TreeInfo.flags(l.head) & STATIC) == 0) {
904                        scan(l.head);
905                        errorUncaught();
906                    }
907                }
908
909                // in an anonymous class, add the set of thrown exceptions to
910                // the throws clause of the synthetic constructor and propagate
911                // outwards.
912                // Changing the throws clause on the fly is okay here because
913                // the anonymous constructor can't be invoked anywhere else,
914                // and its type hasn't been cached.
915                if (tree.name == names.empty) {
916                    for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
917                        if (TreeInfo.isInitialConstructor(l.head)) {
918                            JCMethodDecl mdef = (JCMethodDecl)l.head;
919                            mdef.thrown = make.Types(thrown);
920                            mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
921                        }
922                    }
923                    thrownPrev = chk.union(thrown, thrownPrev);
924                }
925
926                // process all the methods
927                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
928                    if (l.head.hasTag(METHODDEF)) {
929                        scan(l.head);
930                        errorUncaught();
931                    }
932                }
933
934                thrown = thrownPrev;
935            } finally {
936                pendingExits = pendingExitsPrev;
937                caught = caughtPrev;
938                classDef = classDefPrev;
939                lint = lintPrev;
940            }
941        }
942
943        public void visitMethodDef(JCMethodDecl tree) {
944            if (tree.body == null) return;
945
946            List<Type> caughtPrev = caught;
947            List<Type> mthrown = tree.sym.type.getThrownTypes();
948            Lint lintPrev = lint;
949
950            lint = lint.augment(tree.sym);
951
952            Assert.check(pendingExits.isEmpty());
953
954            try {
955                for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
956                    JCVariableDecl def = l.head;
957                    scan(def);
958                }
959                if (TreeInfo.isInitialConstructor(tree))
960                    caught = chk.union(caught, mthrown);
961                else if ((tree.sym.flags() & (BLOCK | STATIC)) != BLOCK)
962                    caught = mthrown;
963                // else we are in an instance initializer block;
964                // leave caught unchanged.
965
966                scan(tree.body);
967
968                List<FlowPendingExit> exits = pendingExits.toList();
969                pendingExits = new ListBuffer<>();
970                while (exits.nonEmpty()) {
971                    FlowPendingExit exit = exits.head;
972                    exits = exits.tail;
973                    if (exit.thrown == null) {
974                        Assert.check(exit.tree.hasTag(RETURN));
975                    } else {
976                        // uncaught throws will be reported later
977                        pendingExits.append(exit);
978                    }
979                }
980            } finally {
981                caught = caughtPrev;
982                lint = lintPrev;
983            }
984        }
985
986        public void visitVarDef(JCVariableDecl tree) {
987            if (tree.init != null) {
988                Lint lintPrev = lint;
989                lint = lint.augment(tree.sym);
990                try{
991                    scan(tree.init);
992                } finally {
993                    lint = lintPrev;
994                }
995            }
996        }
997
998        public void visitBlock(JCBlock tree) {
999            scan(tree.stats);
1000        }
1001
1002        public void visitDoLoop(JCDoWhileLoop tree) {
1003            ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1004            pendingExits = new ListBuffer<>();
1005            scan(tree.body);
1006            resolveContinues(tree);
1007            scan(tree.cond);
1008            resolveBreaks(tree, prevPendingExits);
1009        }
1010
1011        public void visitWhileLoop(JCWhileLoop tree) {
1012            ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1013            pendingExits = new ListBuffer<>();
1014            scan(tree.cond);
1015            scan(tree.body);
1016            resolveContinues(tree);
1017            resolveBreaks(tree, prevPendingExits);
1018        }
1019
1020        public void visitForLoop(JCForLoop tree) {
1021            ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1022            scan(tree.init);
1023            pendingExits = new ListBuffer<>();
1024            if (tree.cond != null) {
1025                scan(tree.cond);
1026            }
1027            scan(tree.body);
1028            resolveContinues(tree);
1029            scan(tree.step);
1030            resolveBreaks(tree, prevPendingExits);
1031        }
1032
1033        public void visitForeachLoop(JCEnhancedForLoop tree) {
1034            visitVarDef(tree.var);
1035            ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1036            scan(tree.expr);
1037            pendingExits = new ListBuffer<>();
1038            scan(tree.body);
1039            resolveContinues(tree);
1040            resolveBreaks(tree, prevPendingExits);
1041        }
1042
1043        public void visitLabelled(JCLabeledStatement tree) {
1044            ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1045            pendingExits = new ListBuffer<>();
1046            scan(tree.body);
1047            resolveBreaks(tree, prevPendingExits);
1048        }
1049
1050        public void visitSwitch(JCSwitch tree) {
1051            ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1052            pendingExits = new ListBuffer<>();
1053            scan(tree.selector);
1054            for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
1055                JCCase c = l.head;
1056                if (c.pat != null) {
1057                    scan(c.pat);
1058                }
1059                scan(c.stats);
1060            }
1061            resolveBreaks(tree, prevPendingExits);
1062        }
1063
1064        public void visitTry(JCTry tree) {
1065            List<Type> caughtPrev = caught;
1066            List<Type> thrownPrev = thrown;
1067            thrown = List.nil();
1068            for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1069                List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1070                        ((JCTypeUnion)l.head.param.vartype).alternatives :
1071                        List.of(l.head.param.vartype);
1072                for (JCExpression ct : subClauses) {
1073                    caught = chk.incl(ct.type, caught);
1074                }
1075            }
1076
1077            ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
1078            pendingExits = new ListBuffer<>();
1079            for (JCTree resource : tree.resources) {
1080                if (resource instanceof JCVariableDecl) {
1081                    JCVariableDecl vdecl = (JCVariableDecl) resource;
1082                    visitVarDef(vdecl);
1083                } else if (resource instanceof JCExpression) {
1084                    scan((JCExpression) resource);
1085                } else {
1086                    throw new AssertionError(tree);  // parser error
1087                }
1088            }
1089            for (JCTree resource : tree.resources) {
1090                List<Type> closeableSupertypes = resource.type.isCompound() ?
1091                    types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1092                    List.of(resource.type);
1093                for (Type sup : closeableSupertypes) {
1094                    if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1095                        Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1096                                attrEnv,
1097                                sup,
1098                                names.close,
1099                                List.<Type>nil(),
1100                                List.<Type>nil());
1101                        Type mt = types.memberType(resource.type, closeMethod);
1102                        if (closeMethod.kind == MTH) {
1103                            for (Type t : mt.getThrownTypes()) {
1104                                markThrown(resource, t);
1105                            }
1106                        }
1107                    }
1108                }
1109            }
1110            scan(tree.body);
1111            List<Type> thrownInTry = allowImprovedCatchAnalysis ?
1112                chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType)) :
1113                thrown;
1114            thrown = thrownPrev;
1115            caught = caughtPrev;
1116
1117            List<Type> caughtInTry = List.nil();
1118            for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
1119                JCVariableDecl param = l.head.param;
1120                List<JCExpression> subClauses = TreeInfo.isMultiCatch(l.head) ?
1121                        ((JCTypeUnion)l.head.param.vartype).alternatives :
1122                        List.of(l.head.param.vartype);
1123                List<Type> ctypes = List.nil();
1124                List<Type> rethrownTypes = chk.diff(thrownInTry, caughtInTry);
1125                for (JCExpression ct : subClauses) {
1126                    Type exc = ct.type;
1127                    if (exc != syms.unknownType) {
1128                        ctypes = ctypes.append(exc);
1129                        if (types.isSameType(exc, syms.objectType))
1130                            continue;
1131                        checkCaughtType(l.head.pos(), exc, thrownInTry, caughtInTry);
1132                        caughtInTry = chk.incl(exc, caughtInTry);
1133                    }
1134                }
1135                scan(param);
1136                preciseRethrowTypes.put(param.sym, chk.intersect(ctypes, rethrownTypes));
1137                scan(l.head.body);
1138                preciseRethrowTypes.remove(param.sym);
1139            }
1140            if (tree.finalizer != null) {
1141                List<Type> savedThrown = thrown;
1142                thrown = List.nil();
1143                ListBuffer<FlowPendingExit> exits = pendingExits;
1144                pendingExits = prevPendingExits;
1145                scan(tree.finalizer);
1146                if (!tree.finallyCanCompleteNormally) {
1147                    // discard exits and exceptions from try and finally
1148                    thrown = chk.union(thrown, thrownPrev);
1149                } else {
1150                    thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1151                    thrown = chk.union(thrown, savedThrown);
1152                    // FIX: this doesn't preserve source order of exits in catch
1153                    // versus finally!
1154                    while (exits.nonEmpty()) {
1155                        pendingExits.append(exits.next());
1156                    }
1157                }
1158            } else {
1159                thrown = chk.union(thrown, chk.diff(thrownInTry, caughtInTry));
1160                ListBuffer<FlowPendingExit> exits = pendingExits;
1161                pendingExits = prevPendingExits;
1162                while (exits.nonEmpty()) pendingExits.append(exits.next());
1163            }
1164        }
1165
1166        @Override
1167        public void visitIf(JCIf tree) {
1168            scan(tree.cond);
1169            scan(tree.thenpart);
1170            if (tree.elsepart != null) {
1171                scan(tree.elsepart);
1172            }
1173        }
1174
1175        void checkCaughtType(DiagnosticPosition pos, Type exc, List<Type> thrownInTry, List<Type> caughtInTry) {
1176            if (chk.subset(exc, caughtInTry)) {
1177                log.error(pos, "except.already.caught", exc);
1178            } else if (!chk.isUnchecked(pos, exc) &&
1179                    !isExceptionOrThrowable(exc) &&
1180                    !chk.intersects(exc, thrownInTry)) {
1181                log.error(pos, "except.never.thrown.in.try", exc);
1182            } else if (allowImprovedCatchAnalysis) {
1183                List<Type> catchableThrownTypes = chk.intersect(List.of(exc), thrownInTry);
1184                // 'catchableThrownTypes' cannnot possibly be empty - if 'exc' was an
1185                // unchecked exception, the result list would not be empty, as the augmented
1186                // thrown set includes { RuntimeException, Error }; if 'exc' was a checked
1187                // exception, that would have been covered in the branch above
1188                if (chk.diff(catchableThrownTypes, caughtInTry).isEmpty() &&
1189                        !isExceptionOrThrowable(exc)) {
1190                    String key = catchableThrownTypes.length() == 1 ?
1191                            "unreachable.catch" :
1192                            "unreachable.catch.1";
1193                    log.warning(pos, key, catchableThrownTypes);
1194                }
1195            }
1196        }
1197        //where
1198            private boolean isExceptionOrThrowable(Type exc) {
1199                return exc.tsym == syms.throwableType.tsym ||
1200                    exc.tsym == syms.exceptionType.tsym;
1201            }
1202
1203        public void visitBreak(JCBreak tree) {
1204            recordExit(tree, new FlowPendingExit(tree, null));
1205        }
1206
1207        public void visitContinue(JCContinue tree) {
1208            recordExit(tree, new FlowPendingExit(tree, null));
1209        }
1210
1211        public void visitReturn(JCReturn tree) {
1212            scan(tree.expr);
1213            recordExit(tree, new FlowPendingExit(tree, null));
1214        }
1215
1216        public void visitThrow(JCThrow tree) {
1217            scan(tree.expr);
1218            Symbol sym = TreeInfo.symbol(tree.expr);
1219            if (sym != null &&
1220                sym.kind == VAR &&
1221                (sym.flags() & (FINAL | EFFECTIVELY_FINAL)) != 0 &&
1222                preciseRethrowTypes.get(sym) != null &&
1223                allowImprovedRethrowAnalysis) {
1224                for (Type t : preciseRethrowTypes.get(sym)) {
1225                    markThrown(tree, t);
1226                }
1227            }
1228            else {
1229                markThrown(tree, tree.expr.type);
1230            }
1231            markDead(tree);
1232        }
1233
1234        public void visitApply(JCMethodInvocation tree) {
1235            scan(tree.meth);
1236            scan(tree.args);
1237            for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
1238                markThrown(tree, l.head);
1239        }
1240
1241        public void visitNewClass(JCNewClass tree) {
1242            scan(tree.encl);
1243            scan(tree.args);
1244           // scan(tree.def);
1245            for (List<Type> l = tree.constructorType.getThrownTypes();
1246                 l.nonEmpty();
1247                 l = l.tail) {
1248                markThrown(tree, l.head);
1249            }
1250            List<Type> caughtPrev = caught;
1251            try {
1252                // If the new class expression defines an anonymous class,
1253                // analysis of the anonymous constructor may encounter thrown
1254                // types which are unsubstituted type variables.
1255                // However, since the constructor's actual thrown types have
1256                // already been marked as thrown, it is safe to simply include
1257                // each of the constructor's formal thrown types in the set of
1258                // 'caught/declared to be thrown' types, for the duration of
1259                // the class def analysis.
1260                if (tree.def != null)
1261                    for (List<Type> l = tree.constructor.type.getThrownTypes();
1262                         l.nonEmpty();
1263                         l = l.tail) {
1264                        caught = chk.incl(l.head, caught);
1265                    }
1266                scan(tree.def);
1267            }
1268            finally {
1269                caught = caughtPrev;
1270            }
1271        }
1272
1273        @Override
1274        public void visitLambda(JCLambda tree) {
1275            if (tree.type != null &&
1276                    tree.type.isErroneous()) {
1277                return;
1278            }
1279            List<Type> prevCaught = caught;
1280            List<Type> prevThrown = thrown;
1281            ListBuffer<FlowPendingExit> prevPending = pendingExits;
1282            try {
1283                pendingExits = new ListBuffer<>();
1284                caught = tree.getDescriptorType(types).getThrownTypes();
1285                thrown = List.nil();
1286                scan(tree.body);
1287                List<FlowPendingExit> exits = pendingExits.toList();
1288                pendingExits = new ListBuffer<>();
1289                while (exits.nonEmpty()) {
1290                    FlowPendingExit exit = exits.head;
1291                    exits = exits.tail;
1292                    if (exit.thrown == null) {
1293                        Assert.check(exit.tree.hasTag(RETURN));
1294                    } else {
1295                        // uncaught throws will be reported later
1296                        pendingExits.append(exit);
1297                    }
1298                }
1299
1300                errorUncaught();
1301            } finally {
1302                pendingExits = prevPending;
1303                caught = prevCaught;
1304                thrown = prevThrown;
1305            }
1306        }
1307
1308    /**************************************************************************
1309     * main method
1310     *************************************************************************/
1311
1312        /** Perform definite assignment/unassignment analysis on a tree.
1313         */
1314        public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
1315            analyzeTree(env, env.tree, make);
1316        }
1317        public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
1318            try {
1319                attrEnv = env;
1320                Flow.this.make = make;
1321                pendingExits = new ListBuffer<>();
1322                preciseRethrowTypes = new HashMap<>();
1323                this.thrown = this.caught = null;
1324                this.classDef = null;
1325                scan(tree);
1326            } finally {
1327                pendingExits = null;
1328                Flow.this.make = null;
1329                this.thrown = this.caught = null;
1330                this.classDef = null;
1331            }
1332        }
1333    }
1334
1335    /**
1336     * Specialized pass that performs inference of thrown types for lambdas.
1337     */
1338    class LambdaFlowAnalyzer extends FlowAnalyzer {
1339        List<Type> inferredThrownTypes;
1340        boolean inLambda;
1341        @Override
1342        public void visitLambda(JCLambda tree) {
1343            if ((tree.type != null &&
1344                    tree.type.isErroneous()) || inLambda) {
1345                return;
1346            }
1347            List<Type> prevCaught = caught;
1348            List<Type> prevThrown = thrown;
1349            ListBuffer<FlowPendingExit> prevPending = pendingExits;
1350            inLambda = true;
1351            try {
1352                pendingExits = new ListBuffer<>();
1353                caught = List.of(syms.throwableType);
1354                thrown = List.nil();
1355                scan(tree.body);
1356                inferredThrownTypes = thrown;
1357            } finally {
1358                pendingExits = prevPending;
1359                caught = prevCaught;
1360                thrown = prevThrown;
1361                inLambda = false;
1362            }
1363        }
1364        @Override
1365        public void visitClassDef(JCClassDecl tree) {
1366            //skip
1367        }
1368    }
1369
1370    /**
1371     * This pass implements (i) definite assignment analysis, which ensures that
1372     * each variable is assigned when used and (ii) definite unassignment analysis,
1373     * which ensures that no final variable is assigned more than once. This visitor
1374     * depends on the results of the liveliness analyzer. This pass is also used to mark
1375     * effectively-final local variables/parameters.
1376     */
1377
1378    public abstract class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer<P>.AbstractAssignPendingExit>
1379        extends BaseAnalyzer<P> {
1380
1381        /** The set of definitely assigned variables.
1382         */
1383        protected Bits inits;
1384
1385        /** The set of definitely unassigned variables.
1386         */
1387        final Bits uninits;
1388
1389        /** The set of variables that are definitely unassigned everywhere
1390         *  in current try block. This variable is maintained lazily; it is
1391         *  updated only when something gets removed from uninits,
1392         *  typically by being assigned in reachable code.  To obtain the
1393         *  correct set of variables which are definitely unassigned
1394         *  anywhere in current try block, intersect uninitsTry and
1395         *  uninits.
1396         */
1397        final Bits uninitsTry;
1398
1399        /** When analyzing a condition, inits and uninits are null.
1400         *  Instead we have:
1401         */
1402        final Bits initsWhenTrue;
1403        final Bits initsWhenFalse;
1404        final Bits uninitsWhenTrue;
1405        final Bits uninitsWhenFalse;
1406
1407        /** A mapping from addresses to variable symbols.
1408         */
1409        protected JCVariableDecl[] vardecls;
1410
1411        /** The current class being defined.
1412         */
1413        JCClassDecl classDef;
1414
1415        /** The first variable sequence number in this class definition.
1416         */
1417        int firstadr;
1418
1419        /** The next available variable sequence number.
1420         */
1421        protected int nextadr;
1422
1423        /** The first variable sequence number in a block that can return.
1424         */
1425        protected int returnadr;
1426
1427        /** The list of unreferenced automatic resources.
1428         */
1429        WriteableScope unrefdResources;
1430
1431        /** Set when processing a loop body the second time for DU analysis. */
1432        FlowKind flowKind = FlowKind.NORMAL;
1433
1434        /** The starting position of the analysed tree */
1435        int startPos;
1436
1437        public class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
1438
1439            final Bits inits;
1440            final Bits uninits;
1441            final Bits exit_inits = new Bits(true);
1442            final Bits exit_uninits = new Bits(true);
1443
1444            public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
1445                super(tree);
1446                this.inits = inits;
1447                this.uninits = uninits;
1448                this.exit_inits.assign(inits);
1449                this.exit_uninits.assign(uninits);
1450            }
1451
1452            @Override
1453            public void resolveJump(JCTree tree) {
1454                inits.andSet(exit_inits);
1455                uninits.andSet(exit_uninits);
1456            }
1457        }
1458
1459        public AbstractAssignAnalyzer() {
1460            this.inits = new Bits();
1461            uninits = new Bits();
1462            uninitsTry = new Bits();
1463            initsWhenTrue = new Bits(true);
1464            initsWhenFalse = new Bits(true);
1465            uninitsWhenTrue = new Bits(true);
1466            uninitsWhenFalse = new Bits(true);
1467        }
1468
1469        private boolean isInitialConstructor = false;
1470
1471        @Override
1472        protected void markDead(JCTree tree) {
1473            if (!isInitialConstructor) {
1474                inits.inclRange(returnadr, nextadr);
1475            } else {
1476                for (int address = returnadr; address < nextadr; address++) {
1477                    if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
1478                        inits.incl(address);
1479                    }
1480                }
1481            }
1482            uninits.inclRange(returnadr, nextadr);
1483        }
1484
1485        /*-------------- Processing variables ----------------------*/
1486
1487        /** Do we need to track init/uninit state of this symbol?
1488         *  I.e. is symbol either a local or a blank final variable?
1489         */
1490        protected boolean trackable(VarSymbol sym) {
1491            return
1492                sym.pos >= startPos &&
1493                ((sym.owner.kind == MTH ||
1494                isFinalUninitializedField(sym)));
1495        }
1496
1497        boolean isFinalUninitializedField(VarSymbol sym) {
1498            return sym.owner.kind == TYP &&
1499                   ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
1500                   classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
1501        }
1502
1503        boolean isFinalUninitializedStaticField(VarSymbol sym) {
1504            return isFinalUninitializedField(sym) && sym.isStatic();
1505        }
1506
1507        /** Initialize new trackable variable by setting its address field
1508         *  to the next available sequence number and entering it under that
1509         *  index into the vars array.
1510         */
1511        void newVar(JCVariableDecl varDecl) {
1512            VarSymbol sym = varDecl.sym;
1513            vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1514            if ((sym.flags() & FINAL) == 0) {
1515                sym.flags_field |= EFFECTIVELY_FINAL;
1516            }
1517            sym.adr = nextadr;
1518            vardecls[nextadr] = varDecl;
1519            exclVarFromInits(varDecl, nextadr);
1520            uninits.incl(nextadr);
1521            nextadr++;
1522        }
1523
1524        protected void exclVarFromInits(JCTree tree, int adr) {
1525            inits.excl(adr);
1526        }
1527
1528        protected void assignToInits(JCTree tree, Bits bits) {
1529            inits.assign(bits);
1530        }
1531
1532        protected void andSetInits(JCTree tree, Bits bits) {
1533            inits.andSet(bits);
1534        }
1535
1536        protected void orSetInits(JCTree tree, Bits bits) {
1537            inits.orSet(bits);
1538        }
1539
1540        /** Record an initialization of a trackable variable.
1541         */
1542        void letInit(DiagnosticPosition pos, VarSymbol sym) {
1543            if (sym.adr >= firstadr && trackable(sym)) {
1544                if (uninits.isMember(sym.adr)) {
1545                    uninit(sym);
1546                }
1547                inits.incl(sym.adr);
1548            }
1549        }
1550        //where
1551            void uninit(VarSymbol sym) {
1552                if (!inits.isMember(sym.adr)) {
1553                    // reachable assignment
1554                    uninits.excl(sym.adr);
1555                    uninitsTry.excl(sym.adr);
1556                } else {
1557                    //log.rawWarning(pos, "unreachable assignment");//DEBUG
1558                    uninits.excl(sym.adr);
1559                }
1560            }
1561
1562        /** If tree is either a simple name or of the form this.name or
1563         *  C.this.name, and tree represents a trackable variable,
1564         *  record an initialization of the variable.
1565         */
1566        void letInit(JCTree tree) {
1567            tree = TreeInfo.skipParens(tree);
1568            if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1569                Symbol sym = TreeInfo.symbol(tree);
1570                if (sym.kind == VAR) {
1571                    letInit(tree.pos(), (VarSymbol)sym);
1572                }
1573            }
1574        }
1575
1576        /** Check that trackable variable is initialized.
1577         */
1578        void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1579            checkInit(pos, sym, "var.might.not.have.been.initialized");
1580        }
1581
1582        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}
1583
1584        /** Utility method to reset several Bits instances.
1585         */
1586        private void resetBits(Bits... bits) {
1587            for (Bits b : bits) {
1588                b.reset();
1589            }
1590        }
1591
1592        /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1593         */
1594        void split(boolean setToNull) {
1595            initsWhenFalse.assign(inits);
1596            uninitsWhenFalse.assign(uninits);
1597            initsWhenTrue.assign(inits);
1598            uninitsWhenTrue.assign(uninits);
1599            if (setToNull) {
1600                resetBits(inits, uninits);
1601            }
1602        }
1603
1604        /** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
1605         */
1606        protected void merge(JCTree tree) {
1607            inits.assign(initsWhenFalse.andSet(initsWhenTrue));
1608            uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
1609        }
1610
1611    /* ************************************************************************
1612     * Visitor methods for statements and definitions
1613     *************************************************************************/
1614
1615        /** Analyze an expression. Make sure to set (un)inits rather than
1616         *  (un)initsWhenTrue(WhenFalse) on exit.
1617         */
1618        void scanExpr(JCTree tree) {
1619            if (tree != null) {
1620                scan(tree);
1621                if (inits.isReset()) {
1622                    merge(tree);
1623                }
1624            }
1625        }
1626
1627        /** Analyze a list of expressions.
1628         */
1629        void scanExprs(List<? extends JCExpression> trees) {
1630            if (trees != null)
1631                for (List<? extends JCExpression> l = trees; l.nonEmpty(); l = l.tail)
1632                    scanExpr(l.head);
1633        }
1634
1635        /** Analyze a condition. Make sure to set (un)initsWhenTrue(WhenFalse)
1636         *  rather than (un)inits on exit.
1637         */
1638        void scanCond(JCTree tree) {
1639            if (tree.type.isFalse()) {
1640                if (inits.isReset()) merge(tree);
1641                initsWhenTrue.assign(inits);
1642                initsWhenTrue.inclRange(firstadr, nextadr);
1643                uninitsWhenTrue.assign(uninits);
1644                uninitsWhenTrue.inclRange(firstadr, nextadr);
1645                initsWhenFalse.assign(inits);
1646                uninitsWhenFalse.assign(uninits);
1647            } else if (tree.type.isTrue()) {
1648                if (inits.isReset()) merge(tree);
1649                initsWhenFalse.assign(inits);
1650                initsWhenFalse.inclRange(firstadr, nextadr);
1651                uninitsWhenFalse.assign(uninits);
1652                uninitsWhenFalse.inclRange(firstadr, nextadr);
1653                initsWhenTrue.assign(inits);
1654                uninitsWhenTrue.assign(uninits);
1655            } else {
1656                scan(tree);
1657                if (!inits.isReset())
1658                    split(tree.type != syms.unknownType);
1659            }
1660            if (tree.type != syms.unknownType) {
1661                resetBits(inits, uninits);
1662            }
1663        }
1664
1665        /* ------------ Visitor methods for various sorts of trees -------------*/
1666
1667        @Override
1668        public void visitClassDef(JCClassDecl tree) {
1669            if (tree.sym == null) {
1670                return;
1671            }
1672
1673            JCClassDecl classDefPrev = classDef;
1674            int firstadrPrev = firstadr;
1675            int nextadrPrev = nextadr;
1676            ListBuffer<P> pendingExitsPrev = pendingExits;
1677
1678            pendingExits = new ListBuffer<>();
1679            if (tree.name != names.empty) {
1680                firstadr = nextadr;
1681            }
1682            classDef = tree;
1683            try {
1684                // define all the static fields
1685                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1686                    if (l.head.hasTag(VARDEF)) {
1687                        JCVariableDecl def = (JCVariableDecl)l.head;
1688                        if ((def.mods.flags & STATIC) != 0) {
1689                            VarSymbol sym = def.sym;
1690                            if (trackable(sym)) {
1691                                newVar(def);
1692                            }
1693                        }
1694                    }
1695                }
1696
1697                // process all the static initializers
1698                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1699                    if (!l.head.hasTag(METHODDEF) &&
1700                        (TreeInfo.flags(l.head) & STATIC) != 0) {
1701                        scan(l.head);
1702                    }
1703                }
1704
1705                // define all the instance fields
1706                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1707                    if (l.head.hasTag(VARDEF)) {
1708                        JCVariableDecl def = (JCVariableDecl)l.head;
1709                        if ((def.mods.flags & STATIC) == 0) {
1710                            VarSymbol sym = def.sym;
1711                            if (trackable(sym)) {
1712                                newVar(def);
1713                            }
1714                        }
1715                    }
1716                }
1717
1718                // process all the instance initializers
1719                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1720                    if (!l.head.hasTag(METHODDEF) &&
1721                        (TreeInfo.flags(l.head) & STATIC) == 0) {
1722                        scan(l.head);
1723                    }
1724                }
1725
1726                // process all the methods
1727                for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1728                    if (l.head.hasTag(METHODDEF)) {
1729                        scan(l.head);
1730                    }
1731                }
1732            } finally {
1733                pendingExits = pendingExitsPrev;
1734                nextadr = nextadrPrev;
1735                firstadr = firstadrPrev;
1736                classDef = classDefPrev;
1737            }
1738        }
1739
1740        @Override
1741        public void visitMethodDef(JCMethodDecl tree) {
1742            if (tree.body == null) {
1743                return;
1744            }
1745            /*  Ignore synthetic methods, except for translated lambda methods.
1746             */
1747            if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
1748                return;
1749            }
1750
1751            final Bits initsPrev = new Bits(inits);
1752            final Bits uninitsPrev = new Bits(uninits);
1753            int nextadrPrev = nextadr;
1754            int firstadrPrev = firstadr;
1755            int returnadrPrev = returnadr;
1756
1757            Assert.check(pendingExits.isEmpty());
1758            boolean lastInitialConstructor = isInitialConstructor;
1759            try {
1760                isInitialConstructor = TreeInfo.isInitialConstructor(tree);
1761
1762                if (!isInitialConstructor) {
1763                    firstadr = nextadr;
1764                }
1765                for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1766                    JCVariableDecl def = l.head;
1767                    scan(def);
1768                    Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
1769                    /*  If we are executing the code from Gen, then there can be
1770                     *  synthetic or mandated variables, ignore them.
1771                     */
1772                    initParam(def);
1773                }
1774                // else we are in an instance initializer block;
1775                // leave caught unchanged.
1776                scan(tree.body);
1777
1778                if (isInitialConstructor) {
1779                    boolean isSynthesized = (tree.sym.flags() &
1780                                             GENERATEDCONSTR) != 0;
1781                    for (int i = firstadr; i < nextadr; i++) {
1782                        JCVariableDecl vardecl = vardecls[i];
1783                        VarSymbol var = vardecl.sym;
1784                        if (var.owner == classDef.sym) {
1785                            // choose the diagnostic position based on whether
1786                            // the ctor is default(synthesized) or not
1787                            if (isSynthesized) {
1788                                checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
1789                                    var, "var.not.initialized.in.default.constructor");
1790                            } else {
1791                                checkInit(TreeInfo.diagEndPos(tree.body), var);
1792                            }
1793                        }
1794                    }
1795                }
1796                List<P> exits = pendingExits.toList();
1797                pendingExits = new ListBuffer<>();
1798                while (exits.nonEmpty()) {
1799                    P exit = exits.head;
1800                    exits = exits.tail;
1801                    Assert.check(exit.tree.hasTag(RETURN), exit.tree);
1802                    if (isInitialConstructor) {
1803                        assignToInits(exit.tree, exit.exit_inits);
1804                        for (int i = firstadr; i < nextadr; i++) {
1805                            checkInit(exit.tree.pos(), vardecls[i].sym);
1806                        }
1807                    }
1808                }
1809            } finally {
1810                assignToInits(tree, initsPrev);
1811                uninits.assign(uninitsPrev);
1812                nextadr = nextadrPrev;
1813                firstadr = firstadrPrev;
1814                returnadr = returnadrPrev;
1815                isInitialConstructor = lastInitialConstructor;
1816            }
1817        }
1818
1819        protected void initParam(JCVariableDecl def) {
1820            inits.incl(def.sym.adr);
1821            uninits.excl(def.sym.adr);
1822            }
1823
1824        public void visitVarDef(JCVariableDecl tree) {
1825            boolean track = trackable(tree.sym);
1826            if (track && tree.sym.owner.kind == MTH) {
1827                newVar(tree);
1828            }
1829            if (tree.init != null) {
1830                scanExpr(tree.init);
1831                if (track) {
1832                    letInit(tree.pos(), tree.sym);
1833                }
1834            }
1835        }
1836
1837        public void visitBlock(JCBlock tree) {
1838            int nextadrPrev = nextadr;
1839            scan(tree.stats);
1840            nextadr = nextadrPrev;
1841        }
1842
1843        int getLogNumberOfErrors() {
1844            return 0;
1845        }
1846
1847        public void visitDoLoop(JCDoWhileLoop tree) {
1848            ListBuffer<P> prevPendingExits = pendingExits;
1849            FlowKind prevFlowKind = flowKind;
1850            flowKind = FlowKind.NORMAL;
1851            final Bits initsSkip = new Bits(true);
1852            final Bits uninitsSkip = new Bits(true);
1853            pendingExits = new ListBuffer<>();
1854            int prevErrors = getLogNumberOfErrors();
1855            do {
1856                final Bits uninitsEntry = new Bits(uninits);
1857                uninitsEntry.excludeFrom(nextadr);
1858                scan(tree.body);
1859                resolveContinues(tree);
1860                scanCond(tree.cond);
1861                if (!flowKind.isFinal()) {
1862                    initsSkip.assign(initsWhenFalse);
1863                    uninitsSkip.assign(uninitsWhenFalse);
1864                }
1865                if (getLogNumberOfErrors() !=  prevErrors ||
1866                    flowKind.isFinal() ||
1867                    new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
1868                    break;
1869                assignToInits(tree.cond, initsWhenTrue);
1870                uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
1871                flowKind = FlowKind.SPECULATIVE_LOOP;
1872            } while (true);
1873            flowKind = prevFlowKind;
1874            assignToInits(tree, initsSkip);
1875            uninits.assign(uninitsSkip);
1876            resolveBreaks(tree, prevPendingExits);
1877        }
1878
1879        public void visitWhileLoop(JCWhileLoop tree) {
1880            ListBuffer<P> prevPendingExits = pendingExits;
1881            FlowKind prevFlowKind = flowKind;
1882            flowKind = FlowKind.NORMAL;
1883            final Bits initsSkip = new Bits(true);
1884            final Bits uninitsSkip = new Bits(true);
1885            pendingExits = new ListBuffer<>();
1886            int prevErrors = getLogNumberOfErrors();
1887            final Bits uninitsEntry = new Bits(uninits);
1888            uninitsEntry.excludeFrom(nextadr);
1889            do {
1890                scanCond(tree.cond);
1891                if (!flowKind.isFinal()) {
1892                    initsSkip.assign(initsWhenFalse) ;
1893                    uninitsSkip.assign(uninitsWhenFalse);
1894                }
1895                assignToInits(tree, initsWhenTrue);
1896                uninits.assign(uninitsWhenTrue);
1897                scan(tree.body);
1898                resolveContinues(tree);
1899                if (getLogNumberOfErrors() != prevErrors ||
1900                    flowKind.isFinal() ||
1901                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
1902                    break;
1903                }
1904                uninits.assign(uninitsEntry.andSet(uninits));
1905                flowKind = FlowKind.SPECULATIVE_LOOP;
1906            } while (true);
1907            flowKind = prevFlowKind;
1908            //a variable is DA/DU after the while statement, if it's DA/DU assuming the
1909            //branch is not taken AND if it's DA/DU before any break statement
1910            assignToInits(tree.body, initsSkip);
1911            uninits.assign(uninitsSkip);
1912            resolveBreaks(tree, prevPendingExits);
1913        }
1914
1915        public void visitForLoop(JCForLoop tree) {
1916            ListBuffer<P> prevPendingExits = pendingExits;
1917            FlowKind prevFlowKind = flowKind;
1918            flowKind = FlowKind.NORMAL;
1919            int nextadrPrev = nextadr;
1920            scan(tree.init);
1921            final Bits initsSkip = new Bits(true);
1922            final Bits uninitsSkip = new Bits(true);
1923            pendingExits = new ListBuffer<>();
1924            int prevErrors = getLogNumberOfErrors();
1925            do {
1926                final Bits uninitsEntry = new Bits(uninits);
1927                uninitsEntry.excludeFrom(nextadr);
1928                if (tree.cond != null) {
1929                    scanCond(tree.cond);
1930                    if (!flowKind.isFinal()) {
1931                        initsSkip.assign(initsWhenFalse);
1932                        uninitsSkip.assign(uninitsWhenFalse);
1933                    }
1934                    assignToInits(tree.body, initsWhenTrue);
1935                    uninits.assign(uninitsWhenTrue);
1936                } else if (!flowKind.isFinal()) {
1937                    initsSkip.assign(inits);
1938                    initsSkip.inclRange(firstadr, nextadr);
1939                    uninitsSkip.assign(uninits);
1940                    uninitsSkip.inclRange(firstadr, nextadr);
1941                }
1942                scan(tree.body);
1943                resolveContinues(tree);
1944                scan(tree.step);
1945                if (getLogNumberOfErrors() != prevErrors ||
1946                    flowKind.isFinal() ||
1947                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
1948                    break;
1949                uninits.assign(uninitsEntry.andSet(uninits));
1950                flowKind = FlowKind.SPECULATIVE_LOOP;
1951            } while (true);
1952            flowKind = prevFlowKind;
1953            //a variable is DA/DU after a for loop, if it's DA/DU assuming the
1954            //branch is not taken AND if it's DA/DU before any break statement
1955            assignToInits(tree.body, initsSkip);
1956            uninits.assign(uninitsSkip);
1957            resolveBreaks(tree, prevPendingExits);
1958            nextadr = nextadrPrev;
1959        }
1960
1961        public void visitForeachLoop(JCEnhancedForLoop tree) {
1962            visitVarDef(tree.var);
1963
1964            ListBuffer<P> prevPendingExits = pendingExits;
1965            FlowKind prevFlowKind = flowKind;
1966            flowKind = FlowKind.NORMAL;
1967            int nextadrPrev = nextadr;
1968            scan(tree.expr);
1969            final Bits initsStart = new Bits(inits);
1970            final Bits uninitsStart = new Bits(uninits);
1971
1972            letInit(tree.pos(), tree.var.sym);
1973            pendingExits = new ListBuffer<>();
1974            int prevErrors = getLogNumberOfErrors();
1975            do {
1976                final Bits uninitsEntry = new Bits(uninits);
1977                uninitsEntry.excludeFrom(nextadr);
1978                scan(tree.body);
1979                resolveContinues(tree);
1980                if (getLogNumberOfErrors() != prevErrors ||
1981                    flowKind.isFinal() ||
1982                    new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
1983                    break;
1984                uninits.assign(uninitsEntry.andSet(uninits));
1985                flowKind = FlowKind.SPECULATIVE_LOOP;
1986            } while (true);
1987            flowKind = prevFlowKind;
1988            assignToInits(tree.body, initsStart);
1989            uninits.assign(uninitsStart.andSet(uninits));
1990            resolveBreaks(tree, prevPendingExits);
1991            nextadr = nextadrPrev;
1992        }
1993
1994        public void visitLabelled(JCLabeledStatement tree) {
1995            ListBuffer<P> prevPendingExits = pendingExits;
1996            pendingExits = new ListBuffer<>();
1997            scan(tree.body);
1998            resolveBreaks(tree, prevPendingExits);
1999        }
2000
2001        public void visitSwitch(JCSwitch tree) {
2002            ListBuffer<P> prevPendingExits = pendingExits;
2003            pendingExits = new ListBuffer<>();
2004            int nextadrPrev = nextadr;
2005            scanExpr(tree.selector);
2006            final Bits initsSwitch = new Bits(inits);
2007            final Bits uninitsSwitch = new Bits(uninits);
2008            boolean hasDefault = false;
2009            for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
2010                assignToInits(l.head, initsSwitch);
2011                uninits.assign(uninits.andSet(uninitsSwitch));
2012                JCCase c = l.head;
2013                if (c.pat == null) {
2014                    hasDefault = true;
2015                } else {
2016                    scanExpr(c.pat);
2017                }
2018                if (hasDefault) {
2019                    assignToInits(null, initsSwitch);
2020                    uninits.assign(uninits.andSet(uninitsSwitch));
2021                }
2022                scan(c.stats);
2023                addVars(c.stats, initsSwitch, uninitsSwitch);
2024                if (!hasDefault) {
2025                    assignToInits(l.head.stats.last(), initsSwitch);
2026                    uninits.assign(uninits.andSet(uninitsSwitch));
2027                }
2028                // Warn about fall-through if lint switch fallthrough enabled.
2029            }
2030            if (!hasDefault) {
2031                andSetInits(null, initsSwitch);
2032            }
2033            resolveBreaks(tree, prevPendingExits);
2034            nextadr = nextadrPrev;
2035        }
2036        // where
2037            /** Add any variables defined in stats to inits and uninits. */
2038            private void addVars(List<JCStatement> stats, final Bits inits,
2039                                        final Bits uninits) {
2040                for (;stats.nonEmpty(); stats = stats.tail) {
2041                    JCTree stat = stats.head;
2042                    if (stat.hasTag(VARDEF)) {
2043                        int adr = ((JCVariableDecl) stat).sym.adr;
2044                        inits.excl(adr);
2045                        uninits.incl(adr);
2046                    }
2047                }
2048            }
2049
2050        boolean isEnabled(Lint.LintCategory lc) {
2051            return false;
2052        }
2053
2054        void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {}
2055
2056        public void visitTry(JCTry tree) {
2057            ListBuffer<JCVariableDecl> resourceVarDecls = new ListBuffer<>();
2058            final Bits uninitsTryPrev = new Bits(uninitsTry);
2059            ListBuffer<P> prevPendingExits = pendingExits;
2060            pendingExits = new ListBuffer<>();
2061            final Bits initsTry = new Bits(inits);
2062            uninitsTry.assign(uninits);
2063            for (JCTree resource : tree.resources) {
2064                if (resource instanceof JCVariableDecl) {
2065                    JCVariableDecl vdecl = (JCVariableDecl) resource;
2066                    visitVarDef(vdecl);
2067                    unrefdResources.enter(vdecl.sym);
2068                    resourceVarDecls.append(vdecl);
2069                } else if (resource instanceof JCExpression) {
2070                    scanExpr((JCExpression) resource);
2071                } else {
2072                    throw new AssertionError(tree);  // parser error
2073                }
2074            }
2075            scan(tree.body);
2076            uninitsTry.andSet(uninits);
2077            final Bits initsEnd = new Bits(inits);
2078            final Bits uninitsEnd = new Bits(uninits);
2079            int nextadrCatch = nextadr;
2080
2081            if (!resourceVarDecls.isEmpty() &&
2082                    isEnabled(Lint.LintCategory.TRY)) {
2083                for (JCVariableDecl resVar : resourceVarDecls) {
2084                    if (unrefdResources.includes(resVar.sym)) {
2085                        reportWarning(Lint.LintCategory.TRY, resVar.pos(),
2086                                    "try.resource.not.referenced", resVar.sym);
2087                        unrefdResources.remove(resVar.sym);
2088                    }
2089                }
2090            }
2091
2092            /*  The analysis of each catch should be independent.
2093             *  Each one should have the same initial values of inits and
2094             *  uninits.
2095             */
2096            final Bits initsCatchPrev = new Bits(initsTry);
2097            final Bits uninitsCatchPrev = new Bits(uninitsTry);
2098
2099            for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
2100                JCVariableDecl param = l.head.param;
2101                assignToInits(tree.body, initsCatchPrev);
2102                uninits.assign(uninitsCatchPrev);
2103                scan(param);
2104                /* If this is a TWR and we are executing the code from Gen,
2105                 * then there can be synthetic variables, ignore them.
2106                 */
2107                initParam(param);
2108                scan(l.head.body);
2109                initsEnd.andSet(inits);
2110                uninitsEnd.andSet(uninits);
2111                nextadr = nextadrCatch;
2112            }
2113            if (tree.finalizer != null) {
2114                assignToInits(tree.finalizer, initsTry);
2115                uninits.assign(uninitsTry);
2116                ListBuffer<P> exits = pendingExits;
2117                pendingExits = prevPendingExits;
2118                scan(tree.finalizer);
2119                if (!tree.finallyCanCompleteNormally) {
2120                    // discard exits and exceptions from try and finally
2121                } else {
2122                    uninits.andSet(uninitsEnd);
2123                    // FIX: this doesn't preserve source order of exits in catch
2124                    // versus finally!
2125                    while (exits.nonEmpty()) {
2126                        P exit = exits.next();
2127                        if (exit.exit_inits != null) {
2128                            exit.exit_inits.orSet(inits);
2129                            exit.exit_uninits.andSet(uninits);
2130                        }
2131                        pendingExits.append(exit);
2132                    }
2133                    orSetInits(tree, initsEnd);
2134                }
2135            } else {
2136                assignToInits(tree, initsEnd);
2137                uninits.assign(uninitsEnd);
2138                ListBuffer<P> exits = pendingExits;
2139                pendingExits = prevPendingExits;
2140                while (exits.nonEmpty()) pendingExits.append(exits.next());
2141            }
2142            uninitsTry.andSet(uninitsTryPrev).andSet(uninits);
2143        }
2144
2145        public void visitConditional(JCConditional tree) {
2146            scanCond(tree.cond);
2147            final Bits initsBeforeElse = new Bits(initsWhenFalse);
2148            final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
2149            assignToInits(tree.cond, initsWhenTrue);
2150            uninits.assign(uninitsWhenTrue);
2151            if (tree.truepart.type.hasTag(BOOLEAN) &&
2152                tree.falsepart.type.hasTag(BOOLEAN)) {
2153                // if b and c are boolean valued, then
2154                // v is (un)assigned after a?b:c when true iff
2155                //    v is (un)assigned after b when true and
2156                //    v is (un)assigned after c when true
2157                scanCond(tree.truepart);
2158                final Bits initsAfterThenWhenTrue = new Bits(initsWhenTrue);
2159                final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
2160                final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
2161                final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
2162                assignToInits(tree.truepart, initsBeforeElse);
2163                uninits.assign(uninitsBeforeElse);
2164                scanCond(tree.falsepart);
2165                initsWhenTrue.andSet(initsAfterThenWhenTrue);
2166                initsWhenFalse.andSet(initsAfterThenWhenFalse);
2167                uninitsWhenTrue.andSet(uninitsAfterThenWhenTrue);
2168                uninitsWhenFalse.andSet(uninitsAfterThenWhenFalse);
2169            } else {
2170                scanExpr(tree.truepart);
2171                final Bits initsAfterThen = new Bits(inits);
2172                final Bits uninitsAfterThen = new Bits(uninits);
2173                assignToInits(tree.truepart, initsBeforeElse);
2174                uninits.assign(uninitsBeforeElse);
2175                scanExpr(tree.falsepart);
2176                andSetInits(tree.falsepart, initsAfterThen);
2177                uninits.andSet(uninitsAfterThen);
2178            }
2179        }
2180
2181        public void visitIf(JCIf tree) {
2182            scanCond(tree.cond);
2183            final Bits initsBeforeElse = new Bits(initsWhenFalse);
2184            final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
2185            assignToInits(tree.cond, initsWhenTrue);
2186            uninits.assign(uninitsWhenTrue);
2187            scan(tree.thenpart);
2188            if (tree.elsepart != null) {
2189                final Bits initsAfterThen = new Bits(inits);
2190                final Bits uninitsAfterThen = new Bits(uninits);
2191                assignToInits(tree.thenpart, initsBeforeElse);
2192                uninits.assign(uninitsBeforeElse);
2193                scan(tree.elsepart);
2194                andSetInits(tree.elsepart, initsAfterThen);
2195                uninits.andSet(uninitsAfterThen);
2196            } else {
2197                andSetInits(tree.thenpart, initsBeforeElse);
2198                uninits.andSet(uninitsBeforeElse);
2199            }
2200        }
2201
2202        protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
2203            return null;
2204        }
2205
2206        @Override
2207        public void visitBreak(JCBreak tree) {
2208            recordExit(tree, createNewPendingExit(tree, inits, uninits));
2209        }
2210
2211        @Override
2212        public void visitContinue(JCContinue tree) {
2213            recordExit(tree, createNewPendingExit(tree, inits, uninits));
2214        }
2215
2216        @Override
2217        public void visitReturn(JCReturn tree) {
2218            scanExpr(tree.expr);
2219            recordExit(tree, createNewPendingExit(tree, inits, uninits));
2220        }
2221
2222        public void visitThrow(JCThrow tree) {
2223            scanExpr(tree.expr);
2224            markDead(tree.expr);
2225        }
2226
2227        public void visitApply(JCMethodInvocation tree) {
2228            scanExpr(tree.meth);
2229            scanExprs(tree.args);
2230        }
2231
2232        public void visitNewClass(JCNewClass tree) {
2233            scanExpr(tree.encl);
2234            scanExprs(tree.args);
2235            scan(tree.def);
2236        }
2237
2238        @Override
2239        public void visitLambda(JCLambda tree) {
2240            final Bits prevUninits = new Bits(uninits);
2241            final Bits prevInits = new Bits(inits);
2242            int returnadrPrev = returnadr;
2243            ListBuffer<P> prevPending = pendingExits;
2244            try {
2245                returnadr = nextadr;
2246                pendingExits = new ListBuffer<>();
2247                for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2248                    JCVariableDecl def = l.head;
2249                    scan(def);
2250                    inits.incl(def.sym.adr);
2251                    uninits.excl(def.sym.adr);
2252                }
2253                if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
2254                    scanExpr(tree.body);
2255                } else {
2256                    scan(tree.body);
2257                }
2258            }
2259            finally {
2260                returnadr = returnadrPrev;
2261                uninits.assign(prevUninits);
2262                assignToInits(tree, prevInits);
2263                pendingExits = prevPending;
2264            }
2265        }
2266
2267        public void visitNewArray(JCNewArray tree) {
2268            scanExprs(tree.dims);
2269            scanExprs(tree.elems);
2270        }
2271
2272        public void visitAssert(JCAssert tree) {
2273            final Bits initsExit = new Bits(inits);
2274            final Bits uninitsExit = new Bits(uninits);
2275            scanCond(tree.cond);
2276            uninitsExit.andSet(uninitsWhenTrue);
2277            if (tree.detail != null) {
2278                assignToInits(tree, initsWhenFalse);
2279                uninits.assign(uninitsWhenFalse);
2280                scanExpr(tree.detail);
2281            }
2282            assignToInits(tree, initsExit);
2283            uninits.assign(uninitsExit);
2284        }
2285
2286        public void visitAssign(JCAssign tree) {
2287            JCTree lhs = TreeInfo.skipParens(tree.lhs);
2288            if (!isIdentOrThisDotIdent(lhs))
2289                scanExpr(lhs);
2290            scanExpr(tree.rhs);
2291            letInit(lhs);
2292        }
2293        private boolean isIdentOrThisDotIdent(JCTree lhs) {
2294            if (lhs.hasTag(IDENT))
2295                return true;
2296            if (!lhs.hasTag(SELECT))
2297                return false;
2298
2299            JCFieldAccess fa = (JCFieldAccess)lhs;
2300            return fa.selected.hasTag(IDENT) &&
2301                   ((JCIdent)fa.selected).name == names._this;
2302        }
2303
2304        // check fields accessed through this.<field> are definitely
2305        // assigned before reading their value
2306        public void visitSelect(JCFieldAccess tree) {
2307            super.visitSelect(tree);
2308            if (enforceThisDotInit &&
2309                tree.selected.hasTag(IDENT) &&
2310                ((JCIdent)tree.selected).name == names._this &&
2311                tree.sym.kind == VAR)
2312            {
2313                checkInit(tree.pos(), (VarSymbol)tree.sym);
2314            }
2315        }
2316
2317        public void visitAssignop(JCAssignOp tree) {
2318            scanExpr(tree.lhs);
2319            scanExpr(tree.rhs);
2320            letInit(tree.lhs);
2321        }
2322
2323        public void visitUnary(JCUnary tree) {
2324            switch (tree.getTag()) {
2325            case NOT:
2326                scanCond(tree.arg);
2327                final Bits t = new Bits(initsWhenFalse);
2328                initsWhenFalse.assign(initsWhenTrue);
2329                initsWhenTrue.assign(t);
2330                t.assign(uninitsWhenFalse);
2331                uninitsWhenFalse.assign(uninitsWhenTrue);
2332                uninitsWhenTrue.assign(t);
2333                break;
2334            case PREINC: case POSTINC:
2335            case PREDEC: case POSTDEC:
2336                scanExpr(tree.arg);
2337                letInit(tree.arg);
2338                break;
2339            default:
2340                scanExpr(tree.arg);
2341            }
2342        }
2343
2344        public void visitBinary(JCBinary tree) {
2345            switch (tree.getTag()) {
2346            case AND:
2347                scanCond(tree.lhs);
2348                final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
2349                final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
2350                assignToInits(tree.lhs, initsWhenTrue);
2351                uninits.assign(uninitsWhenTrue);
2352                scanCond(tree.rhs);
2353                initsWhenFalse.andSet(initsWhenFalseLeft);
2354                uninitsWhenFalse.andSet(uninitsWhenFalseLeft);
2355                break;
2356            case OR:
2357                scanCond(tree.lhs);
2358                final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
2359                final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
2360                assignToInits(tree.lhs, initsWhenFalse);
2361                uninits.assign(uninitsWhenFalse);
2362                scanCond(tree.rhs);
2363                initsWhenTrue.andSet(initsWhenTrueLeft);
2364                uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
2365                break;
2366            default:
2367                scanExpr(tree.lhs);
2368                scanExpr(tree.rhs);
2369            }
2370        }
2371
2372        public void visitIdent(JCIdent tree) {
2373            if (tree.sym.kind == VAR) {
2374                checkInit(tree.pos(), (VarSymbol)tree.sym);
2375                referenced(tree.sym);
2376            }
2377        }
2378
2379        void referenced(Symbol sym) {
2380            unrefdResources.remove(sym);
2381        }
2382
2383        public void visitAnnotatedType(JCAnnotatedType tree) {
2384            // annotations don't get scanned
2385            tree.underlyingType.accept(this);
2386        }
2387
2388    /**************************************************************************
2389     * main method
2390     *************************************************************************/
2391
2392        /** Perform definite assignment/unassignment analysis on a tree.
2393         */
2394        public void analyzeTree(Env<?> env) {
2395            analyzeTree(env, env.tree);
2396         }
2397
2398        public void analyzeTree(Env<?> env, JCTree tree) {
2399            try {
2400                startPos = tree.pos().getStartPosition();
2401
2402                if (vardecls == null)
2403                    vardecls = new JCVariableDecl[32];
2404                else
2405                    for (int i=0; i<vardecls.length; i++)
2406                        vardecls[i] = null;
2407                firstadr = 0;
2408                nextadr = 0;
2409                pendingExits = new ListBuffer<>();
2410                this.classDef = null;
2411                unrefdResources = WriteableScope.create(env.enclClass.sym);
2412                scan(tree);
2413            } finally {
2414                // note that recursive invocations of this method fail hard
2415                startPos = -1;
2416                resetBits(inits, uninits, uninitsTry, initsWhenTrue,
2417                        initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
2418                if (vardecls != null) {
2419                    for (int i=0; i<vardecls.length; i++)
2420                        vardecls[i] = null;
2421                }
2422                firstadr = 0;
2423                nextadr = 0;
2424                pendingExits = null;
2425                this.classDef = null;
2426                unrefdResources = null;
2427            }
2428        }
2429    }
2430
2431    public class AssignAnalyzer extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> {
2432
2433        public class AssignPendingExit extends AbstractAssignAnalyzer<AssignPendingExit>.AbstractAssignPendingExit {
2434
2435            public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2436                super(tree, inits, uninits);
2437            }
2438        }
2439
2440        @Override
2441        protected AssignPendingExit createNewPendingExit(JCTree tree,
2442            Bits inits, Bits uninits) {
2443            return new AssignPendingExit(tree, inits, uninits);
2444        }
2445
2446        /** Record an initialization of a trackable variable.
2447         */
2448        @Override
2449        void letInit(DiagnosticPosition pos, VarSymbol sym) {
2450            if (sym.adr >= firstadr && trackable(sym)) {
2451                if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
2452                    if (!uninits.isMember(sym.adr)) {
2453                        //assignment targeting an effectively final variable
2454                        //makes the variable lose its status of effectively final
2455                        //if the variable is _not_ definitively unassigned
2456                        sym.flags_field &= ~EFFECTIVELY_FINAL;
2457                    } else {
2458                        uninit(sym);
2459                    }
2460                }
2461                else if ((sym.flags() & FINAL) != 0) {
2462                    if ((sym.flags() & PARAMETER) != 0) {
2463                        if ((sym.flags() & UNION) != 0) { //multi-catch parameter
2464                            log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
2465                        }
2466                        else {
2467                            log.error(pos, "final.parameter.may.not.be.assigned",
2468                                  sym);
2469                        }
2470                    } else if (!uninits.isMember(sym.adr)) {
2471                        log.error(pos, flowKind.errKey, sym);
2472                    } else {
2473                        uninit(sym);
2474                    }
2475                }
2476                inits.incl(sym.adr);
2477            } else if ((sym.flags() & FINAL) != 0) {
2478                log.error(pos, "var.might.already.be.assigned", sym);
2479            }
2480        }
2481
2482        @Override
2483        void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
2484            if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2485                trackable(sym) &&
2486                !inits.isMember(sym.adr)) {
2487                log.error(pos, errkey, sym);
2488                inits.incl(sym.adr);
2489            }
2490        }
2491
2492        @Override
2493        void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
2494            String key, Object ... args) {
2495            log.warning(lc, pos, key, args);
2496        }
2497
2498        @Override
2499        int getLogNumberOfErrors() {
2500            return log.nerrors;
2501        }
2502
2503        @Override
2504        boolean isEnabled(Lint.LintCategory lc) {
2505            return lint.isEnabled(lc);
2506        }
2507
2508        @Override
2509        public void visitClassDef(JCClassDecl tree) {
2510            if (tree.sym == null) {
2511                return;
2512            }
2513
2514            Lint lintPrev = lint;
2515            lint = lint.augment(tree.sym);
2516            try {
2517                super.visitClassDef(tree);
2518            } finally {
2519                lint = lintPrev;
2520            }
2521        }
2522
2523        @Override
2524        public void visitMethodDef(JCMethodDecl tree) {
2525            if (tree.body == null) {
2526                return;
2527            }
2528
2529            /*  MemberEnter can generate synthetic methods ignore them
2530             */
2531            if ((tree.sym.flags() & SYNTHETIC) != 0) {
2532                return;
2533            }
2534
2535            Lint lintPrev = lint;
2536            lint = lint.augment(tree.sym);
2537            try {
2538                super.visitMethodDef(tree);
2539            } finally {
2540                lint = lintPrev;
2541            }
2542        }
2543
2544        @Override
2545        public void visitVarDef(JCVariableDecl tree) {
2546            if (tree.init == null) {
2547                super.visitVarDef(tree);
2548            } else {
2549                Lint lintPrev = lint;
2550                lint = lint.augment(tree.sym);
2551                try{
2552                    super.visitVarDef(tree);
2553                } finally {
2554                    lint = lintPrev;
2555                }
2556            }
2557        }
2558
2559    }
2560
2561    /**
2562     * This pass implements the last step of the dataflow analysis, namely
2563     * the effectively-final analysis check. This checks that every local variable
2564     * reference from a lambda body/local inner class is either final or effectively final.
2565     * As effectively final variables are marked as such during DA/DU, this pass must run after
2566     * AssignAnalyzer.
2567     */
2568    class CaptureAnalyzer extends BaseAnalyzer<BaseAnalyzer.PendingExit> {
2569
2570        JCTree currentTree; //local class or lambda
2571
2572        @Override
2573        void markDead(JCTree tree) {
2574            //do nothing
2575        }
2576
2577        @SuppressWarnings("fallthrough")
2578        void checkEffectivelyFinal(DiagnosticPosition pos, VarSymbol sym) {
2579            if (currentTree != null &&
2580                    sym.owner.kind == MTH &&
2581                    sym.pos < currentTree.getStartPosition()) {
2582                switch (currentTree.getTag()) {
2583                    case CLASSDEF:
2584                        if (!allowEffectivelyFinalInInnerClasses) {
2585                            if ((sym.flags() & FINAL) == 0) {
2586                                reportInnerClsNeedsFinalError(pos, sym);
2587                            }
2588                            break;
2589                        }
2590                    case LAMBDA:
2591                        if ((sym.flags() & (EFFECTIVELY_FINAL | FINAL)) == 0) {
2592                           reportEffectivelyFinalError(pos, sym);
2593                        }
2594                }
2595            }
2596        }
2597
2598        @SuppressWarnings("fallthrough")
2599        void letInit(JCTree tree) {
2600            tree = TreeInfo.skipParens(tree);
2601            if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2602                Symbol sym = TreeInfo.symbol(tree);
2603                if (currentTree != null &&
2604                        sym.kind == VAR &&
2605                        sym.owner.kind == MTH &&
2606                        ((VarSymbol)sym).pos < currentTree.getStartPosition()) {
2607                    switch (currentTree.getTag()) {
2608                        case CLASSDEF:
2609                            if (!allowEffectivelyFinalInInnerClasses) {
2610                                reportInnerClsNeedsFinalError(tree, sym);
2611                                break;
2612                            }
2613                        case LAMBDA:
2614                            reportEffectivelyFinalError(tree, sym);
2615                    }
2616                }
2617            }
2618        }
2619
2620        void reportEffectivelyFinalError(DiagnosticPosition pos, Symbol sym) {
2621            String subKey = currentTree.hasTag(LAMBDA) ?
2622                  "lambda"  : "inner.cls";
2623            log.error(pos, "cant.ref.non.effectively.final.var", sym, diags.fragment(subKey));
2624        }
2625
2626        void reportInnerClsNeedsFinalError(DiagnosticPosition pos, Symbol sym) {
2627            log.error(pos,
2628                    "local.var.accessed.from.icls.needs.final",
2629                    sym);
2630        }
2631
2632    /*************************************************************************
2633     * Visitor methods for statements and definitions
2634     *************************************************************************/
2635
2636        /* ------------ Visitor methods for various sorts of trees -------------*/
2637
2638        public void visitClassDef(JCClassDecl tree) {
2639            JCTree prevTree = currentTree;
2640            try {
2641                currentTree = tree.sym.isLocal() ? tree : null;
2642                super.visitClassDef(tree);
2643            } finally {
2644                currentTree = prevTree;
2645            }
2646        }
2647
2648        @Override
2649        public void visitLambda(JCLambda tree) {
2650            JCTree prevTree = currentTree;
2651            try {
2652                currentTree = tree;
2653                super.visitLambda(tree);
2654            } finally {
2655                currentTree = prevTree;
2656            }
2657        }
2658
2659        @Override
2660        public void visitIdent(JCIdent tree) {
2661            if (tree.sym.kind == VAR) {
2662                checkEffectivelyFinal(tree, (VarSymbol)tree.sym);
2663            }
2664        }
2665
2666        public void visitAssign(JCAssign tree) {
2667            JCTree lhs = TreeInfo.skipParens(tree.lhs);
2668            if (!(lhs instanceof JCIdent)) {
2669                scan(lhs);
2670            }
2671            scan(tree.rhs);
2672            letInit(lhs);
2673        }
2674
2675        public void visitAssignop(JCAssignOp tree) {
2676            scan(tree.lhs);
2677            scan(tree.rhs);
2678            letInit(tree.lhs);
2679        }
2680
2681        public void visitUnary(JCUnary tree) {
2682            switch (tree.getTag()) {
2683                case PREINC: case POSTINC:
2684                case PREDEC: case POSTDEC:
2685                    scan(tree.arg);
2686                    letInit(tree.arg);
2687                    break;
2688                default:
2689                    scan(tree.arg);
2690            }
2691        }
2692
2693    /**************************************************************************
2694     * main method
2695     *************************************************************************/
2696
2697        /** Perform definite assignment/unassignment analysis on a tree.
2698         */
2699        public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
2700            analyzeTree(env, env.tree, make);
2701        }
2702        public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
2703            try {
2704                attrEnv = env;
2705                Flow.this.make = make;
2706                pendingExits = new ListBuffer<>();
2707                scan(tree);
2708            } finally {
2709                pendingExits = null;
2710                Flow.this.make = null;
2711            }
2712        }
2713    }
2714}
2715