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