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.*;
192 * support for assigning to a final field via this.x.
193 *
194 * <p><b>This is NOT part of any supported API.
195 * If you write code that depends on this, you do so at your own risk.
196 * This code and its internal interfaces are subject to change or
197 * deletion without notice.</b>
198 */
199 public class Flow {
200 protected static final Context.Key<Flow> flowKey = new Context.Key<>();
201
202 private final Names names;
203 private final Log log;
204 private final Symtab syms;
205 private final Types types;
206 private final Check chk;
207 private TreeMaker make;
208 private final Resolve rs;
209 private final JCDiagnostic.Factory diags;
210 private final ExhaustivenessComputer exhaustiveness;
211 private Env<AttrContext> attrEnv;
212
213 public static Flow instance(Context context) {
214 Flow instance = context.get(flowKey);
215 if (instance == null)
216 instance = new Flow(context);
217 return instance;
218 }
219
220 public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
221 new AliveAnalyzer().analyzeTree(env, make);
222 new AssignAnalyzer().analyzeTree(env, make);
223 new FlowAnalyzer().analyzeTree(env, make);
224 new CaptureAnalyzer().analyzeTree(env, make);
225 }
226
227 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
228 Log.DiagnosticHandler diagHandler = null;
229 //we need to disable diagnostics temporarily; the problem is that if
230 //a lambda expression contains e.g. an unreachable statement, an error
231 //message will be reported and will cause compilation to skip the flow analysis
315 FlowKind(String errKey, boolean isFinal) {
316 this.errKey = errKey;
317 this.isFinal = isFinal;
318 }
319
320 boolean isFinal() {
321 return isFinal;
322 }
323 }
324
325 @SuppressWarnings("this-escape")
326 protected Flow(Context context) {
327 context.put(flowKey, this);
328 names = Names.instance(context);
329 log = Log.instance(context);
330 syms = Symtab.instance(context);
331 types = Types.instance(context);
332 chk = Check.instance(context);
333 rs = Resolve.instance(context);
334 diags = JCDiagnostic.Factory.instance(context);
335 exhaustiveness = ExhaustivenessComputer.instance(context);
336 }
337
338 /**
339 * Base visitor class for all visitors implementing dataflow analysis logic.
340 * This class define the shared logic for handling jumps (break/continue statements).
341 */
342 abstract static class BaseAnalyzer extends TreeScanner {
343
344 enum JumpKind {
345 BREAK(JCTree.Tag.BREAK) {
346 @Override
347 JCTree getTarget(JCTree tree) {
348 return ((JCBreak)tree).target;
349 }
350 },
351 CONTINUE(JCTree.Tag.CONTINUE) {
352 @Override
353 JCTree getTarget(JCTree tree) {
354 return ((JCContinue)tree).target;
452 }
453 }
454
455 public void visitPackageDef(JCPackageDecl tree) {
456 // Do nothing for PackageDecl
457 }
458
459 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
460 if (swtch.hasTag(SWITCH_EXPRESSION)) {
461 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
462 .setType(swtch.type));
463 brk.target = swtch;
464 scan(brk);
465 } else {
466 JCBreak brk = make.at(Position.NOPOS).Break(null);
467 brk.target = swtch;
468 scan(brk);
469 }
470 }
471
472 // Do something with all static or non-static field initializers and initialization blocks.
473 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
474 if (classDef == initScanClass) // avoid infinite loops
475 return;
476 JCClassDecl initScanClassPrev = initScanClass;
477 initScanClass = classDef;
478 try {
479 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
480 JCTree def = defs.head;
481
482 // Don't recurse into nested classes
483 if (def.hasTag(CLASSDEF))
484 continue;
485
486 /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
487 * represented in the symbol but not in the tree modifiers as they were not originally in the source
488 * code
489 */
490 boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
491 if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic))
492 handler.accept(def);
493 }
494 } finally {
495 initScanClass = initScanClassPrev;
496 }
497 }
498 }
499
500 /**
501 * This pass implements the first step of the dataflow analysis, namely
502 * the liveness analysis check. This checks that every statement is reachable.
503 * The output of this analysis pass are used by other analyzers. This analyzer
504 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
505 */
506 class AliveAnalyzer extends BaseAnalyzer {
507
508 /** A flag that indicates whether the last statement could
509 * complete normally.
510 */
511 private Liveness alive;
512
1729 }
1730
1731 @Override
1732 public void resolveJump() {
1733 inits.andSet(exit_inits);
1734 uninits.andSet(exit_uninits);
1735 }
1736 }
1737
1738 public AssignAnalyzer() {
1739 this.inits = new Bits();
1740 uninits = new Bits();
1741 uninitsTry = new Bits();
1742 initsWhenTrue = new Bits(true);
1743 initsWhenFalse = new Bits(true);
1744 uninitsWhenTrue = new Bits(true);
1745 uninitsWhenFalse = new Bits(true);
1746 }
1747
1748 private boolean isConstructor;
1749
1750 @Override
1751 protected void markDead() {
1752 inits.inclRange(returnadr, nextadr);
1753 uninits.inclRange(returnadr, nextadr);
1754 }
1755
1756 /*-------------- Processing variables ----------------------*/
1757
1758 /** Do we need to track init/uninit state of this symbol?
1759 * I.e. is symbol either a local or a blank final variable?
1760 */
1761 protected boolean trackable(VarSymbol sym) {
1762 return
1763 sym.pos >= startPos &&
1764 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
1765 isFinalUninitializedField(sym)));
1766 }
1767
1768 boolean isFinalUninitializedField(VarSymbol sym) {
1769 return sym.owner.kind == TYP &&
1770 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
1771 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
1772 }
1773
1774 /** Initialize new trackable variable by setting its address field
1775 * to the next available sequence number and entering it under that
1776 * index into the vars array.
1777 */
1778 void newVar(JCVariableDecl varDecl) {
1779 VarSymbol sym = varDecl.sym;
1780 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1781 if ((sym.flags() & FINAL) == 0) {
1782 sym.flags_field |= EFFECTIVELY_FINAL;
1783 }
1784 sym.adr = nextadr;
1785 vardecls[nextadr] = varDecl;
1786 inits.excl(nextadr);
1787 uninits.incl(nextadr);
1788 nextadr++;
1789 }
1790
1822 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1823 }
1824 }
1825 //where
1826 void uninit(VarSymbol sym) {
1827 if (!inits.isMember(sym.adr)) {
1828 // reachable assignment
1829 uninits.excl(sym.adr);
1830 uninitsTry.excl(sym.adr);
1831 } else {
1832 //log.rawWarning(pos, "unreachable assignment");//DEBUG
1833 uninits.excl(sym.adr);
1834 }
1835 }
1836
1837 /** If tree is either a simple name or of the form this.name or
1838 * C.this.name, and tree represents a trackable variable,
1839 * record an initialization of the variable.
1840 */
1841 void letInit(JCTree tree) {
1842 tree = TreeInfo.skipParens(tree);
1843 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1844 Symbol sym = TreeInfo.symbol(tree);
1845 if (sym.kind == VAR) {
1846 letInit(tree.pos(), (VarSymbol)sym);
1847 }
1848 }
1849 }
1850
1851 /** Check that trackable variable is initialized.
1852 */
1853 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1854 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1855 }
1856
1857 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1858 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1859 trackable(sym) &&
1860 !inits.isMember(sym.adr) &&
1861 (sym.flags_field & CLASH) == 0) {
1862 log.error(pos, errkey);
1863 inits.incl(sym.adr);
1864 }
1865 }
1866
1867 /** Utility method to reset several Bits instances.
1868 */
1869 private void resetBits(Bits... bits) {
1870 for (Bits b : bits) {
1871 b.reset();
1872 }
1873 }
1874
1875 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1876 */
1877 void split(boolean setToNull) {
1878 initsWhenFalse.assign(inits);
1879 uninitsWhenFalse.assign(uninits);
1880 initsWhenTrue.assign(inits);
1881 uninitsWhenTrue.assign(uninits);
1882 if (setToNull) {
2031
2032 public void visitMethodDef(JCMethodDecl tree) {
2033 if (tree.body == null) {
2034 return;
2035 }
2036
2037 /* MemberEnter can generate synthetic methods ignore them
2038 */
2039 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2040 return;
2041 }
2042
2043 final Bits initsPrev = new Bits(inits);
2044 final Bits uninitsPrev = new Bits(uninits);
2045 int nextadrPrev = nextadr;
2046 int firstadrPrev = firstadr;
2047 int returnadrPrev = returnadr;
2048
2049 Assert.check(pendingExits.isEmpty());
2050 boolean isConstructorPrev = isConstructor;
2051 try {
2052 isConstructor = TreeInfo.isConstructor(tree);
2053
2054 // We only track field initialization inside constructors
2055 if (!isConstructor) {
2056 firstadr = nextadr;
2057 }
2058
2059 // Mark all method parameters as DA
2060 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2061 JCVariableDecl def = l.head;
2062 scan(def);
2063 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2064 /* If we are executing the code from Gen, then there can be
2065 * synthetic or mandated variables, ignore them.
2066 */
2067 initParam(def);
2068 }
2069 // else we are in an instance initializer block;
2070 // leave caught unchanged.
2071 scan(tree.body);
2072
2073 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2074 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2075 if (isConstructor) {
2076 boolean isSynthesized = (tree.sym.flags() &
2077 GENERATEDCONSTR) != 0;
2078 for (int i = firstadr; i < nextadr; i++) {
2079 JCVariableDecl vardecl = vardecls[i];
2080 VarSymbol var = vardecl.sym;
2081 if (var.owner == classDef.sym && !var.isStatic()) {
2082 // choose the diagnostic position based on whether
2083 // the ctor is default(synthesized) or not
2084 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2085 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2086 var, Errors.VarNotInitializedInDefaultConstructor(var));
2087 } else if (isCompactOrGeneratedRecordConstructor) {
2088 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2089 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2090 var.owner.kind == TYP;
2091 if (isInstanceRecordField) {
2092 boolean notInitialized = !inits.isMember(var.adr);
2093 if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2094 /* this way we indicate Lower that it should generate an initialization for this field
2098 } else {
2099 checkInit(TreeInfo.diagEndPos(tree.body), var);
2100 }
2101 } else {
2102 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2103 }
2104 } else {
2105 checkInit(TreeInfo.diagEndPos(tree.body), var);
2106 }
2107 }
2108 }
2109 }
2110 clearPendingExits(true);
2111 } finally {
2112 inits.assign(initsPrev);
2113 uninits.assign(uninitsPrev);
2114 nextadr = nextadrPrev;
2115 firstadr = firstadrPrev;
2116 returnadr = returnadrPrev;
2117 isConstructor = isConstructorPrev;
2118 }
2119 }
2120
2121 private void clearPendingExits(boolean inMethod) {
2122 List<PendingExit> exits = pendingExits.toList();
2123 pendingExits = new ListBuffer<>();
2124 while (exits.nonEmpty()) {
2125 PendingExit exit = exits.head;
2126 exits = exits.tail;
2127 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2128 log.hasErrorOn(exit.tree.pos()),
2129 exit.tree);
2130 if (inMethod && isConstructor) {
2131 Assert.check(exit instanceof AssignPendingExit);
2132 inits.assign(((AssignPendingExit) exit).exit_inits);
2133 for (int i = firstadr; i < nextadr; i++) {
2134 checkInit(exit.tree.pos(), vardecls[i].sym);
2135 }
2136 }
2137 }
2138 }
2557 }
2558 }
2559
2560 @Override
2561 public void visitContinue(JCContinue tree) {
2562 recordExit(new AssignPendingExit(tree, inits, uninits));
2563 }
2564
2565 @Override
2566 public void visitReturn(JCReturn tree) {
2567 scanExpr(tree.expr);
2568 recordExit(new AssignPendingExit(tree, inits, uninits));
2569 }
2570
2571 public void visitThrow(JCThrow tree) {
2572 scanExpr(tree.expr);
2573 markDead();
2574 }
2575
2576 public void visitApply(JCMethodInvocation tree) {
2577 scanExpr(tree.meth);
2578 scanExprs(tree.args);
2579
2580 // Handle superclass constructor invocations
2581 if (isConstructor) {
2582
2583 // If super(): at this point all initialization blocks will execute
2584 Name name = TreeInfo.name(tree.meth);
2585 if (name == names._super) {
2586 forEachInitializer(classDef, false, def -> {
2587 scan(def);
2588 clearPendingExits(false);
2589 });
2590 }
2591
2592 // If this(): at this point all final uninitialized fields will get initialized
2593 else if (name == names._this) {
2594 for (int address = firstadr; address < nextadr; address++) {
2595 VarSymbol sym = vardecls[address].sym;
2596 if (isFinalUninitializedField(sym) && !sym.isStatic())
2597 letInit(tree.pos(), sym);
2598 }
2599 }
2600 }
2601 }
2602
2603 public void visitNewClass(JCNewClass tree) {
2604 scanExpr(tree.encl);
2605 scanExprs(tree.args);
2606 scan(tree.def);
2607 }
2608
2609 @Override
2610 public void visitLambda(JCLambda tree) {
2611 final Bits prevUninits = new Bits(uninits);
2612 final Bits prevUninitsTry = new Bits(uninitsTry);
2613 final Bits prevInits = new Bits(inits);
2614 int returnadrPrev = returnadr;
2615 int nextadrPrev = nextadr;
2616 ListBuffer<PendingExit> prevPending = pendingExits;
2650 }
2651
2652 public void visitAssert(JCAssert tree) {
2653 final Bits initsExit = new Bits(inits);
2654 final Bits uninitsExit = new Bits(uninits);
2655 scanCond(tree.cond);
2656 uninitsExit.andSet(uninitsWhenTrue);
2657 if (tree.detail != null) {
2658 inits.assign(initsWhenFalse);
2659 uninits.assign(uninitsWhenFalse);
2660 scanExpr(tree.detail);
2661 }
2662 inits.assign(initsExit);
2663 uninits.assign(uninitsExit);
2664 }
2665
2666 public void visitAssign(JCAssign tree) {
2667 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2668 scanExpr(tree.lhs);
2669 scanExpr(tree.rhs);
2670 letInit(tree.lhs);
2671 }
2672
2673 // check fields accessed through this.<field> are definitely
2674 // assigned before reading their value
2675 public void visitSelect(JCFieldAccess tree) {
2676 super.visitSelect(tree);
2677 if (TreeInfo.isThisQualifier(tree.selected) &&
2678 tree.sym.kind == VAR) {
2679 checkInit(tree.pos(), (VarSymbol)tree.sym);
2680 }
2681 }
2682
2683 public void visitAssignop(JCAssignOp tree) {
2684 scanExpr(tree.lhs);
2685 scanExpr(tree.rhs);
2686 letInit(tree.lhs);
2687 }
2688
2689 public void visitUnary(JCUnary tree) {
2690 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.*;
194 * support for assigning to a final field via this.x.
195 *
196 * <p><b>This is NOT part of any supported API.
197 * If you write code that depends on this, you do so at your own risk.
198 * This code and its internal interfaces are subject to change or
199 * deletion without notice.</b>
200 */
201 public class Flow {
202 protected static final Context.Key<Flow> flowKey = new Context.Key<>();
203
204 private final Names names;
205 private final Log log;
206 private final Symtab syms;
207 private final Types types;
208 private final Check chk;
209 private TreeMaker make;
210 private final Resolve rs;
211 private final JCDiagnostic.Factory diags;
212 private final ExhaustivenessComputer exhaustiveness;
213 private Env<AttrContext> attrEnv;
214 private final UnsetFieldsInfo unsetFieldsInfo;
215 private final boolean allowValueClasses;
216
217 public static Flow instance(Context context) {
218 Flow instance = context.get(flowKey);
219 if (instance == null)
220 instance = new Flow(context);
221 return instance;
222 }
223
224 public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
225 new AliveAnalyzer().analyzeTree(env, make);
226 new AssignAnalyzer().analyzeTree(env, make);
227 new FlowAnalyzer().analyzeTree(env, make);
228 new CaptureAnalyzer().analyzeTree(env, make);
229 }
230
231 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
232 Log.DiagnosticHandler diagHandler = null;
233 //we need to disable diagnostics temporarily; the problem is that if
234 //a lambda expression contains e.g. an unreachable statement, an error
235 //message will be reported and will cause compilation to skip the flow analysis
319 FlowKind(String errKey, boolean isFinal) {
320 this.errKey = errKey;
321 this.isFinal = isFinal;
322 }
323
324 boolean isFinal() {
325 return isFinal;
326 }
327 }
328
329 @SuppressWarnings("this-escape")
330 protected Flow(Context context) {
331 context.put(flowKey, this);
332 names = Names.instance(context);
333 log = Log.instance(context);
334 syms = Symtab.instance(context);
335 types = Types.instance(context);
336 chk = Check.instance(context);
337 rs = Resolve.instance(context);
338 diags = JCDiagnostic.Factory.instance(context);
339 unsetFieldsInfo = UnsetFieldsInfo.instance(context);
340 Preview preview = Preview.instance(context);
341 Source source = Source.instance(context);
342 allowValueClasses = (!preview.isPreview(Source.Feature.VALUE_CLASSES) || preview.isEnabled()) &&
343 Source.Feature.VALUE_CLASSES.allowedInSource(source);
344 exhaustiveness = ExhaustivenessComputer.instance(context);
345 }
346
347 /**
348 * Base visitor class for all visitors implementing dataflow analysis logic.
349 * This class define the shared logic for handling jumps (break/continue statements).
350 */
351 abstract static class BaseAnalyzer extends TreeScanner {
352
353 enum JumpKind {
354 BREAK(JCTree.Tag.BREAK) {
355 @Override
356 JCTree getTarget(JCTree tree) {
357 return ((JCBreak)tree).target;
358 }
359 },
360 CONTINUE(JCTree.Tag.CONTINUE) {
361 @Override
362 JCTree getTarget(JCTree tree) {
363 return ((JCContinue)tree).target;
461 }
462 }
463
464 public void visitPackageDef(JCPackageDecl tree) {
465 // Do nothing for PackageDecl
466 }
467
468 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
469 if (swtch.hasTag(SWITCH_EXPRESSION)) {
470 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
471 .setType(swtch.type));
472 brk.target = swtch;
473 scan(brk);
474 } else {
475 JCBreak brk = make.at(Position.NOPOS).Break(null);
476 brk.target = swtch;
477 scan(brk);
478 }
479 }
480
481 // Do something with static or non-static field initializers and initialization blocks.
482 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
483 forEachInitializer(classDef, isStatic, false, handler);
484 }
485
486 /* Do something with static or non-static field initializers and initialization blocks.
487 * the `earlyOnly` argument will determine if we will deal or not with early variable instance
488 * initializers we want to process only those before a super() invocation and ignore them after
489 * it.
490 */
491 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, boolean earlyOnly,
492 Consumer<? super JCTree> handler) {
493 if (classDef == initScanClass) // avoid infinite loops
494 return;
495 JCClassDecl initScanClassPrev = initScanClass;
496 initScanClass = classDef;
497 try {
498 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
499 JCTree def = defs.head;
500
501 // Don't recurse into nested classes
502 if (def.hasTag(CLASSDEF))
503 continue;
504
505 /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
506 * represented in the symbol but not in the tree modifiers as they were not originally in the source
507 * code
508 */
509 boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
510 if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic)) {
511 if (def instanceof JCVariableDecl varDecl) {
512 boolean isEarly = varDecl.init != null &&
513 varDecl.sym.isStrict() &&
514 !varDecl.sym.isStatic();
515 if (isEarly == earlyOnly) {
516 handler.accept(def);
517 }
518 } else if (!earlyOnly) {
519 handler.accept(def);
520 }
521 }
522 }
523 } finally {
524 initScanClass = initScanClassPrev;
525 }
526 }
527 }
528
529 /**
530 * This pass implements the first step of the dataflow analysis, namely
531 * the liveness analysis check. This checks that every statement is reachable.
532 * The output of this analysis pass are used by other analyzers. This analyzer
533 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
534 */
535 class AliveAnalyzer extends BaseAnalyzer {
536
537 /** A flag that indicates whether the last statement could
538 * complete normally.
539 */
540 private Liveness alive;
541
1758 }
1759
1760 @Override
1761 public void resolveJump() {
1762 inits.andSet(exit_inits);
1763 uninits.andSet(exit_uninits);
1764 }
1765 }
1766
1767 public AssignAnalyzer() {
1768 this.inits = new Bits();
1769 uninits = new Bits();
1770 uninitsTry = new Bits();
1771 initsWhenTrue = new Bits(true);
1772 initsWhenFalse = new Bits(true);
1773 uninitsWhenTrue = new Bits(true);
1774 uninitsWhenFalse = new Bits(true);
1775 }
1776
1777 private boolean isConstructor;
1778 private boolean isCompactOrGeneratedRecordConstructor;
1779
1780 @Override
1781 protected void markDead() {
1782 inits.inclRange(returnadr, nextadr);
1783 uninits.inclRange(returnadr, nextadr);
1784 }
1785
1786 /*-------------- Processing variables ----------------------*/
1787
1788 /** Do we need to track init/uninit state of this symbol?
1789 * I.e. is symbol either a local or a blank final variable?
1790 */
1791 protected boolean trackable(VarSymbol sym) {
1792 return
1793 sym.pos >= startPos &&
1794 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
1795 isFinalOrStrictUninitializedField(sym)));
1796 }
1797
1798 boolean isFinalOrStrictUninitializedField(VarSymbol sym) {
1799 return sym.owner.kind == TYP &&
1800 (((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL ||
1801 (sym.flags() & (STRICT | HASINIT | PARAMETER)) == STRICT) &&
1802 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
1803 }
1804
1805 /** Initialize new trackable variable by setting its address field
1806 * to the next available sequence number and entering it under that
1807 * index into the vars array.
1808 */
1809 void newVar(JCVariableDecl varDecl) {
1810 VarSymbol sym = varDecl.sym;
1811 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1812 if ((sym.flags() & FINAL) == 0) {
1813 sym.flags_field |= EFFECTIVELY_FINAL;
1814 }
1815 sym.adr = nextadr;
1816 vardecls[nextadr] = varDecl;
1817 inits.excl(nextadr);
1818 uninits.incl(nextadr);
1819 nextadr++;
1820 }
1821
1853 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1854 }
1855 }
1856 //where
1857 void uninit(VarSymbol sym) {
1858 if (!inits.isMember(sym.adr)) {
1859 // reachable assignment
1860 uninits.excl(sym.adr);
1861 uninitsTry.excl(sym.adr);
1862 } else {
1863 //log.rawWarning(pos, "unreachable assignment");//DEBUG
1864 uninits.excl(sym.adr);
1865 }
1866 }
1867
1868 /** If tree is either a simple name or of the form this.name or
1869 * C.this.name, and tree represents a trackable variable,
1870 * record an initialization of the variable.
1871 */
1872 void letInit(JCTree tree) {
1873 letInit(tree, (JCAssign) null);
1874 }
1875
1876 void letInit(JCTree tree, JCAssign assign) {
1877 tree = TreeInfo.skipParens(tree);
1878 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1879 Symbol sym = TreeInfo.symbol(tree);
1880 if (sym.kind == VAR) {
1881 letInit(tree.pos(), (VarSymbol)sym);
1882 if (isConstructor && sym.isStrict()) {
1883 /* we are initializing a strict field inside of a constructor, we now need to find which fields
1884 * haven't been initialized yet
1885 */
1886 unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, assign != null ? assign : tree, findUninitStrictFields());
1887 }
1888 }
1889 }
1890 }
1891
1892 /** Check that trackable variable is initialized.
1893 */
1894 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1895 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1896 }
1897
1898 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1899 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1900 trackable(sym) &&
1901 !inits.isMember(sym.adr) &&
1902 (sym.flags_field & CLASH) == 0) {
1903 log.error(pos, errkey);
1904 inits.incl(sym.adr);
1905 }
1906 }
1907
1908 /** Utility method to reset several Bits instances.
1909 */
1910 private void resetBits(Bits... bits) {
1911 for (Bits b : bits) {
1912 b.reset();
1913 }
1914 }
1915
1916 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1917 */
1918 void split(boolean setToNull) {
1919 initsWhenFalse.assign(inits);
1920 uninitsWhenFalse.assign(uninits);
1921 initsWhenTrue.assign(inits);
1922 uninitsWhenTrue.assign(uninits);
1923 if (setToNull) {
2072
2073 public void visitMethodDef(JCMethodDecl tree) {
2074 if (tree.body == null) {
2075 return;
2076 }
2077
2078 /* MemberEnter can generate synthetic methods ignore them
2079 */
2080 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2081 return;
2082 }
2083
2084 final Bits initsPrev = new Bits(inits);
2085 final Bits uninitsPrev = new Bits(uninits);
2086 int nextadrPrev = nextadr;
2087 int firstadrPrev = firstadr;
2088 int returnadrPrev = returnadr;
2089
2090 Assert.check(pendingExits.isEmpty());
2091 boolean isConstructorPrev = isConstructor;
2092 boolean isCompactOrGeneratedRecordConstructorPrev = isCompactOrGeneratedRecordConstructor;
2093 try {
2094 isConstructor = TreeInfo.isConstructor(tree);
2095 isCompactOrGeneratedRecordConstructor = isConstructor && ((tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2096 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD));
2097
2098 // We only track field initialization inside constructors
2099 if (!isConstructor) {
2100 firstadr = nextadr;
2101 }
2102
2103 // Mark all method parameters as DA
2104 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2105 JCVariableDecl def = l.head;
2106 scan(def);
2107 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2108 /* If we are executing the code from Gen, then there can be
2109 * synthetic or mandated variables, ignore them.
2110 */
2111 initParam(def);
2112 }
2113 if (isConstructor) {
2114 Set<VarSymbol> unsetFields = findUninitStrictFields();
2115 if (unsetFields != null && !unsetFields.isEmpty()) {
2116 unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
2117 }
2118 }
2119
2120 // else we are in an instance initializer block;
2121 // leave caught unchanged.
2122 scan(tree.body);
2123
2124 if (isConstructor) {
2125 boolean isSynthesized = (tree.sym.flags() &
2126 GENERATEDCONSTR) != 0;
2127 for (int i = firstadr; i < nextadr; i++) {
2128 JCVariableDecl vardecl = vardecls[i];
2129 VarSymbol var = vardecl.sym;
2130 if (var.owner == classDef.sym && !var.isStatic()) {
2131 // choose the diagnostic position based on whether
2132 // the ctor is default(synthesized) or not
2133 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2134 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2135 var, Errors.VarNotInitializedInDefaultConstructor(var));
2136 } else if (isCompactOrGeneratedRecordConstructor) {
2137 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2138 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2139 var.owner.kind == TYP;
2140 if (isInstanceRecordField) {
2141 boolean notInitialized = !inits.isMember(var.adr);
2142 if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2143 /* this way we indicate Lower that it should generate an initialization for this field
2147 } else {
2148 checkInit(TreeInfo.diagEndPos(tree.body), var);
2149 }
2150 } else {
2151 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2152 }
2153 } else {
2154 checkInit(TreeInfo.diagEndPos(tree.body), var);
2155 }
2156 }
2157 }
2158 }
2159 clearPendingExits(true);
2160 } finally {
2161 inits.assign(initsPrev);
2162 uninits.assign(uninitsPrev);
2163 nextadr = nextadrPrev;
2164 firstadr = firstadrPrev;
2165 returnadr = returnadrPrev;
2166 isConstructor = isConstructorPrev;
2167 isCompactOrGeneratedRecordConstructor = isCompactOrGeneratedRecordConstructorPrev;
2168 }
2169 }
2170
2171 Set<VarSymbol> findUninitStrictFields() {
2172 Set<VarSymbol> unsetFields = new LinkedHashSet<>();
2173 for (int i = firstadr; i < nextadr; i++) {
2174 if (uninits.isMember(i) && vardecls[i].sym.isStrict()) {
2175 unsetFields.add(vardecls[i].sym);
2176 }
2177 }
2178 return unsetFields;
2179 }
2180
2181 private void clearPendingExits(boolean inMethod) {
2182 List<PendingExit> exits = pendingExits.toList();
2183 pendingExits = new ListBuffer<>();
2184 while (exits.nonEmpty()) {
2185 PendingExit exit = exits.head;
2186 exits = exits.tail;
2187 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2188 log.hasErrorOn(exit.tree.pos()),
2189 exit.tree);
2190 if (inMethod && isConstructor) {
2191 Assert.check(exit instanceof AssignPendingExit);
2192 inits.assign(((AssignPendingExit) exit).exit_inits);
2193 for (int i = firstadr; i < nextadr; i++) {
2194 checkInit(exit.tree.pos(), vardecls[i].sym);
2195 }
2196 }
2197 }
2198 }
2617 }
2618 }
2619
2620 @Override
2621 public void visitContinue(JCContinue tree) {
2622 recordExit(new AssignPendingExit(tree, inits, uninits));
2623 }
2624
2625 @Override
2626 public void visitReturn(JCReturn tree) {
2627 scanExpr(tree.expr);
2628 recordExit(new AssignPendingExit(tree, inits, uninits));
2629 }
2630
2631 public void visitThrow(JCThrow tree) {
2632 scanExpr(tree.expr);
2633 markDead();
2634 }
2635
2636 public void visitApply(JCMethodInvocation tree) {
2637 Name name = TreeInfo.name(tree.meth);
2638 // let's process early initializers
2639 if (name == names._super) {
2640 forEachInitializer(classDef, false, true, def -> {
2641 scan(def);
2642 clearPendingExits(false);
2643 });
2644 }
2645 scanExpr(tree.meth);
2646 scanExprs(tree.args);
2647
2648 // Handle superclass constructor invocations
2649 if (isConstructor) {
2650
2651 // If super(): at this point all initialization blocks will execute
2652
2653 if (name == names._super) {
2654 // strict fields should have been initialized at this point
2655 for (int i = firstadr; i < nextadr; i++) {
2656 JCVariableDecl vardecl = vardecls[i];
2657 VarSymbol var = vardecl.sym;
2658 if (allowValueClasses && (var.owner == classDef.sym && !var.isStatic() && (var.isStrict() || ((var.flags_field & RECORD) != 0)) && !isCompactOrGeneratedRecordConstructor)) {
2659 checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
2660 }
2661 }
2662 forEachInitializer(classDef, false, def -> {
2663 scan(def);
2664 clearPendingExits(false);
2665 });
2666 }
2667
2668 // If this(): at this point all final uninitialized fields will get initialized
2669 else if (name == names._this) {
2670 for (int address = firstadr; address < nextadr; address++) {
2671 VarSymbol sym = vardecls[address].sym;
2672 if (isFinalOrStrictUninitializedField(sym) && !sym.isStatic())
2673 letInit(tree.pos(), sym);
2674 }
2675 }
2676 }
2677 }
2678
2679 public void visitNewClass(JCNewClass tree) {
2680 scanExpr(tree.encl);
2681 scanExprs(tree.args);
2682 scan(tree.def);
2683 }
2684
2685 @Override
2686 public void visitLambda(JCLambda tree) {
2687 final Bits prevUninits = new Bits(uninits);
2688 final Bits prevUninitsTry = new Bits(uninitsTry);
2689 final Bits prevInits = new Bits(inits);
2690 int returnadrPrev = returnadr;
2691 int nextadrPrev = nextadr;
2692 ListBuffer<PendingExit> prevPending = pendingExits;
2726 }
2727
2728 public void visitAssert(JCAssert tree) {
2729 final Bits initsExit = new Bits(inits);
2730 final Bits uninitsExit = new Bits(uninits);
2731 scanCond(tree.cond);
2732 uninitsExit.andSet(uninitsWhenTrue);
2733 if (tree.detail != null) {
2734 inits.assign(initsWhenFalse);
2735 uninits.assign(uninitsWhenFalse);
2736 scanExpr(tree.detail);
2737 }
2738 inits.assign(initsExit);
2739 uninits.assign(uninitsExit);
2740 }
2741
2742 public void visitAssign(JCAssign tree) {
2743 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2744 scanExpr(tree.lhs);
2745 scanExpr(tree.rhs);
2746 letInit(tree.lhs, tree);
2747 }
2748
2749 // check fields accessed through this.<field> are definitely
2750 // assigned before reading their value
2751 public void visitSelect(JCFieldAccess tree) {
2752 super.visitSelect(tree);
2753 if (TreeInfo.isThisQualifier(tree.selected) &&
2754 tree.sym.kind == VAR) {
2755 checkInit(tree.pos(), (VarSymbol)tree.sym);
2756 }
2757 }
2758
2759 public void visitAssignop(JCAssignOp tree) {
2760 scanExpr(tree.lhs);
2761 scanExpr(tree.rhs);
2762 letInit(tree.lhs);
2763 }
2764
2765 public void visitUnary(JCUnary tree) {
2766 switch (tree.getTag()) {
|