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