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.*;
186 * support for assigning to a final field via this.x.
187 *
188 * <p><b>This is NOT part of any supported API.
189 * If you write code that depends on this, you do so at your own risk.
190 * This code and its internal interfaces are subject to change or
191 * deletion without notice.</b>
192 */
193 public class Flow {
194 protected static final Context.Key<Flow> flowKey = new Context.Key<>();
195
196 private final Names names;
197 private final Log log;
198 private final Symtab syms;
199 private final Types types;
200 private final Check chk;
201 private TreeMaker make;
202 private final Resolve rs;
203 private final JCDiagnostic.Factory diags;
204 private final ExhaustivenessComputer exhaustiveness;
205 private Env<AttrContext> attrEnv;
206
207 public static Flow instance(Context context) {
208 Flow instance = context.get(flowKey);
209 if (instance == null)
210 instance = new Flow(context);
211 return instance;
212 }
213
214 public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
215 new AliveAnalyzer().analyzeTree(env, make);
216 new AssignAnalyzer().analyzeTree(env, make);
217 new FlowAnalyzer().analyzeTree(env, make);
218 new CaptureAnalyzer().analyzeTree(env, make);
219 }
220
221 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
222 Log.DiagnosticHandler diagHandler = null;
223 //we need to disable diagnostics temporarily; the problem is that if
224 //a lambda expression contains e.g. an unreachable statement, an error
225 //message will be reported and will cause compilation to skip the flow analysis
309 FlowKind(String errKey, boolean isFinal) {
310 this.errKey = errKey;
311 this.isFinal = isFinal;
312 }
313
314 boolean isFinal() {
315 return isFinal;
316 }
317 }
318
319 @SuppressWarnings("this-escape")
320 protected Flow(Context context) {
321 context.put(flowKey, this);
322 names = Names.instance(context);
323 log = Log.instance(context);
324 syms = Symtab.instance(context);
325 types = Types.instance(context);
326 chk = Check.instance(context);
327 rs = Resolve.instance(context);
328 diags = JCDiagnostic.Factory.instance(context);
329 exhaustiveness = ExhaustivenessComputer.instance(context);
330 }
331
332 /**
333 * Base visitor class for all visitors implementing dataflow analysis logic.
334 * This class define the shared logic for handling jumps (break/continue statements).
335 */
336 abstract static class BaseAnalyzer extends TreeScanner {
337
338 enum JumpKind {
339 BREAK(JCTree.Tag.BREAK) {
340 @Override
341 JCTree getTarget(JCTree tree) {
342 return ((JCBreak)tree).target;
343 }
344 },
345 CONTINUE(JCTree.Tag.CONTINUE) {
346 @Override
347 JCTree getTarget(JCTree tree) {
348 return ((JCContinue)tree).target;
446 }
447 }
448
449 public void visitPackageDef(JCPackageDecl tree) {
450 // Do nothing for PackageDecl
451 }
452
453 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
454 if (swtch.hasTag(SWITCH_EXPRESSION)) {
455 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
456 .setType(swtch.type));
457 brk.target = swtch;
458 scan(brk);
459 } else {
460 JCBreak brk = make.at(Position.NOPOS).Break(null);
461 brk.target = swtch;
462 scan(brk);
463 }
464 }
465
466 // Do something with all static or non-static field initializers and initialization blocks.
467 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
468 if (classDef == initScanClass) // avoid infinite loops
469 return;
470 JCClassDecl initScanClassPrev = initScanClass;
471 initScanClass = classDef;
472 try {
473 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
474 JCTree def = defs.head;
475
476 // Don't recurse into nested classes
477 if (def.hasTag(CLASSDEF))
478 continue;
479
480 /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
481 * represented in the symbol but not in the tree modifiers as they were not originally in the source
482 * code
483 */
484 boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
485 if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic))
486 handler.accept(def);
487 }
488 } finally {
489 initScanClass = initScanClassPrev;
490 }
491 }
492 }
493
494 /**
495 * This pass implements the first step of the dataflow analysis, namely
496 * the liveness analysis check. This checks that every statement is reachable.
497 * The output of this analysis pass are used by other analyzers. This analyzer
498 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
499 */
500 class AliveAnalyzer extends BaseAnalyzer {
501
502 /** A flag that indicates whether the last statement could
503 * complete normally.
504 */
505 private Liveness alive;
506
1676 }
1677
1678 @Override
1679 public void resolveJump() {
1680 inits.andSet(exit_inits);
1681 uninits.andSet(exit_uninits);
1682 }
1683 }
1684
1685 public AssignAnalyzer() {
1686 this.inits = new Bits();
1687 uninits = new Bits();
1688 uninitsTry = new Bits();
1689 initsWhenTrue = new Bits(true);
1690 initsWhenFalse = new Bits(true);
1691 uninitsWhenTrue = new Bits(true);
1692 uninitsWhenFalse = new Bits(true);
1693 }
1694
1695 private boolean isConstructor;
1696
1697 @Override
1698 protected void markDead() {
1699 inits.inclRange(returnadr, nextadr);
1700 uninits.inclRange(returnadr, nextadr);
1701 }
1702
1703 /*-------------- Processing variables ----------------------*/
1704
1705 /** Do we need to track init/uninit state of this symbol?
1706 * I.e. is symbol either a local or a blank final variable?
1707 */
1708 protected boolean trackable(VarSymbol sym) {
1709 return
1710 sym.pos >= startPos &&
1711 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
1712 isFinalUninitializedField(sym)));
1713 }
1714
1715 boolean isFinalUninitializedField(VarSymbol sym) {
1716 return sym.owner.kind == TYP &&
1717 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
1718 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
1719 }
1720
1721 /** Initialize new trackable variable by setting its address field
1722 * to the next available sequence number and entering it under that
1723 * index into the vars array.
1724 */
1725 void newVar(JCVariableDecl varDecl) {
1726 VarSymbol sym = varDecl.sym;
1727 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1728 if ((sym.flags() & FINAL) == 0) {
1729 sym.flags_field |= EFFECTIVELY_FINAL;
1730 }
1731 sym.adr = nextadr;
1732 vardecls[nextadr] = varDecl;
1733 inits.excl(nextadr);
1734 uninits.incl(nextadr);
1735 nextadr++;
1736 }
1737
1769 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1770 }
1771 }
1772 //where
1773 void uninit(VarSymbol sym) {
1774 if (!inits.isMember(sym.adr)) {
1775 // reachable assignment
1776 uninits.excl(sym.adr);
1777 uninitsTry.excl(sym.adr);
1778 } else {
1779 //log.rawWarning(pos, "unreachable assignment");//DEBUG
1780 uninits.excl(sym.adr);
1781 }
1782 }
1783
1784 /** If tree is either a simple name or of the form this.name or
1785 * C.this.name, and tree represents a trackable variable,
1786 * record an initialization of the variable.
1787 */
1788 void letInit(JCTree tree) {
1789 tree = TreeInfo.skipParens(tree);
1790 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1791 Symbol sym = TreeInfo.symbol(tree);
1792 if (sym.kind == VAR) {
1793 letInit(tree.pos(), (VarSymbol)sym);
1794 }
1795 }
1796 }
1797
1798 /** Check that trackable variable is initialized.
1799 */
1800 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1801 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1802 }
1803
1804 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1805 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1806 trackable(sym) &&
1807 !inits.isMember(sym.adr) &&
1808 (sym.flags_field & CLASH) == 0) {
1809 log.error(pos, errkey);
1810 inits.incl(sym.adr);
1811 }
1812 }
1813
1814 /** Utility method to reset several Bits instances.
1815 */
1816 private void resetBits(Bits... bits) {
1817 for (Bits b : bits) {
1818 b.reset();
1819 }
1820 }
1821
1822 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1823 */
1824 void split(boolean setToNull) {
1825 initsWhenFalse.assign(inits);
1826 uninitsWhenFalse.assign(uninits);
1827 initsWhenTrue.assign(inits);
1828 uninitsWhenTrue.assign(uninits);
1829 if (setToNull) {
1978
1979 public void visitMethodDef(JCMethodDecl tree) {
1980 if (tree.body == null) {
1981 return;
1982 }
1983
1984 /* MemberEnter can generate synthetic methods ignore them
1985 */
1986 if ((tree.sym.flags() & SYNTHETIC) != 0) {
1987 return;
1988 }
1989
1990 final Bits initsPrev = new Bits(inits);
1991 final Bits uninitsPrev = new Bits(uninits);
1992 int nextadrPrev = nextadr;
1993 int firstadrPrev = firstadr;
1994 int returnadrPrev = returnadr;
1995
1996 Assert.check(pendingExits.isEmpty());
1997 boolean isConstructorPrev = isConstructor;
1998 try {
1999 isConstructor = TreeInfo.isConstructor(tree);
2000
2001 // We only track field initialization inside constructors
2002 if (!isConstructor) {
2003 firstadr = nextadr;
2004 }
2005
2006 // Mark all method parameters as DA
2007 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2008 JCVariableDecl def = l.head;
2009 scan(def);
2010 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2011 /* If we are executing the code from Gen, then there can be
2012 * synthetic or mandated variables, ignore them.
2013 */
2014 initParam(def);
2015 }
2016 // else we are in an instance initializer block;
2017 // leave caught unchanged.
2018 scan(tree.body);
2019
2020 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2021 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2022 if (isConstructor) {
2023 boolean isSynthesized = (tree.sym.flags() &
2024 GENERATEDCONSTR) != 0;
2025 for (int i = firstadr; i < nextadr; i++) {
2026 JCVariableDecl vardecl = vardecls[i];
2027 VarSymbol var = vardecl.sym;
2028 if (var.owner == classDef.sym && !var.isStatic()) {
2029 // choose the diagnostic position based on whether
2030 // the ctor is default(synthesized) or not
2031 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2032 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2033 var, Errors.VarNotInitializedInDefaultConstructor(var));
2034 } else if (isCompactOrGeneratedRecordConstructor) {
2035 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2036 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2037 var.owner.kind == TYP;
2038 if (isInstanceRecordField) {
2039 boolean notInitialized = !inits.isMember(var.adr);
2040 if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2041 /* this way we indicate Lower that it should generate an initialization for this field
2045 } else {
2046 checkInit(TreeInfo.diagEndPos(tree.body), var);
2047 }
2048 } else {
2049 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2050 }
2051 } else {
2052 checkInit(TreeInfo.diagEndPos(tree.body), var);
2053 }
2054 }
2055 }
2056 }
2057 clearPendingExits(true);
2058 } finally {
2059 inits.assign(initsPrev);
2060 uninits.assign(uninitsPrev);
2061 nextadr = nextadrPrev;
2062 firstadr = firstadrPrev;
2063 returnadr = returnadrPrev;
2064 isConstructor = isConstructorPrev;
2065 }
2066 }
2067
2068 private void clearPendingExits(boolean inMethod) {
2069 List<PendingExit> exits = pendingExits.toList();
2070 pendingExits = new ListBuffer<>();
2071 while (exits.nonEmpty()) {
2072 PendingExit exit = exits.head;
2073 exits = exits.tail;
2074 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2075 log.hasErrorOn(exit.tree.pos()),
2076 exit.tree);
2077 if (inMethod && isConstructor) {
2078 Assert.check(exit instanceof AssignPendingExit);
2079 inits.assign(((AssignPendingExit) exit).exit_inits);
2080 for (int i = firstadr; i < nextadr; i++) {
2081 checkInit(exit.tree.pos(), vardecls[i].sym);
2082 }
2083 }
2084 }
2085 }
2504 }
2505 }
2506
2507 @Override
2508 public void visitContinue(JCContinue tree) {
2509 recordExit(new AssignPendingExit(tree, inits, uninits));
2510 }
2511
2512 @Override
2513 public void visitReturn(JCReturn tree) {
2514 scanExpr(tree.expr);
2515 recordExit(new AssignPendingExit(tree, inits, uninits));
2516 }
2517
2518 public void visitThrow(JCThrow tree) {
2519 scanExpr(tree.expr);
2520 markDead();
2521 }
2522
2523 public void visitApply(JCMethodInvocation tree) {
2524 scanExpr(tree.meth);
2525 scanExprs(tree.args);
2526
2527 // Handle superclass constructor invocations
2528 if (isConstructor) {
2529
2530 // If super(): at this point all initialization blocks will execute
2531 Name name = TreeInfo.name(tree.meth);
2532 if (name == names._super) {
2533 forEachInitializer(classDef, false, def -> {
2534 scan(def);
2535 clearPendingExits(false);
2536 });
2537 }
2538
2539 // If this(): at this point all final uninitialized fields will get initialized
2540 else if (name == names._this) {
2541 for (int address = firstadr; address < nextadr; address++) {
2542 VarSymbol sym = vardecls[address].sym;
2543 if (isFinalUninitializedField(sym) && !sym.isStatic())
2544 letInit(tree.pos(), sym);
2545 }
2546 }
2547 }
2548 }
2549
2550 public void visitNewClass(JCNewClass tree) {
2551 scanExpr(tree.encl);
2552 scanExprs(tree.args);
2553 scan(tree.def);
2554 }
2555
2556 @Override
2557 public void visitLambda(JCLambda tree) {
2558 final Bits prevUninits = new Bits(uninits);
2559 final Bits prevUninitsTry = new Bits(uninitsTry);
2560 final Bits prevInits = new Bits(inits);
2561 int returnadrPrev = returnadr;
2562 int nextadrPrev = nextadr;
2563 ListBuffer<PendingExit> prevPending = pendingExits;
2597 }
2598
2599 public void visitAssert(JCAssert tree) {
2600 final Bits initsExit = new Bits(inits);
2601 final Bits uninitsExit = new Bits(uninits);
2602 scanCond(tree.cond);
2603 uninitsExit.andSet(uninitsWhenTrue);
2604 if (tree.detail != null) {
2605 inits.assign(initsWhenFalse);
2606 uninits.assign(uninitsWhenFalse);
2607 scanExpr(tree.detail);
2608 }
2609 inits.assign(initsExit);
2610 uninits.assign(uninitsExit);
2611 }
2612
2613 public void visitAssign(JCAssign tree) {
2614 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2615 scanExpr(tree.lhs);
2616 scanExpr(tree.rhs);
2617 letInit(tree.lhs);
2618 }
2619
2620 // check fields accessed through this.<field> are definitely
2621 // assigned before reading their value
2622 public void visitSelect(JCFieldAccess tree) {
2623 super.visitSelect(tree);
2624 if (TreeInfo.isThisQualifier(tree.selected) &&
2625 tree.sym.kind == VAR) {
2626 checkInit(tree.pos(), (VarSymbol)tree.sym);
2627 }
2628 }
2629
2630 public void visitAssignop(JCAssignOp tree) {
2631 scanExpr(tree.lhs);
2632 scanExpr(tree.rhs);
2633 letInit(tree.lhs);
2634 }
2635
2636 public void visitUnary(JCUnary tree) {
2637 switch (tree.getTag()) {
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 //todo: one might eliminate uninits.andSets when monotonic
27
28 package com.sun.tools.javac.comp;
29
30 import java.util.HashMap;
31 import java.util.LinkedHashSet;
32 import java.util.Set;
33 import java.util.function.Consumer;
34
35 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
36 import com.sun.tools.javac.code.*;
37 import com.sun.tools.javac.code.Scope.WriteableScope;
38 import com.sun.tools.javac.resources.CompilerProperties.Errors;
39 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
40 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
41 import com.sun.tools.javac.tree.*;
42 import com.sun.tools.javac.util.*;
43 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
44 import com.sun.tools.javac.util.JCDiagnostic.Error;
45 import com.sun.tools.javac.util.JCDiagnostic.Warning;
46
47 import com.sun.tools.javac.code.Symbol.*;
48 import com.sun.tools.javac.tree.JCTree.*;
49
50 import static com.sun.tools.javac.code.Flags.*;
51 import static com.sun.tools.javac.code.Flags.BLOCK;
52 import static com.sun.tools.javac.code.Kinds.Kind.*;
188 * support for assigning to a final field via this.x.
189 *
190 * <p><b>This is NOT part of any supported API.
191 * If you write code that depends on this, you do so at your own risk.
192 * This code and its internal interfaces are subject to change or
193 * deletion without notice.</b>
194 */
195 public class Flow {
196 protected static final Context.Key<Flow> flowKey = new Context.Key<>();
197
198 private final Names names;
199 private final Log log;
200 private final Symtab syms;
201 private final Types types;
202 private final Check chk;
203 private TreeMaker make;
204 private final Resolve rs;
205 private final JCDiagnostic.Factory diags;
206 private final ExhaustivenessComputer exhaustiveness;
207 private Env<AttrContext> attrEnv;
208 private final UnsetFieldsInfo unsetFieldsInfo;
209 private final boolean allowValueClasses;
210
211 public static Flow instance(Context context) {
212 Flow instance = context.get(flowKey);
213 if (instance == null)
214 instance = new Flow(context);
215 return instance;
216 }
217
218 public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
219 new AliveAnalyzer().analyzeTree(env, make);
220 new AssignAnalyzer().analyzeTree(env, make);
221 new FlowAnalyzer().analyzeTree(env, make);
222 new CaptureAnalyzer().analyzeTree(env, make);
223 }
224
225 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
226 Log.DiagnosticHandler diagHandler = null;
227 //we need to disable diagnostics temporarily; the problem is that if
228 //a lambda expression contains e.g. an unreachable statement, an error
229 //message will be reported and will cause compilation to skip the flow analysis
313 FlowKind(String errKey, boolean isFinal) {
314 this.errKey = errKey;
315 this.isFinal = isFinal;
316 }
317
318 boolean isFinal() {
319 return isFinal;
320 }
321 }
322
323 @SuppressWarnings("this-escape")
324 protected Flow(Context context) {
325 context.put(flowKey, this);
326 names = Names.instance(context);
327 log = Log.instance(context);
328 syms = Symtab.instance(context);
329 types = Types.instance(context);
330 chk = Check.instance(context);
331 rs = Resolve.instance(context);
332 diags = JCDiagnostic.Factory.instance(context);
333 unsetFieldsInfo = UnsetFieldsInfo.instance(context);
334 Preview preview = Preview.instance(context);
335 Source source = Source.instance(context);
336 allowValueClasses = (!preview.isPreview(Source.Feature.VALUE_CLASSES) || preview.isEnabled()) &&
337 Source.Feature.VALUE_CLASSES.allowedInSource(source);
338 exhaustiveness = ExhaustivenessComputer.instance(context);
339 }
340
341 /**
342 * Base visitor class for all visitors implementing dataflow analysis logic.
343 * This class define the shared logic for handling jumps (break/continue statements).
344 */
345 abstract static class BaseAnalyzer extends TreeScanner {
346
347 enum JumpKind {
348 BREAK(JCTree.Tag.BREAK) {
349 @Override
350 JCTree getTarget(JCTree tree) {
351 return ((JCBreak)tree).target;
352 }
353 },
354 CONTINUE(JCTree.Tag.CONTINUE) {
355 @Override
356 JCTree getTarget(JCTree tree) {
357 return ((JCContinue)tree).target;
455 }
456 }
457
458 public void visitPackageDef(JCPackageDecl tree) {
459 // Do nothing for PackageDecl
460 }
461
462 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
463 if (swtch.hasTag(SWITCH_EXPRESSION)) {
464 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
465 .setType(swtch.type));
466 brk.target = swtch;
467 scan(brk);
468 } else {
469 JCBreak brk = make.at(Position.NOPOS).Break(null);
470 brk.target = swtch;
471 scan(brk);
472 }
473 }
474
475 // Do something with static or non-static field initializers and initialization blocks.
476 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
477 forEachInitializer(classDef, isStatic, false, handler);
478 }
479
480 /* Do something with static or non-static field initializers and initialization blocks.
481 * the `earlyOnly` argument will determine if we will deal or not with early variable instance
482 * initializers we want to process only those before a super() invocation and ignore them after
483 * it.
484 */
485 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, boolean earlyOnly,
486 Consumer<? super JCTree> handler) {
487 if (classDef == initScanClass) // avoid infinite loops
488 return;
489 JCClassDecl initScanClassPrev = initScanClass;
490 initScanClass = classDef;
491 try {
492 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
493 JCTree def = defs.head;
494
495 // Don't recurse into nested classes
496 if (def.hasTag(CLASSDEF))
497 continue;
498
499 /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
500 * represented in the symbol but not in the tree modifiers as they were not originally in the source
501 * code
502 */
503 boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
504 if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic)) {
505 if (def instanceof JCVariableDecl varDecl) {
506 boolean isEarly = varDecl.init != null &&
507 varDecl.sym.isStrict() &&
508 !varDecl.sym.isStatic();
509 if (isEarly == earlyOnly) {
510 handler.accept(def);
511 }
512 } else if (!earlyOnly) {
513 handler.accept(def);
514 }
515 }
516 }
517 } finally {
518 initScanClass = initScanClassPrev;
519 }
520 }
521 }
522
523 /**
524 * This pass implements the first step of the dataflow analysis, namely
525 * the liveness analysis check. This checks that every statement is reachable.
526 * The output of this analysis pass are used by other analyzers. This analyzer
527 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
528 */
529 class AliveAnalyzer extends BaseAnalyzer {
530
531 /** A flag that indicates whether the last statement could
532 * complete normally.
533 */
534 private Liveness alive;
535
1705 }
1706
1707 @Override
1708 public void resolveJump() {
1709 inits.andSet(exit_inits);
1710 uninits.andSet(exit_uninits);
1711 }
1712 }
1713
1714 public AssignAnalyzer() {
1715 this.inits = new Bits();
1716 uninits = new Bits();
1717 uninitsTry = new Bits();
1718 initsWhenTrue = new Bits(true);
1719 initsWhenFalse = new Bits(true);
1720 uninitsWhenTrue = new Bits(true);
1721 uninitsWhenFalse = new Bits(true);
1722 }
1723
1724 private boolean isConstructor;
1725 private boolean isCompactOrGeneratedRecordConstructor;
1726
1727 @Override
1728 protected void markDead() {
1729 inits.inclRange(returnadr, nextadr);
1730 uninits.inclRange(returnadr, nextadr);
1731 }
1732
1733 /*-------------- Processing variables ----------------------*/
1734
1735 /** Do we need to track init/uninit state of this symbol?
1736 * I.e. is symbol either a local or a blank final variable?
1737 */
1738 protected boolean trackable(VarSymbol sym) {
1739 return
1740 sym.pos >= startPos &&
1741 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
1742 isFinalOrStrictUninitializedField(sym)));
1743 }
1744
1745 boolean isFinalOrStrictUninitializedField(VarSymbol sym) {
1746 return sym.owner.kind == TYP &&
1747 (((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL ||
1748 (sym.flags() & (STRICT | HASINIT | PARAMETER)) == STRICT) &&
1749 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
1750 }
1751
1752 /** Initialize new trackable variable by setting its address field
1753 * to the next available sequence number and entering it under that
1754 * index into the vars array.
1755 */
1756 void newVar(JCVariableDecl varDecl) {
1757 VarSymbol sym = varDecl.sym;
1758 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1759 if ((sym.flags() & FINAL) == 0) {
1760 sym.flags_field |= EFFECTIVELY_FINAL;
1761 }
1762 sym.adr = nextadr;
1763 vardecls[nextadr] = varDecl;
1764 inits.excl(nextadr);
1765 uninits.incl(nextadr);
1766 nextadr++;
1767 }
1768
1800 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1801 }
1802 }
1803 //where
1804 void uninit(VarSymbol sym) {
1805 if (!inits.isMember(sym.adr)) {
1806 // reachable assignment
1807 uninits.excl(sym.adr);
1808 uninitsTry.excl(sym.adr);
1809 } else {
1810 //log.rawWarning(pos, "unreachable assignment");//DEBUG
1811 uninits.excl(sym.adr);
1812 }
1813 }
1814
1815 /** If tree is either a simple name or of the form this.name or
1816 * C.this.name, and tree represents a trackable variable,
1817 * record an initialization of the variable.
1818 */
1819 void letInit(JCTree tree) {
1820 letInit(tree, (JCAssign) null);
1821 }
1822
1823 void letInit(JCTree tree, JCAssign assign) {
1824 tree = TreeInfo.skipParens(tree);
1825 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1826 Symbol sym = TreeInfo.symbol(tree);
1827 if (sym.kind == VAR) {
1828 letInit(tree.pos(), (VarSymbol)sym);
1829 if (isConstructor && sym.isStrict()) {
1830 /* we are initializing a strict field inside of a constructor, we now need to find which fields
1831 * haven't been initialized yet
1832 */
1833 unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, assign != null ? assign : tree, findUninitStrictFields());
1834 }
1835 }
1836 }
1837 }
1838
1839 /** Check that trackable variable is initialized.
1840 */
1841 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1842 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1843 }
1844
1845 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1846 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1847 trackable(sym) &&
1848 !inits.isMember(sym.adr) &&
1849 (sym.flags_field & CLASH) == 0) {
1850 log.error(pos, errkey);
1851 inits.incl(sym.adr);
1852 }
1853 }
1854
1855 /** Utility method to reset several Bits instances.
1856 */
1857 private void resetBits(Bits... bits) {
1858 for (Bits b : bits) {
1859 b.reset();
1860 }
1861 }
1862
1863 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1864 */
1865 void split(boolean setToNull) {
1866 initsWhenFalse.assign(inits);
1867 uninitsWhenFalse.assign(uninits);
1868 initsWhenTrue.assign(inits);
1869 uninitsWhenTrue.assign(uninits);
1870 if (setToNull) {
2019
2020 public void visitMethodDef(JCMethodDecl tree) {
2021 if (tree.body == null) {
2022 return;
2023 }
2024
2025 /* MemberEnter can generate synthetic methods ignore them
2026 */
2027 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2028 return;
2029 }
2030
2031 final Bits initsPrev = new Bits(inits);
2032 final Bits uninitsPrev = new Bits(uninits);
2033 int nextadrPrev = nextadr;
2034 int firstadrPrev = firstadr;
2035 int returnadrPrev = returnadr;
2036
2037 Assert.check(pendingExits.isEmpty());
2038 boolean isConstructorPrev = isConstructor;
2039 boolean isCompactOrGeneratedRecordConstructorPrev = isCompactOrGeneratedRecordConstructor;
2040 try {
2041 isConstructor = TreeInfo.isConstructor(tree);
2042 isCompactOrGeneratedRecordConstructor = isConstructor && ((tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2043 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD));
2044
2045 // We only track field initialization inside constructors
2046 if (!isConstructor) {
2047 firstadr = nextadr;
2048 }
2049
2050 // Mark all method parameters as DA
2051 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2052 JCVariableDecl def = l.head;
2053 scan(def);
2054 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2055 /* If we are executing the code from Gen, then there can be
2056 * synthetic or mandated variables, ignore them.
2057 */
2058 initParam(def);
2059 }
2060 if (isConstructor) {
2061 Set<VarSymbol> unsetFields = findUninitStrictFields();
2062 if (unsetFields != null && !unsetFields.isEmpty()) {
2063 unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
2064 }
2065 }
2066
2067 // else we are in an instance initializer block;
2068 // leave caught unchanged.
2069 scan(tree.body);
2070
2071 if (isConstructor) {
2072 boolean isSynthesized = (tree.sym.flags() &
2073 GENERATEDCONSTR) != 0;
2074 for (int i = firstadr; i < nextadr; i++) {
2075 JCVariableDecl vardecl = vardecls[i];
2076 VarSymbol var = vardecl.sym;
2077 if (var.owner == classDef.sym && !var.isStatic()) {
2078 // choose the diagnostic position based on whether
2079 // the ctor is default(synthesized) or not
2080 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2081 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2082 var, Errors.VarNotInitializedInDefaultConstructor(var));
2083 } else if (isCompactOrGeneratedRecordConstructor) {
2084 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2085 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2086 var.owner.kind == TYP;
2087 if (isInstanceRecordField) {
2088 boolean notInitialized = !inits.isMember(var.adr);
2089 if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2090 /* this way we indicate Lower that it should generate an initialization for this field
2094 } else {
2095 checkInit(TreeInfo.diagEndPos(tree.body), var);
2096 }
2097 } else {
2098 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2099 }
2100 } else {
2101 checkInit(TreeInfo.diagEndPos(tree.body), var);
2102 }
2103 }
2104 }
2105 }
2106 clearPendingExits(true);
2107 } finally {
2108 inits.assign(initsPrev);
2109 uninits.assign(uninitsPrev);
2110 nextadr = nextadrPrev;
2111 firstadr = firstadrPrev;
2112 returnadr = returnadrPrev;
2113 isConstructor = isConstructorPrev;
2114 isCompactOrGeneratedRecordConstructor = isCompactOrGeneratedRecordConstructorPrev;
2115 }
2116 }
2117
2118 Set<VarSymbol> findUninitStrictFields() {
2119 Set<VarSymbol> unsetFields = new LinkedHashSet<>();
2120 for (int i = uninits.nextBit(0); i >= 0; i = uninits.nextBit(i + 1)) {
2121 JCVariableDecl variableDecl = vardecls[i];
2122 if (variableDecl.sym.isStrict()) {
2123 unsetFields.add(variableDecl.sym);
2124 }
2125 }
2126 return unsetFields;
2127 }
2128
2129 private void clearPendingExits(boolean inMethod) {
2130 List<PendingExit> exits = pendingExits.toList();
2131 pendingExits = new ListBuffer<>();
2132 while (exits.nonEmpty()) {
2133 PendingExit exit = exits.head;
2134 exits = exits.tail;
2135 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2136 log.hasErrorOn(exit.tree.pos()),
2137 exit.tree);
2138 if (inMethod && isConstructor) {
2139 Assert.check(exit instanceof AssignPendingExit);
2140 inits.assign(((AssignPendingExit) exit).exit_inits);
2141 for (int i = firstadr; i < nextadr; i++) {
2142 checkInit(exit.tree.pos(), vardecls[i].sym);
2143 }
2144 }
2145 }
2146 }
2565 }
2566 }
2567
2568 @Override
2569 public void visitContinue(JCContinue tree) {
2570 recordExit(new AssignPendingExit(tree, inits, uninits));
2571 }
2572
2573 @Override
2574 public void visitReturn(JCReturn tree) {
2575 scanExpr(tree.expr);
2576 recordExit(new AssignPendingExit(tree, inits, uninits));
2577 }
2578
2579 public void visitThrow(JCThrow tree) {
2580 scanExpr(tree.expr);
2581 markDead();
2582 }
2583
2584 public void visitApply(JCMethodInvocation tree) {
2585 Name name = TreeInfo.name(tree.meth);
2586 // let's process early initializers
2587 if (name == names._super) {
2588 forEachInitializer(classDef, false, true, def -> {
2589 scan(def);
2590 clearPendingExits(false);
2591 });
2592 }
2593 scanExpr(tree.meth);
2594 scanExprs(tree.args);
2595
2596 // Handle superclass constructor invocations
2597 if (isConstructor) {
2598
2599 // If super(): at this point all initialization blocks will execute
2600
2601 if (name == names._super) {
2602 // strict fields should have been initialized at this point
2603 for (int i = firstadr; i < nextadr; i++) {
2604 JCVariableDecl vardecl = vardecls[i];
2605 VarSymbol var = vardecl.sym;
2606 if (allowValueClasses && (var.owner == classDef.sym && !var.isStatic() && (var.isStrict() || ((var.flags_field & RECORD) != 0)) && !isCompactOrGeneratedRecordConstructor)) {
2607 checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
2608 }
2609 }
2610 forEachInitializer(classDef, false, def -> {
2611 scan(def);
2612 clearPendingExits(false);
2613 });
2614 }
2615
2616 // If this(): at this point all final uninitialized fields will get initialized
2617 else if (name == names._this) {
2618 for (int address = firstadr; address < nextadr; address++) {
2619 VarSymbol sym = vardecls[address].sym;
2620 if (isFinalOrStrictUninitializedField(sym) && !sym.isStatic())
2621 letInit(tree.pos(), sym);
2622 }
2623 }
2624 }
2625 }
2626
2627 public void visitNewClass(JCNewClass tree) {
2628 scanExpr(tree.encl);
2629 scanExprs(tree.args);
2630 scan(tree.def);
2631 }
2632
2633 @Override
2634 public void visitLambda(JCLambda tree) {
2635 final Bits prevUninits = new Bits(uninits);
2636 final Bits prevUninitsTry = new Bits(uninitsTry);
2637 final Bits prevInits = new Bits(inits);
2638 int returnadrPrev = returnadr;
2639 int nextadrPrev = nextadr;
2640 ListBuffer<PendingExit> prevPending = pendingExits;
2674 }
2675
2676 public void visitAssert(JCAssert tree) {
2677 final Bits initsExit = new Bits(inits);
2678 final Bits uninitsExit = new Bits(uninits);
2679 scanCond(tree.cond);
2680 uninitsExit.andSet(uninitsWhenTrue);
2681 if (tree.detail != null) {
2682 inits.assign(initsWhenFalse);
2683 uninits.assign(uninitsWhenFalse);
2684 scanExpr(tree.detail);
2685 }
2686 inits.assign(initsExit);
2687 uninits.assign(uninitsExit);
2688 }
2689
2690 public void visitAssign(JCAssign tree) {
2691 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2692 scanExpr(tree.lhs);
2693 scanExpr(tree.rhs);
2694 letInit(tree.lhs, tree);
2695 }
2696
2697 // check fields accessed through this.<field> are definitely
2698 // assigned before reading their value
2699 public void visitSelect(JCFieldAccess tree) {
2700 super.visitSelect(tree);
2701 if (TreeInfo.isThisQualifier(tree.selected) &&
2702 tree.sym.kind == VAR) {
2703 checkInit(tree.pos(), (VarSymbol)tree.sym);
2704 }
2705 }
2706
2707 public void visitAssignop(JCAssignOp tree) {
2708 scanExpr(tree.lhs);
2709 scanExpr(tree.rhs);
2710 letInit(tree.lhs);
2711 }
2712
2713 public void visitUnary(JCUnary tree) {
2714 switch (tree.getTag()) {
|