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.Map;
31 import java.util.Map.Entry;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.Set;
35 import java.util.function.Consumer;
36
37 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
38 import com.sun.tools.javac.code.*;
39 import com.sun.tools.javac.code.Scope.WriteableScope;
40 import com.sun.tools.javac.resources.CompilerProperties.Errors;
41 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
42 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
43 import com.sun.tools.javac.tree.*;
44 import com.sun.tools.javac.util.*;
45 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
46 import com.sun.tools.javac.util.JCDiagnostic.Error;
47 import com.sun.tools.javac.util.JCDiagnostic.Warning;
48
49 import com.sun.tools.javac.code.Symbol.*;
198 * support for assigning to a final field via this.x.
199 *
200 * <p><b>This is NOT part of any supported API.
201 * If you write code that depends on this, you do so at your own risk.
202 * This code and its internal interfaces are subject to change or
203 * deletion without notice.</b>
204 */
205 public class Flow {
206 protected static final Context.Key<Flow> flowKey = new Context.Key<>();
207
208 private final Names names;
209 private final Log log;
210 private final Symtab syms;
211 private final Types types;
212 private final Check chk;
213 private TreeMaker make;
214 private final Resolve rs;
215 private final JCDiagnostic.Factory diags;
216 private Env<AttrContext> attrEnv;
217 private final Infer infer;
218
219 public static Flow instance(Context context) {
220 Flow instance = context.get(flowKey);
221 if (instance == null)
222 instance = new Flow(context);
223 return instance;
224 }
225
226 public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
227 new AliveAnalyzer().analyzeTree(env, make);
228 new AssignAnalyzer().analyzeTree(env, make);
229 new FlowAnalyzer().analyzeTree(env, make);
230 new CaptureAnalyzer().analyzeTree(env, make);
231 }
232
233 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
234 Log.DiagnosticHandler diagHandler = null;
235 //we need to disable diagnostics temporarily; the problem is that if
236 //a lambda expression contains e.g. an unreachable statement, an error
237 //message will be reported and will cause compilation to skip the flow analysis
322 this.errKey = errKey;
323 this.isFinal = isFinal;
324 }
325
326 boolean isFinal() {
327 return isFinal;
328 }
329 }
330
331 @SuppressWarnings("this-escape")
332 protected Flow(Context context) {
333 context.put(flowKey, this);
334 names = Names.instance(context);
335 log = Log.instance(context);
336 syms = Symtab.instance(context);
337 types = Types.instance(context);
338 chk = Check.instance(context);
339 infer = Infer.instance(context);
340 rs = Resolve.instance(context);
341 diags = JCDiagnostic.Factory.instance(context);
342 Source source = Source.instance(context);
343 }
344
345 /**
346 * Base visitor class for all visitors implementing dataflow analysis logic.
347 * This class define the shared logic for handling jumps (break/continue statements).
348 */
349 abstract static class BaseAnalyzer extends TreeScanner {
350
351 enum JumpKind {
352 BREAK(JCTree.Tag.BREAK) {
353 @Override
354 JCTree getTarget(JCTree tree) {
355 return ((JCBreak)tree).target;
356 }
357 },
358 CONTINUE(JCTree.Tag.CONTINUE) {
359 @Override
360 JCTree getTarget(JCTree tree) {
361 return ((JCContinue)tree).target;
362 }
459 }
460 }
461
462 public void visitPackageDef(JCPackageDecl tree) {
463 // Do nothing for PackageDecl
464 }
465
466 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
467 if (swtch.hasTag(SWITCH_EXPRESSION)) {
468 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
469 .setType(swtch.type));
470 brk.target = swtch;
471 scan(brk);
472 } else {
473 JCBreak brk = make.at(Position.NOPOS).Break(null);
474 brk.target = swtch;
475 scan(brk);
476 }
477 }
478
479 // Do something with all static or non-static field initializers and initialization blocks.
480 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
481 if (classDef == initScanClass) // avoid infinite loops
482 return;
483 JCClassDecl initScanClassPrev = initScanClass;
484 initScanClass = classDef;
485 try {
486 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
487 JCTree def = defs.head;
488
489 // Don't recurse into nested classes
490 if (def.hasTag(CLASSDEF))
491 continue;
492
493 /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
494 * represented in the symbol but not in the tree modifiers as they were not originally in the source
495 * code
496 */
497 boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
498 if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic))
499 handler.accept(def);
500 }
501 } finally {
502 initScanClass = initScanClassPrev;
503 }
504 }
505 }
506
507 /**
508 * This pass implements the first step of the dataflow analysis, namely
509 * the liveness analysis check. This checks that every statement is reachable.
510 * The output of this analysis pass are used by other analyzers. This analyzer
511 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
512 */
513 class AliveAnalyzer extends BaseAnalyzer {
514
515 /** A flag that indicates whether the last statement could
516 * complete normally.
517 */
518 private Liveness alive;
519
2124 }
2125
2126 @Override
2127 public void resolveJump() {
2128 inits.andSet(exit_inits);
2129 uninits.andSet(exit_uninits);
2130 }
2131 }
2132
2133 public AssignAnalyzer() {
2134 this.inits = new Bits();
2135 uninits = new Bits();
2136 uninitsTry = new Bits();
2137 initsWhenTrue = new Bits(true);
2138 initsWhenFalse = new Bits(true);
2139 uninitsWhenTrue = new Bits(true);
2140 uninitsWhenFalse = new Bits(true);
2141 }
2142
2143 private boolean isConstructor;
2144
2145 @Override
2146 protected void markDead() {
2147 inits.inclRange(returnadr, nextadr);
2148 uninits.inclRange(returnadr, nextadr);
2149 }
2150
2151 /*-------------- Processing variables ----------------------*/
2152
2153 /** Do we need to track init/uninit state of this symbol?
2154 * I.e. is symbol either a local or a blank final variable?
2155 */
2156 protected boolean trackable(VarSymbol sym) {
2157 return
2158 sym.pos >= startPos &&
2159 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2160 isFinalUninitializedField(sym)));
2161 }
2162
2163 boolean isFinalUninitializedField(VarSymbol sym) {
2164 return sym.owner.kind == TYP &&
2165 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
2166 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2167 }
2168
2169 /** Initialize new trackable variable by setting its address field
2170 * to the next available sequence number and entering it under that
2171 * index into the vars array.
2172 */
2173 void newVar(JCVariableDecl varDecl) {
2174 VarSymbol sym = varDecl.sym;
2175 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2176 if ((sym.flags() & FINAL) == 0) {
2177 sym.flags_field |= EFFECTIVELY_FINAL;
2178 }
2179 sym.adr = nextadr;
2180 vardecls[nextadr] = varDecl;
2181 inits.excl(nextadr);
2182 uninits.incl(nextadr);
2183 nextadr++;
2184 }
2185
2217 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2218 }
2219 }
2220 //where
2221 void uninit(VarSymbol sym) {
2222 if (!inits.isMember(sym.adr)) {
2223 // reachable assignment
2224 uninits.excl(sym.adr);
2225 uninitsTry.excl(sym.adr);
2226 } else {
2227 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2228 uninits.excl(sym.adr);
2229 }
2230 }
2231
2232 /** If tree is either a simple name or of the form this.name or
2233 * C.this.name, and tree represents a trackable variable,
2234 * record an initialization of the variable.
2235 */
2236 void letInit(JCTree tree) {
2237 tree = TreeInfo.skipParens(tree);
2238 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2239 Symbol sym = TreeInfo.symbol(tree);
2240 if (sym.kind == VAR) {
2241 letInit(tree.pos(), (VarSymbol)sym);
2242 }
2243 }
2244 }
2245
2246 /** Check that trackable variable is initialized.
2247 */
2248 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2249 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2250 }
2251
2252 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2253 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2254 trackable(sym) &&
2255 !inits.isMember(sym.adr) &&
2256 (sym.flags_field & CLASH) == 0) {
2257 log.error(pos, errkey);
2258 inits.incl(sym.adr);
2259 }
2260 }
2261
2262 /** Utility method to reset several Bits instances.
2263 */
2264 private void resetBits(Bits... bits) {
2265 for (Bits b : bits) {
2266 b.reset();
2267 }
2268 }
2269
2270 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2271 */
2272 void split(boolean setToNull) {
2273 initsWhenFalse.assign(inits);
2274 uninitsWhenFalse.assign(uninits);
2275 initsWhenTrue.assign(inits);
2276 uninitsWhenTrue.assign(uninits);
2277 if (setToNull) {
2426
2427 public void visitMethodDef(JCMethodDecl tree) {
2428 if (tree.body == null) {
2429 return;
2430 }
2431
2432 /* MemberEnter can generate synthetic methods ignore them
2433 */
2434 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2435 return;
2436 }
2437
2438 final Bits initsPrev = new Bits(inits);
2439 final Bits uninitsPrev = new Bits(uninits);
2440 int nextadrPrev = nextadr;
2441 int firstadrPrev = firstadr;
2442 int returnadrPrev = returnadr;
2443
2444 Assert.check(pendingExits.isEmpty());
2445 boolean isConstructorPrev = isConstructor;
2446 try {
2447 isConstructor = TreeInfo.isConstructor(tree);
2448
2449 // We only track field initialization inside constructors
2450 if (!isConstructor) {
2451 firstadr = nextadr;
2452 }
2453
2454 // Mark all method parameters as DA
2455 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2456 JCVariableDecl def = l.head;
2457 scan(def);
2458 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2459 /* If we are executing the code from Gen, then there can be
2460 * synthetic or mandated variables, ignore them.
2461 */
2462 initParam(def);
2463 }
2464 // else we are in an instance initializer block;
2465 // leave caught unchanged.
2466 scan(tree.body);
2467
2468 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2469 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2470 if (isConstructor) {
2471 boolean isSynthesized = (tree.sym.flags() &
2472 GENERATEDCONSTR) != 0;
2473 for (int i = firstadr; i < nextadr; i++) {
2474 JCVariableDecl vardecl = vardecls[i];
2475 VarSymbol var = vardecl.sym;
2476 if (var.owner == classDef.sym && !var.isStatic()) {
2477 // choose the diagnostic position based on whether
2478 // the ctor is default(synthesized) or not
2479 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2480 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2481 var, Errors.VarNotInitializedInDefaultConstructor(var));
2482 } else if (isCompactOrGeneratedRecordConstructor) {
2483 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2484 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2485 var.owner.kind == TYP;
2486 if (isInstanceRecordField) {
2487 boolean notInitialized = !inits.isMember(var.adr);
2488 if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2489 /* this way we indicate Lower that it should generate an initialization for this field
2493 } else {
2494 checkInit(TreeInfo.diagEndPos(tree.body), var);
2495 }
2496 } else {
2497 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2498 }
2499 } else {
2500 checkInit(TreeInfo.diagEndPos(tree.body), var);
2501 }
2502 }
2503 }
2504 }
2505 clearPendingExits(true);
2506 } finally {
2507 inits.assign(initsPrev);
2508 uninits.assign(uninitsPrev);
2509 nextadr = nextadrPrev;
2510 firstadr = firstadrPrev;
2511 returnadr = returnadrPrev;
2512 isConstructor = isConstructorPrev;
2513 }
2514 }
2515
2516 private void clearPendingExits(boolean inMethod) {
2517 List<PendingExit> exits = pendingExits.toList();
2518 pendingExits = new ListBuffer<>();
2519 while (exits.nonEmpty()) {
2520 PendingExit exit = exits.head;
2521 exits = exits.tail;
2522 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2523 log.hasErrorOn(exit.tree.pos()),
2524 exit.tree);
2525 if (inMethod && isConstructor) {
2526 Assert.check(exit instanceof AssignPendingExit);
2527 inits.assign(((AssignPendingExit) exit).exit_inits);
2528 for (int i = firstadr; i < nextadr; i++) {
2529 checkInit(exit.tree.pos(), vardecls[i].sym);
2530 }
2531 }
2532 }
2533 }
2534 protected void initParam(JCVariableDecl def) {
2535 inits.incl(def.sym.adr);
2952 }
2953 }
2954
2955 @Override
2956 public void visitContinue(JCContinue tree) {
2957 recordExit(new AssignPendingExit(tree, inits, uninits));
2958 }
2959
2960 @Override
2961 public void visitReturn(JCReturn tree) {
2962 scanExpr(tree.expr);
2963 recordExit(new AssignPendingExit(tree, inits, uninits));
2964 }
2965
2966 public void visitThrow(JCThrow tree) {
2967 scanExpr(tree.expr);
2968 markDead();
2969 }
2970
2971 public void visitApply(JCMethodInvocation tree) {
2972 scanExpr(tree.meth);
2973 scanExprs(tree.args);
2974
2975 // Handle superclass constructor invocations
2976 if (isConstructor) {
2977
2978 // If super(): at this point all initialization blocks will execute
2979 Name name = TreeInfo.name(tree.meth);
2980 if (name == names._super) {
2981 forEachInitializer(classDef, false, def -> {
2982 scan(def);
2983 clearPendingExits(false);
2984 });
2985 }
2986
2987 // If this(): at this point all final uninitialized fields will get initialized
2988 else if (name == names._this) {
2989 for (int address = firstadr; address < nextadr; address++) {
2990 VarSymbol sym = vardecls[address].sym;
2991 if (isFinalUninitializedField(sym) && !sym.isStatic())
2992 letInit(tree.pos(), sym);
2993 }
2994 }
2995 }
2996 }
2997
2998 public void visitNewClass(JCNewClass tree) {
2999 scanExpr(tree.encl);
3000 scanExprs(tree.args);
3001 scan(tree.def);
3002 }
3003
3004 @Override
3005 public void visitLambda(JCLambda tree) {
3006 final Bits prevUninits = new Bits(uninits);
3007 final Bits prevUninitsTry = new Bits(uninitsTry);
3008 final Bits prevInits = new Bits(inits);
3009 int returnadrPrev = returnadr;
3010 int nextadrPrev = nextadr;
3011 ListBuffer<PendingExit> prevPending = pendingExits;
3045 }
3046
3047 public void visitAssert(JCAssert tree) {
3048 final Bits initsExit = new Bits(inits);
3049 final Bits uninitsExit = new Bits(uninits);
3050 scanCond(tree.cond);
3051 uninitsExit.andSet(uninitsWhenTrue);
3052 if (tree.detail != null) {
3053 inits.assign(initsWhenFalse);
3054 uninits.assign(uninitsWhenFalse);
3055 scanExpr(tree.detail);
3056 }
3057 inits.assign(initsExit);
3058 uninits.assign(uninitsExit);
3059 }
3060
3061 public void visitAssign(JCAssign tree) {
3062 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3063 scanExpr(tree.lhs);
3064 scanExpr(tree.rhs);
3065 letInit(tree.lhs);
3066 }
3067
3068 // check fields accessed through this.<field> are definitely
3069 // assigned before reading their value
3070 public void visitSelect(JCFieldAccess tree) {
3071 super.visitSelect(tree);
3072 if (TreeInfo.isThisQualifier(tree.selected) &&
3073 tree.sym.kind == VAR) {
3074 checkInit(tree.pos(), (VarSymbol)tree.sym);
3075 }
3076 }
3077
3078 public void visitAssignop(JCAssignOp tree) {
3079 scanExpr(tree.lhs);
3080 scanExpr(tree.rhs);
3081 letInit(tree.lhs);
3082 }
3083
3084 public void visitUnary(JCUnary tree) {
3085 switch (tree.getTag()) {
|
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.LinkedHashSet;
31 import java.util.Map;
32 import java.util.Map.Entry;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Set;
36 import java.util.function.Consumer;
37
38 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
39 import com.sun.tools.javac.code.*;
40 import com.sun.tools.javac.code.Scope.WriteableScope;
41 import com.sun.tools.javac.resources.CompilerProperties.Errors;
42 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
43 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
44 import com.sun.tools.javac.tree.*;
45 import com.sun.tools.javac.util.*;
46 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
47 import com.sun.tools.javac.util.JCDiagnostic.Error;
48 import com.sun.tools.javac.util.JCDiagnostic.Warning;
49
50 import com.sun.tools.javac.code.Symbol.*;
199 * support for assigning to a final field via this.x.
200 *
201 * <p><b>This is NOT part of any supported API.
202 * If you write code that depends on this, you do so at your own risk.
203 * This code and its internal interfaces are subject to change or
204 * deletion without notice.</b>
205 */
206 public class Flow {
207 protected static final Context.Key<Flow> flowKey = new Context.Key<>();
208
209 private final Names names;
210 private final Log log;
211 private final Symtab syms;
212 private final Types types;
213 private final Check chk;
214 private TreeMaker make;
215 private final Resolve rs;
216 private final JCDiagnostic.Factory diags;
217 private Env<AttrContext> attrEnv;
218 private final Infer infer;
219 private final UnsetFieldsInfo unsetFieldsInfo;
220 private final boolean allowValueClasses;
221
222 public static Flow instance(Context context) {
223 Flow instance = context.get(flowKey);
224 if (instance == null)
225 instance = new Flow(context);
226 return instance;
227 }
228
229 public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
230 new AliveAnalyzer().analyzeTree(env, make);
231 new AssignAnalyzer().analyzeTree(env, make);
232 new FlowAnalyzer().analyzeTree(env, make);
233 new CaptureAnalyzer().analyzeTree(env, make);
234 }
235
236 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
237 Log.DiagnosticHandler diagHandler = null;
238 //we need to disable diagnostics temporarily; the problem is that if
239 //a lambda expression contains e.g. an unreachable statement, an error
240 //message will be reported and will cause compilation to skip the flow analysis
325 this.errKey = errKey;
326 this.isFinal = isFinal;
327 }
328
329 boolean isFinal() {
330 return isFinal;
331 }
332 }
333
334 @SuppressWarnings("this-escape")
335 protected Flow(Context context) {
336 context.put(flowKey, this);
337 names = Names.instance(context);
338 log = Log.instance(context);
339 syms = Symtab.instance(context);
340 types = Types.instance(context);
341 chk = Check.instance(context);
342 infer = Infer.instance(context);
343 rs = Resolve.instance(context);
344 diags = JCDiagnostic.Factory.instance(context);
345 unsetFieldsInfo = UnsetFieldsInfo.instance(context);
346 Preview preview = Preview.instance(context);
347 Source source = Source.instance(context);
348 allowValueClasses = (!preview.isPreview(Source.Feature.VALUE_CLASSES) || preview.isEnabled()) &&
349 Source.Feature.VALUE_CLASSES.allowedInSource(source);
350 }
351
352 /**
353 * Base visitor class for all visitors implementing dataflow analysis logic.
354 * This class define the shared logic for handling jumps (break/continue statements).
355 */
356 abstract static class BaseAnalyzer extends TreeScanner {
357
358 enum JumpKind {
359 BREAK(JCTree.Tag.BREAK) {
360 @Override
361 JCTree getTarget(JCTree tree) {
362 return ((JCBreak)tree).target;
363 }
364 },
365 CONTINUE(JCTree.Tag.CONTINUE) {
366 @Override
367 JCTree getTarget(JCTree tree) {
368 return ((JCContinue)tree).target;
369 }
466 }
467 }
468
469 public void visitPackageDef(JCPackageDecl tree) {
470 // Do nothing for PackageDecl
471 }
472
473 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
474 if (swtch.hasTag(SWITCH_EXPRESSION)) {
475 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
476 .setType(swtch.type));
477 brk.target = swtch;
478 scan(brk);
479 } else {
480 JCBreak brk = make.at(Position.NOPOS).Break(null);
481 brk.target = swtch;
482 scan(brk);
483 }
484 }
485
486 // Do something with static or non-static field initializers and initialization blocks.
487 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
488 forEachInitializer(classDef, isStatic, false, handler);
489 }
490
491 /* Do something with static or non-static field initializers and initialization blocks.
492 * the `earlyOnly` argument will determine if we will deal or not with early variable instance
493 * initializers we want to process only those before a super() invocation and ignore them after
494 * it.
495 */
496 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, boolean earlyOnly,
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 // Don't recurse into nested classes
507 if (def.hasTag(CLASSDEF))
508 continue;
509
510 /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
511 * represented in the symbol but not in the tree modifiers as they were not originally in the source
512 * code
513 */
514 boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
515 if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic)) {
516 if (def instanceof JCVariableDecl varDecl) {
517 boolean isEarly = varDecl.init != null &&
518 varDecl.sym.isStrict() &&
519 !varDecl.sym.isStatic();
520 if (isEarly == earlyOnly) {
521 handler.accept(def);
522 }
523 } else if (!earlyOnly) {
524 handler.accept(def);
525 }
526 }
527 }
528 } finally {
529 initScanClass = initScanClassPrev;
530 }
531 }
532 }
533
534 /**
535 * This pass implements the first step of the dataflow analysis, namely
536 * the liveness analysis check. This checks that every statement is reachable.
537 * The output of this analysis pass are used by other analyzers. This analyzer
538 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
539 */
540 class AliveAnalyzer extends BaseAnalyzer {
541
542 /** A flag that indicates whether the last statement could
543 * complete normally.
544 */
545 private Liveness alive;
546
2151 }
2152
2153 @Override
2154 public void resolveJump() {
2155 inits.andSet(exit_inits);
2156 uninits.andSet(exit_uninits);
2157 }
2158 }
2159
2160 public AssignAnalyzer() {
2161 this.inits = new Bits();
2162 uninits = new Bits();
2163 uninitsTry = new Bits();
2164 initsWhenTrue = new Bits(true);
2165 initsWhenFalse = new Bits(true);
2166 uninitsWhenTrue = new Bits(true);
2167 uninitsWhenFalse = new Bits(true);
2168 }
2169
2170 private boolean isConstructor;
2171 private boolean isCompactOrGeneratedRecordConstructor;
2172
2173 @Override
2174 protected void markDead() {
2175 inits.inclRange(returnadr, nextadr);
2176 uninits.inclRange(returnadr, nextadr);
2177 }
2178
2179 /*-------------- Processing variables ----------------------*/
2180
2181 /** Do we need to track init/uninit state of this symbol?
2182 * I.e. is symbol either a local or a blank final variable?
2183 */
2184 protected boolean trackable(VarSymbol sym) {
2185 return
2186 sym.pos >= startPos &&
2187 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2188 isFinalOrStrictUninitializedField(sym)));
2189 }
2190
2191 boolean isFinalOrStrictUninitializedField(VarSymbol sym) {
2192 return sym.owner.kind == TYP &&
2193 (((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL ||
2194 (sym.flags() & (STRICT | HASINIT | PARAMETER)) == STRICT) &&
2195 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2196 }
2197
2198 /** Initialize new trackable variable by setting its address field
2199 * to the next available sequence number and entering it under that
2200 * index into the vars array.
2201 */
2202 void newVar(JCVariableDecl varDecl) {
2203 VarSymbol sym = varDecl.sym;
2204 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2205 if ((sym.flags() & FINAL) == 0) {
2206 sym.flags_field |= EFFECTIVELY_FINAL;
2207 }
2208 sym.adr = nextadr;
2209 vardecls[nextadr] = varDecl;
2210 inits.excl(nextadr);
2211 uninits.incl(nextadr);
2212 nextadr++;
2213 }
2214
2246 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2247 }
2248 }
2249 //where
2250 void uninit(VarSymbol sym) {
2251 if (!inits.isMember(sym.adr)) {
2252 // reachable assignment
2253 uninits.excl(sym.adr);
2254 uninitsTry.excl(sym.adr);
2255 } else {
2256 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2257 uninits.excl(sym.adr);
2258 }
2259 }
2260
2261 /** If tree is either a simple name or of the form this.name or
2262 * C.this.name, and tree represents a trackable variable,
2263 * record an initialization of the variable.
2264 */
2265 void letInit(JCTree tree) {
2266 letInit(tree, (JCAssign) null);
2267 }
2268
2269 void letInit(JCTree tree, JCAssign assign) {
2270 tree = TreeInfo.skipParens(tree);
2271 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2272 Symbol sym = TreeInfo.symbol(tree);
2273 if (sym.kind == VAR) {
2274 letInit(tree.pos(), (VarSymbol)sym);
2275 if (isConstructor && sym.isStrict()) {
2276 /* we are initializing a strict field inside of a constructor, we now need to find which fields
2277 * haven't been initialized yet
2278 */
2279 unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, assign != null ? assign : tree, findUninitStrictFields());
2280 }
2281 }
2282 }
2283 }
2284
2285 /** Check that trackable variable is initialized.
2286 */
2287 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2288 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2289 }
2290
2291 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2292 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2293 trackable(sym) &&
2294 !inits.isMember(sym.adr) &&
2295 (sym.flags_field & CLASH) == 0) {
2296 log.error(pos, errkey);
2297 inits.incl(sym.adr);
2298 }
2299 }
2300
2301 /** Utility method to reset several Bits instances.
2302 */
2303 private void resetBits(Bits... bits) {
2304 for (Bits b : bits) {
2305 b.reset();
2306 }
2307 }
2308
2309 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2310 */
2311 void split(boolean setToNull) {
2312 initsWhenFalse.assign(inits);
2313 uninitsWhenFalse.assign(uninits);
2314 initsWhenTrue.assign(inits);
2315 uninitsWhenTrue.assign(uninits);
2316 if (setToNull) {
2465
2466 public void visitMethodDef(JCMethodDecl tree) {
2467 if (tree.body == null) {
2468 return;
2469 }
2470
2471 /* MemberEnter can generate synthetic methods ignore them
2472 */
2473 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2474 return;
2475 }
2476
2477 final Bits initsPrev = new Bits(inits);
2478 final Bits uninitsPrev = new Bits(uninits);
2479 int nextadrPrev = nextadr;
2480 int firstadrPrev = firstadr;
2481 int returnadrPrev = returnadr;
2482
2483 Assert.check(pendingExits.isEmpty());
2484 boolean isConstructorPrev = isConstructor;
2485 boolean isCompactOrGeneratedRecordConstructorPrev = isCompactOrGeneratedRecordConstructor;
2486 try {
2487 isConstructor = TreeInfo.isConstructor(tree);
2488 isCompactOrGeneratedRecordConstructor = isConstructor && ((tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2489 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD));
2490
2491 // We only track field initialization inside constructors
2492 if (!isConstructor) {
2493 firstadr = nextadr;
2494 }
2495
2496 // Mark all method parameters as DA
2497 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2498 JCVariableDecl def = l.head;
2499 scan(def);
2500 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2501 /* If we are executing the code from Gen, then there can be
2502 * synthetic or mandated variables, ignore them.
2503 */
2504 initParam(def);
2505 }
2506 if (isConstructor) {
2507 Set<VarSymbol> unsetFields = findUninitStrictFields();
2508 if (unsetFields != null && !unsetFields.isEmpty()) {
2509 unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
2510 }
2511 }
2512
2513 // else we are in an instance initializer block;
2514 // leave caught unchanged.
2515 scan(tree.body);
2516
2517 if (isConstructor) {
2518 boolean isSynthesized = (tree.sym.flags() &
2519 GENERATEDCONSTR) != 0;
2520 for (int i = firstadr; i < nextadr; i++) {
2521 JCVariableDecl vardecl = vardecls[i];
2522 VarSymbol var = vardecl.sym;
2523 if (var.owner == classDef.sym && !var.isStatic()) {
2524 // choose the diagnostic position based on whether
2525 // the ctor is default(synthesized) or not
2526 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2527 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2528 var, Errors.VarNotInitializedInDefaultConstructor(var));
2529 } else if (isCompactOrGeneratedRecordConstructor) {
2530 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2531 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2532 var.owner.kind == TYP;
2533 if (isInstanceRecordField) {
2534 boolean notInitialized = !inits.isMember(var.adr);
2535 if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2536 /* this way we indicate Lower that it should generate an initialization for this field
2540 } else {
2541 checkInit(TreeInfo.diagEndPos(tree.body), var);
2542 }
2543 } else {
2544 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2545 }
2546 } else {
2547 checkInit(TreeInfo.diagEndPos(tree.body), var);
2548 }
2549 }
2550 }
2551 }
2552 clearPendingExits(true);
2553 } finally {
2554 inits.assign(initsPrev);
2555 uninits.assign(uninitsPrev);
2556 nextadr = nextadrPrev;
2557 firstadr = firstadrPrev;
2558 returnadr = returnadrPrev;
2559 isConstructor = isConstructorPrev;
2560 isCompactOrGeneratedRecordConstructor = isCompactOrGeneratedRecordConstructorPrev;
2561 }
2562 }
2563
2564 Set<VarSymbol> findUninitStrictFields() {
2565 Set<VarSymbol> unsetFields = new LinkedHashSet<>();
2566 for (int i = uninits.nextBit(0); i >= 0; i = uninits.nextBit(i + 1)) {
2567 JCVariableDecl variableDecl = vardecls[i];
2568 if (variableDecl.sym.isStrict()) {
2569 unsetFields.add(variableDecl.sym);
2570 }
2571 }
2572 return unsetFields;
2573 }
2574
2575 private void clearPendingExits(boolean inMethod) {
2576 List<PendingExit> exits = pendingExits.toList();
2577 pendingExits = new ListBuffer<>();
2578 while (exits.nonEmpty()) {
2579 PendingExit exit = exits.head;
2580 exits = exits.tail;
2581 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2582 log.hasErrorOn(exit.tree.pos()),
2583 exit.tree);
2584 if (inMethod && isConstructor) {
2585 Assert.check(exit instanceof AssignPendingExit);
2586 inits.assign(((AssignPendingExit) exit).exit_inits);
2587 for (int i = firstadr; i < nextadr; i++) {
2588 checkInit(exit.tree.pos(), vardecls[i].sym);
2589 }
2590 }
2591 }
2592 }
2593 protected void initParam(JCVariableDecl def) {
2594 inits.incl(def.sym.adr);
3011 }
3012 }
3013
3014 @Override
3015 public void visitContinue(JCContinue tree) {
3016 recordExit(new AssignPendingExit(tree, inits, uninits));
3017 }
3018
3019 @Override
3020 public void visitReturn(JCReturn tree) {
3021 scanExpr(tree.expr);
3022 recordExit(new AssignPendingExit(tree, inits, uninits));
3023 }
3024
3025 public void visitThrow(JCThrow tree) {
3026 scanExpr(tree.expr);
3027 markDead();
3028 }
3029
3030 public void visitApply(JCMethodInvocation tree) {
3031 Name name = TreeInfo.name(tree.meth);
3032 // let's process early initializers
3033 if (name == names._super) {
3034 forEachInitializer(classDef, false, true, def -> {
3035 scan(def);
3036 clearPendingExits(false);
3037 });
3038 }
3039 scanExpr(tree.meth);
3040 scanExprs(tree.args);
3041
3042 // Handle superclass constructor invocations
3043 if (isConstructor) {
3044
3045 // If super(): at this point all initialization blocks will execute
3046
3047 if (name == names._super) {
3048 // strict fields should have been initialized at this point
3049 for (int i = firstadr; i < nextadr; i++) {
3050 JCVariableDecl vardecl = vardecls[i];
3051 VarSymbol var = vardecl.sym;
3052 if (allowValueClasses && (var.owner == classDef.sym && !var.isStatic() && (var.isStrict() || ((var.flags_field & RECORD) != 0)) && !isCompactOrGeneratedRecordConstructor)) {
3053 checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
3054 }
3055 }
3056 forEachInitializer(classDef, false, def -> {
3057 scan(def);
3058 clearPendingExits(false);
3059 });
3060 }
3061
3062 // If this(): at this point all final uninitialized fields will get initialized
3063 else if (name == names._this) {
3064 for (int address = firstadr; address < nextadr; address++) {
3065 VarSymbol sym = vardecls[address].sym;
3066 if (isFinalOrStrictUninitializedField(sym) && !sym.isStatic())
3067 letInit(tree.pos(), sym);
3068 }
3069 }
3070 }
3071 }
3072
3073 public void visitNewClass(JCNewClass tree) {
3074 scanExpr(tree.encl);
3075 scanExprs(tree.args);
3076 scan(tree.def);
3077 }
3078
3079 @Override
3080 public void visitLambda(JCLambda tree) {
3081 final Bits prevUninits = new Bits(uninits);
3082 final Bits prevUninitsTry = new Bits(uninitsTry);
3083 final Bits prevInits = new Bits(inits);
3084 int returnadrPrev = returnadr;
3085 int nextadrPrev = nextadr;
3086 ListBuffer<PendingExit> prevPending = pendingExits;
3120 }
3121
3122 public void visitAssert(JCAssert tree) {
3123 final Bits initsExit = new Bits(inits);
3124 final Bits uninitsExit = new Bits(uninits);
3125 scanCond(tree.cond);
3126 uninitsExit.andSet(uninitsWhenTrue);
3127 if (tree.detail != null) {
3128 inits.assign(initsWhenFalse);
3129 uninits.assign(uninitsWhenFalse);
3130 scanExpr(tree.detail);
3131 }
3132 inits.assign(initsExit);
3133 uninits.assign(uninitsExit);
3134 }
3135
3136 public void visitAssign(JCAssign tree) {
3137 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3138 scanExpr(tree.lhs);
3139 scanExpr(tree.rhs);
3140 letInit(tree.lhs, tree);
3141 }
3142
3143 // check fields accessed through this.<field> are definitely
3144 // assigned before reading their value
3145 public void visitSelect(JCFieldAccess tree) {
3146 super.visitSelect(tree);
3147 if (TreeInfo.isThisQualifier(tree.selected) &&
3148 tree.sym.kind == VAR) {
3149 checkInit(tree.pos(), (VarSymbol)tree.sym);
3150 }
3151 }
3152
3153 public void visitAssignop(JCAssignOp tree) {
3154 scanExpr(tree.lhs);
3155 scanExpr(tree.rhs);
3156 letInit(tree.lhs);
3157 }
3158
3159 public void visitUnary(JCUnary tree) {
3160 switch (tree.getTag()) {
|