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