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