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