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