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