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