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