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