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.*;
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 Lint lint;
218 private final Infer infer;
219
220 public static Flow instance(Context context) {
221 Flow instance = context.get(flowKey);
222 if (instance == null)
223 instance = new Flow(context);
224 return instance;
225 }
226
227 public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
228 new AliveAnalyzer().analyzeTree(env, make);
229 new AssignAnalyzer().analyzeTree(env, make);
230 new FlowAnalyzer().analyzeTree(env, make);
231 new CaptureAnalyzer().analyzeTree(env, make);
232 }
233
234 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
235 Log.DiagnosticHandler diagHandler = null;
236 //we need to disable diagnostics temporarily; the problem is that if
237 //a lambda expression contains e.g. an unreachable statement, an error
238 //message will be reported and will cause compilation to skip the flow analysis
324 this.isFinal = isFinal;
325 }
326
327 boolean isFinal() {
328 return isFinal;
329 }
330 }
331
332 @SuppressWarnings("this-escape")
333 protected Flow(Context context) {
334 context.put(flowKey, this);
335 names = Names.instance(context);
336 log = Log.instance(context);
337 syms = Symtab.instance(context);
338 types = Types.instance(context);
339 chk = Check.instance(context);
340 lint = Lint.instance(context);
341 infer = Infer.instance(context);
342 rs = Resolve.instance(context);
343 diags = JCDiagnostic.Factory.instance(context);
344 Source source = Source.instance(context);
345 }
346
347 /**
348 * Base visitor class for all visitors implementing dataflow analysis logic.
349 * This class define the shared logic for handling jumps (break/continue statements).
350 */
351 abstract static class BaseAnalyzer extends TreeScanner {
352
353 enum JumpKind {
354 BREAK(JCTree.Tag.BREAK) {
355 @Override
356 JCTree getTarget(JCTree tree) {
357 return ((JCBreak)tree).target;
358 }
359 },
360 CONTINUE(JCTree.Tag.CONTINUE) {
361 @Override
362 JCTree getTarget(JCTree tree) {
363 return ((JCContinue)tree).target;
364 }
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 all static or non-static field initializers and initialization blocks.
482 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
483 if (classDef == initScanClass) // avoid infinite loops
484 return;
485 JCClassDecl initScanClassPrev = initScanClass;
486 initScanClass = classDef;
487 try {
488 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
489 JCTree def = defs.head;
490
491 // Don't recurse into nested classes
492 if (def.hasTag(CLASSDEF))
493 continue;
494
495 /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
496 * represented in the symbol but not in the tree modifiers as they were not originally in the source
497 * code
498 */
499 boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
500 if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic))
501 handler.accept(def);
502 }
503 } finally {
504 initScanClass = initScanClassPrev;
505 }
506 }
507 }
508
509 /**
510 * This pass implements the first step of the dataflow analysis, namely
511 * the liveness analysis check. This checks that every statement is reachable.
512 * The output of this analysis pass are used by other analyzers. This analyzer
513 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
514 */
515 class AliveAnalyzer extends BaseAnalyzer {
516
517 /** A flag that indicates whether the last statement could
518 * complete normally.
519 */
520 private Liveness alive;
521
2160 }
2161
2162 @Override
2163 public void resolveJump() {
2164 inits.andSet(exit_inits);
2165 uninits.andSet(exit_uninits);
2166 }
2167 }
2168
2169 public AssignAnalyzer() {
2170 this.inits = new Bits();
2171 uninits = new Bits();
2172 uninitsTry = new Bits();
2173 initsWhenTrue = new Bits(true);
2174 initsWhenFalse = new Bits(true);
2175 uninitsWhenTrue = new Bits(true);
2176 uninitsWhenFalse = new Bits(true);
2177 }
2178
2179 private boolean isConstructor;
2180
2181 @Override
2182 protected void markDead() {
2183 inits.inclRange(returnadr, nextadr);
2184 uninits.inclRange(returnadr, nextadr);
2185 }
2186
2187 /*-------------- Processing variables ----------------------*/
2188
2189 /** Do we need to track init/uninit state of this symbol?
2190 * I.e. is symbol either a local or a blank final variable?
2191 */
2192 protected boolean trackable(VarSymbol sym) {
2193 return
2194 sym.pos >= startPos &&
2195 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2196 isFinalUninitializedField(sym)));
2197 }
2198
2199 boolean isFinalUninitializedField(VarSymbol sym) {
2200 return sym.owner.kind == TYP &&
2201 ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&
2202 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2203 }
2204
2205 /** Initialize new trackable variable by setting its address field
2206 * to the next available sequence number and entering it under that
2207 * index into the vars array.
2208 */
2209 void newVar(JCVariableDecl varDecl) {
2210 VarSymbol sym = varDecl.sym;
2211 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2212 if ((sym.flags() & FINAL) == 0) {
2213 sym.flags_field |= EFFECTIVELY_FINAL;
2214 }
2215 sym.adr = nextadr;
2216 vardecls[nextadr] = varDecl;
2217 inits.excl(nextadr);
2218 uninits.incl(nextadr);
2219 nextadr++;
2220 }
2221
2253 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2254 }
2255 }
2256 //where
2257 void uninit(VarSymbol sym) {
2258 if (!inits.isMember(sym.adr)) {
2259 // reachable assignment
2260 uninits.excl(sym.adr);
2261 uninitsTry.excl(sym.adr);
2262 } else {
2263 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2264 uninits.excl(sym.adr);
2265 }
2266 }
2267
2268 /** If tree is either a simple name or of the form this.name or
2269 * C.this.name, and tree represents a trackable variable,
2270 * record an initialization of the variable.
2271 */
2272 void letInit(JCTree tree) {
2273 tree = TreeInfo.skipParens(tree);
2274 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2275 Symbol sym = TreeInfo.symbol(tree);
2276 if (sym.kind == VAR) {
2277 letInit(tree.pos(), (VarSymbol)sym);
2278 }
2279 }
2280 }
2281
2282 /** Check that trackable variable is initialized.
2283 */
2284 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2285 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2286 }
2287
2288 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2289 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2290 trackable(sym) &&
2291 !inits.isMember(sym.adr) &&
2292 (sym.flags_field & CLASH) == 0) {
2293 log.error(pos, errkey);
2294 inits.incl(sym.adr);
2295 }
2296 }
2297
2298 /** Utility method to reset several Bits instances.
2299 */
2300 private void resetBits(Bits... bits) {
2301 for (Bits b : bits) {
2302 b.reset();
2303 }
2304 }
2305
2306 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2307 */
2308 void split(boolean setToNull) {
2309 initsWhenFalse.assign(inits);
2310 uninitsWhenFalse.assign(uninits);
2311 initsWhenTrue.assign(inits);
2312 uninitsWhenTrue.assign(uninits);
2313 if (setToNull) {
2471 return;
2472 }
2473
2474 /* MemberEnter can generate synthetic methods ignore them
2475 */
2476 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2477 return;
2478 }
2479
2480 Lint lintPrev = lint;
2481 lint = lint.augment(tree.sym);
2482 try {
2483 final Bits initsPrev = new Bits(inits);
2484 final Bits uninitsPrev = new Bits(uninits);
2485 int nextadrPrev = nextadr;
2486 int firstadrPrev = firstadr;
2487 int returnadrPrev = returnadr;
2488
2489 Assert.check(pendingExits.isEmpty());
2490 boolean isConstructorPrev = isConstructor;
2491 try {
2492 isConstructor = TreeInfo.isConstructor(tree);
2493
2494 // We only track field initialization inside constructors
2495 if (!isConstructor) {
2496 firstadr = nextadr;
2497 }
2498
2499 // Mark all method parameters as DA
2500 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2501 JCVariableDecl def = l.head;
2502 scan(def);
2503 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2504 /* If we are executing the code from Gen, then there can be
2505 * synthetic or mandated variables, ignore them.
2506 */
2507 initParam(def);
2508 }
2509 // else we are in an instance initializer block;
2510 // leave caught unchanged.
2511 scan(tree.body);
2512
2513 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2514 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2515 if (isConstructor) {
2516 boolean isSynthesized = (tree.sym.flags() &
2517 GENERATEDCONSTR) != 0;
2518 for (int i = firstadr; i < nextadr; i++) {
2519 JCVariableDecl vardecl = vardecls[i];
2520 VarSymbol var = vardecl.sym;
2521 if (var.owner == classDef.sym && !var.isStatic()) {
2522 // choose the diagnostic position based on whether
2523 // the ctor is default(synthesized) or not
2524 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2525 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2526 var, Errors.VarNotInitializedInDefaultConstructor(var));
2527 } else if (isCompactOrGeneratedRecordConstructor) {
2528 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2529 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2530 var.owner.kind == TYP;
2531 if (isInstanceRecordField) {
2532 boolean notInitialized = !inits.isMember(var.adr);
2533 if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2534 /* this way we indicate Lower that it should generate an initialization for this field
2538 } else {
2539 checkInit(TreeInfo.diagEndPos(tree.body), var);
2540 }
2541 } else {
2542 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2543 }
2544 } else {
2545 checkInit(TreeInfo.diagEndPos(tree.body), var);
2546 }
2547 }
2548 }
2549 }
2550 clearPendingExits(true);
2551 } finally {
2552 inits.assign(initsPrev);
2553 uninits.assign(uninitsPrev);
2554 nextadr = nextadrPrev;
2555 firstadr = firstadrPrev;
2556 returnadr = returnadrPrev;
2557 isConstructor = isConstructorPrev;
2558 }
2559 } finally {
2560 lint = lintPrev;
2561 }
2562 }
2563
2564 private void clearPendingExits(boolean inMethod) {
2565 List<PendingExit> exits = pendingExits.toList();
2566 pendingExits = new ListBuffer<>();
2567 while (exits.nonEmpty()) {
2568 PendingExit exit = exits.head;
2569 exits = exits.tail;
2570 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2571 log.hasErrorOn(exit.tree.pos()),
2572 exit.tree);
2573 if (inMethod && isConstructor) {
2574 Assert.check(exit instanceof AssignPendingExit);
2575 inits.assign(((AssignPendingExit) exit).exit_inits);
2576 for (int i = firstadr; i < nextadr; i++) {
2577 checkInit(exit.tree.pos(), vardecls[i].sym);
2578 }
2579 }
2580 }
2581 }
2582 protected void initParam(JCVariableDecl def) {
2583 inits.incl(def.sym.adr);
3007 }
3008 }
3009
3010 @Override
3011 public void visitContinue(JCContinue tree) {
3012 recordExit(new AssignPendingExit(tree, inits, uninits));
3013 }
3014
3015 @Override
3016 public void visitReturn(JCReturn tree) {
3017 scanExpr(tree.expr);
3018 recordExit(new AssignPendingExit(tree, inits, uninits));
3019 }
3020
3021 public void visitThrow(JCThrow tree) {
3022 scanExpr(tree.expr);
3023 markDead();
3024 }
3025
3026 public void visitApply(JCMethodInvocation tree) {
3027 scanExpr(tree.meth);
3028 scanExprs(tree.args);
3029
3030 // Handle superclass constructor invocations
3031 if (isConstructor) {
3032
3033 // If super(): at this point all initialization blocks will execute
3034 Name name = TreeInfo.name(tree.meth);
3035 if (name == names._super) {
3036 forEachInitializer(classDef, false, def -> {
3037 scan(def);
3038 clearPendingExits(false);
3039 });
3040 }
3041
3042 // If this(): at this point all final uninitialized fields will get initialized
3043 else if (name == names._this) {
3044 for (int address = firstadr; address < nextadr; address++) {
3045 VarSymbol sym = vardecls[address].sym;
3046 if (isFinalUninitializedField(sym) && !sym.isStatic())
3047 letInit(tree.pos(), sym);
3048 }
3049 }
3050 }
3051 }
3052
3053 public void visitNewClass(JCNewClass tree) {
3054 scanExpr(tree.encl);
3055 scanExprs(tree.args);
3056 scan(tree.def);
3057 }
3058
3059 @Override
3060 public void visitLambda(JCLambda tree) {
3061 final Bits prevUninits = new Bits(uninits);
3062 final Bits prevUninitsTry = new Bits(uninitsTry);
3063 final Bits prevInits = new Bits(inits);
3064 int returnadrPrev = returnadr;
3065 int nextadrPrev = nextadr;
3066 ListBuffer<PendingExit> prevPending = pendingExits;
3100 }
3101
3102 public void visitAssert(JCAssert tree) {
3103 final Bits initsExit = new Bits(inits);
3104 final Bits uninitsExit = new Bits(uninits);
3105 scanCond(tree.cond);
3106 uninitsExit.andSet(uninitsWhenTrue);
3107 if (tree.detail != null) {
3108 inits.assign(initsWhenFalse);
3109 uninits.assign(uninitsWhenFalse);
3110 scanExpr(tree.detail);
3111 }
3112 inits.assign(initsExit);
3113 uninits.assign(uninitsExit);
3114 }
3115
3116 public void visitAssign(JCAssign tree) {
3117 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3118 scanExpr(tree.lhs);
3119 scanExpr(tree.rhs);
3120 letInit(tree.lhs);
3121 }
3122
3123 // check fields accessed through this.<field> are definitely
3124 // assigned before reading their value
3125 public void visitSelect(JCFieldAccess tree) {
3126 super.visitSelect(tree);
3127 if (TreeInfo.isThisQualifier(tree.selected) &&
3128 tree.sym.kind == VAR) {
3129 checkInit(tree.pos(), (VarSymbol)tree.sym);
3130 }
3131 }
3132
3133 public void visitAssignop(JCAssignOp tree) {
3134 scanExpr(tree.lhs);
3135 scanExpr(tree.rhs);
3136 letInit(tree.lhs);
3137 }
3138
3139 public void visitUnary(JCUnary tree) {
3140 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.*;
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 Lint lint;
219 private final Infer infer;
220 private final UnsetFieldsInfo unsetFieldsInfo;
221 private final boolean allowValueClasses;
222
223 public static Flow instance(Context context) {
224 Flow instance = context.get(flowKey);
225 if (instance == null)
226 instance = new Flow(context);
227 return instance;
228 }
229
230 public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
231 new AliveAnalyzer().analyzeTree(env, make);
232 new AssignAnalyzer().analyzeTree(env, make);
233 new FlowAnalyzer().analyzeTree(env, make);
234 new CaptureAnalyzer().analyzeTree(env, make);
235 }
236
237 public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
238 Log.DiagnosticHandler diagHandler = null;
239 //we need to disable diagnostics temporarily; the problem is that if
240 //a lambda expression contains e.g. an unreachable statement, an error
241 //message will be reported and will cause compilation to skip the flow analysis
327 this.isFinal = isFinal;
328 }
329
330 boolean isFinal() {
331 return isFinal;
332 }
333 }
334
335 @SuppressWarnings("this-escape")
336 protected Flow(Context context) {
337 context.put(flowKey, this);
338 names = Names.instance(context);
339 log = Log.instance(context);
340 syms = Symtab.instance(context);
341 types = Types.instance(context);
342 chk = Check.instance(context);
343 lint = Lint.instance(context);
344 infer = Infer.instance(context);
345 rs = Resolve.instance(context);
346 diags = JCDiagnostic.Factory.instance(context);
347 unsetFieldsInfo = UnsetFieldsInfo.instance(context);
348 Preview preview = Preview.instance(context);
349 Source source = Source.instance(context);
350 allowValueClasses = (!preview.isPreview(Source.Feature.VALUE_CLASSES) || preview.isEnabled()) &&
351 Source.Feature.VALUE_CLASSES.allowedInSource(source);
352 }
353
354 /**
355 * Base visitor class for all visitors implementing dataflow analysis logic.
356 * This class define the shared logic for handling jumps (break/continue statements).
357 */
358 abstract static class BaseAnalyzer extends TreeScanner {
359
360 enum JumpKind {
361 BREAK(JCTree.Tag.BREAK) {
362 @Override
363 JCTree getTarget(JCTree tree) {
364 return ((JCBreak)tree).target;
365 }
366 },
367 CONTINUE(JCTree.Tag.CONTINUE) {
368 @Override
369 JCTree getTarget(JCTree tree) {
370 return ((JCContinue)tree).target;
371 }
468 }
469 }
470
471 public void visitPackageDef(JCPackageDecl tree) {
472 // Do nothing for PackageDecl
473 }
474
475 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
476 if (swtch.hasTag(SWITCH_EXPRESSION)) {
477 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
478 .setType(swtch.type));
479 brk.target = swtch;
480 scan(brk);
481 } else {
482 JCBreak brk = make.at(Position.NOPOS).Break(null);
483 brk.target = swtch;
484 scan(brk);
485 }
486 }
487
488 // Do something with static or non-static field initializers and initialization blocks.
489 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
490 forEachInitializer(classDef, isStatic, false, handler);
491 }
492
493 /* Do something with static or non-static field initializers and initialization blocks.
494 * the `earlyOnly` argument will determine if we will deal or not with early variable instance
495 * initializers we want to process only those before a super() invocation and ignore them after
496 * it.
497 */
498 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, boolean earlyOnly,
499 Consumer<? super JCTree> handler) {
500 if (classDef == initScanClass) // avoid infinite loops
501 return;
502 JCClassDecl initScanClassPrev = initScanClass;
503 initScanClass = classDef;
504 try {
505 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
506 JCTree def = defs.head;
507
508 // Don't recurse into nested classes
509 if (def.hasTag(CLASSDEF))
510 continue;
511
512 /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
513 * represented in the symbol but not in the tree modifiers as they were not originally in the source
514 * code
515 */
516 boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
517 if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic)) {
518 if (def instanceof JCVariableDecl varDecl) {
519 boolean isEarly = varDecl.init != null &&
520 varDecl.sym.isStrict() &&
521 !varDecl.sym.isStatic();
522 if (isEarly == earlyOnly) {
523 handler.accept(def);
524 }
525 } else if (!earlyOnly) {
526 handler.accept(def);
527 }
528 }
529 }
530 } finally {
531 initScanClass = initScanClassPrev;
532 }
533 }
534 }
535
536 /**
537 * This pass implements the first step of the dataflow analysis, namely
538 * the liveness analysis check. This checks that every statement is reachable.
539 * The output of this analysis pass are used by other analyzers. This analyzer
540 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
541 */
542 class AliveAnalyzer extends BaseAnalyzer {
543
544 /** A flag that indicates whether the last statement could
545 * complete normally.
546 */
547 private Liveness alive;
548
2187 }
2188
2189 @Override
2190 public void resolveJump() {
2191 inits.andSet(exit_inits);
2192 uninits.andSet(exit_uninits);
2193 }
2194 }
2195
2196 public AssignAnalyzer() {
2197 this.inits = new Bits();
2198 uninits = new Bits();
2199 uninitsTry = new Bits();
2200 initsWhenTrue = new Bits(true);
2201 initsWhenFalse = new Bits(true);
2202 uninitsWhenTrue = new Bits(true);
2203 uninitsWhenFalse = new Bits(true);
2204 }
2205
2206 private boolean isConstructor;
2207 private boolean isCompactOrGeneratedRecordConstructor;
2208
2209 @Override
2210 protected void markDead() {
2211 inits.inclRange(returnadr, nextadr);
2212 uninits.inclRange(returnadr, nextadr);
2213 }
2214
2215 /*-------------- Processing variables ----------------------*/
2216
2217 /** Do we need to track init/uninit state of this symbol?
2218 * I.e. is symbol either a local or a blank final variable?
2219 */
2220 protected boolean trackable(VarSymbol sym) {
2221 return
2222 sym.pos >= startPos &&
2223 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2224 isFinalOrStrictUninitializedField(sym)));
2225 }
2226
2227 boolean isFinalOrStrictUninitializedField(VarSymbol sym) {
2228 return sym.owner.kind == TYP &&
2229 (((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL ||
2230 (sym.flags() & (STRICT | HASINIT | PARAMETER)) == STRICT) &&
2231 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2232 }
2233
2234 /** Initialize new trackable variable by setting its address field
2235 * to the next available sequence number and entering it under that
2236 * index into the vars array.
2237 */
2238 void newVar(JCVariableDecl varDecl) {
2239 VarSymbol sym = varDecl.sym;
2240 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2241 if ((sym.flags() & FINAL) == 0) {
2242 sym.flags_field |= EFFECTIVELY_FINAL;
2243 }
2244 sym.adr = nextadr;
2245 vardecls[nextadr] = varDecl;
2246 inits.excl(nextadr);
2247 uninits.incl(nextadr);
2248 nextadr++;
2249 }
2250
2282 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2283 }
2284 }
2285 //where
2286 void uninit(VarSymbol sym) {
2287 if (!inits.isMember(sym.adr)) {
2288 // reachable assignment
2289 uninits.excl(sym.adr);
2290 uninitsTry.excl(sym.adr);
2291 } else {
2292 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2293 uninits.excl(sym.adr);
2294 }
2295 }
2296
2297 /** If tree is either a simple name or of the form this.name or
2298 * C.this.name, and tree represents a trackable variable,
2299 * record an initialization of the variable.
2300 */
2301 void letInit(JCTree tree) {
2302 letInit(tree, (JCAssign) null);
2303 }
2304
2305 void letInit(JCTree tree, JCAssign assign) {
2306 tree = TreeInfo.skipParens(tree);
2307 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2308 Symbol sym = TreeInfo.symbol(tree);
2309 if (sym.kind == VAR) {
2310 letInit(tree.pos(), (VarSymbol)sym);
2311 if (isConstructor && sym.isStrict()) {
2312 /* we are initializing a strict field inside of a constructor, we now need to find which fields
2313 * haven't been initialized yet
2314 */
2315 unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, assign != null ? assign : tree, findUninitStrictFields());
2316 }
2317 }
2318 }
2319 }
2320
2321 /** Check that trackable variable is initialized.
2322 */
2323 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2324 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2325 }
2326
2327 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2328 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2329 trackable(sym) &&
2330 !inits.isMember(sym.adr) &&
2331 (sym.flags_field & CLASH) == 0) {
2332 log.error(pos, errkey);
2333 inits.incl(sym.adr);
2334 }
2335 }
2336
2337 /** Utility method to reset several Bits instances.
2338 */
2339 private void resetBits(Bits... bits) {
2340 for (Bits b : bits) {
2341 b.reset();
2342 }
2343 }
2344
2345 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2346 */
2347 void split(boolean setToNull) {
2348 initsWhenFalse.assign(inits);
2349 uninitsWhenFalse.assign(uninits);
2350 initsWhenTrue.assign(inits);
2351 uninitsWhenTrue.assign(uninits);
2352 if (setToNull) {
2510 return;
2511 }
2512
2513 /* MemberEnter can generate synthetic methods ignore them
2514 */
2515 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2516 return;
2517 }
2518
2519 Lint lintPrev = lint;
2520 lint = lint.augment(tree.sym);
2521 try {
2522 final Bits initsPrev = new Bits(inits);
2523 final Bits uninitsPrev = new Bits(uninits);
2524 int nextadrPrev = nextadr;
2525 int firstadrPrev = firstadr;
2526 int returnadrPrev = returnadr;
2527
2528 Assert.check(pendingExits.isEmpty());
2529 boolean isConstructorPrev = isConstructor;
2530 boolean isCompactOrGeneratedRecordConstructorPrev = isCompactOrGeneratedRecordConstructor;
2531 try {
2532 isConstructor = TreeInfo.isConstructor(tree);
2533 isCompactOrGeneratedRecordConstructor = isConstructor && ((tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2534 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD));
2535
2536 // We only track field initialization inside constructors
2537 if (!isConstructor) {
2538 firstadr = nextadr;
2539 }
2540
2541 // Mark all method parameters as DA
2542 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2543 JCVariableDecl def = l.head;
2544 scan(def);
2545 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2546 /* If we are executing the code from Gen, then there can be
2547 * synthetic or mandated variables, ignore them.
2548 */
2549 initParam(def);
2550 }
2551 if (isConstructor) {
2552 Set<VarSymbol> unsetFields = findUninitStrictFields();
2553 if (unsetFields != null && !unsetFields.isEmpty()) {
2554 unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
2555 }
2556 }
2557
2558 // else we are in an instance initializer block;
2559 // leave caught unchanged.
2560 scan(tree.body);
2561
2562 if (isConstructor) {
2563 boolean isSynthesized = (tree.sym.flags() &
2564 GENERATEDCONSTR) != 0;
2565 for (int i = firstadr; i < nextadr; i++) {
2566 JCVariableDecl vardecl = vardecls[i];
2567 VarSymbol var = vardecl.sym;
2568 if (var.owner == classDef.sym && !var.isStatic()) {
2569 // choose the diagnostic position based on whether
2570 // the ctor is default(synthesized) or not
2571 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2572 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2573 var, Errors.VarNotInitializedInDefaultConstructor(var));
2574 } else if (isCompactOrGeneratedRecordConstructor) {
2575 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2576 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2577 var.owner.kind == TYP;
2578 if (isInstanceRecordField) {
2579 boolean notInitialized = !inits.isMember(var.adr);
2580 if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2581 /* this way we indicate Lower that it should generate an initialization for this field
2585 } else {
2586 checkInit(TreeInfo.diagEndPos(tree.body), var);
2587 }
2588 } else {
2589 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2590 }
2591 } else {
2592 checkInit(TreeInfo.diagEndPos(tree.body), var);
2593 }
2594 }
2595 }
2596 }
2597 clearPendingExits(true);
2598 } finally {
2599 inits.assign(initsPrev);
2600 uninits.assign(uninitsPrev);
2601 nextadr = nextadrPrev;
2602 firstadr = firstadrPrev;
2603 returnadr = returnadrPrev;
2604 isConstructor = isConstructorPrev;
2605 isCompactOrGeneratedRecordConstructor = isCompactOrGeneratedRecordConstructorPrev;
2606 }
2607 } finally {
2608 lint = lintPrev;
2609 }
2610 }
2611
2612 Set<VarSymbol> findUninitStrictFields() {
2613 Set<VarSymbol> unsetFields = new LinkedHashSet<>();
2614 for (int i = uninits.nextBit(0); i >= 0; i = uninits.nextBit(i + 1)) {
2615 JCVariableDecl variableDecl = vardecls[i];
2616 if (variableDecl.sym.isStrict()) {
2617 unsetFields.add(variableDecl.sym);
2618 }
2619 }
2620 return unsetFields;
2621 }
2622
2623 private void clearPendingExits(boolean inMethod) {
2624 List<PendingExit> exits = pendingExits.toList();
2625 pendingExits = new ListBuffer<>();
2626 while (exits.nonEmpty()) {
2627 PendingExit exit = exits.head;
2628 exits = exits.tail;
2629 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2630 log.hasErrorOn(exit.tree.pos()),
2631 exit.tree);
2632 if (inMethod && isConstructor) {
2633 Assert.check(exit instanceof AssignPendingExit);
2634 inits.assign(((AssignPendingExit) exit).exit_inits);
2635 for (int i = firstadr; i < nextadr; i++) {
2636 checkInit(exit.tree.pos(), vardecls[i].sym);
2637 }
2638 }
2639 }
2640 }
2641 protected void initParam(JCVariableDecl def) {
2642 inits.incl(def.sym.adr);
3066 }
3067 }
3068
3069 @Override
3070 public void visitContinue(JCContinue tree) {
3071 recordExit(new AssignPendingExit(tree, inits, uninits));
3072 }
3073
3074 @Override
3075 public void visitReturn(JCReturn tree) {
3076 scanExpr(tree.expr);
3077 recordExit(new AssignPendingExit(tree, inits, uninits));
3078 }
3079
3080 public void visitThrow(JCThrow tree) {
3081 scanExpr(tree.expr);
3082 markDead();
3083 }
3084
3085 public void visitApply(JCMethodInvocation tree) {
3086 Name name = TreeInfo.name(tree.meth);
3087 // let's process early initializers
3088 if (name == names._super) {
3089 forEachInitializer(classDef, false, true, def -> {
3090 scan(def);
3091 clearPendingExits(false);
3092 });
3093 }
3094 scanExpr(tree.meth);
3095 scanExprs(tree.args);
3096
3097 // Handle superclass constructor invocations
3098 if (isConstructor) {
3099
3100 // If super(): at this point all initialization blocks will execute
3101
3102 if (name == names._super) {
3103 // strict fields should have been initialized at this point
3104 for (int i = firstadr; i < nextadr; i++) {
3105 JCVariableDecl vardecl = vardecls[i];
3106 VarSymbol var = vardecl.sym;
3107 if (allowValueClasses && (var.owner == classDef.sym && !var.isStatic() && (var.isStrict() || ((var.flags_field & RECORD) != 0)) && !isCompactOrGeneratedRecordConstructor)) {
3108 checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
3109 }
3110 }
3111 forEachInitializer(classDef, false, def -> {
3112 scan(def);
3113 clearPendingExits(false);
3114 });
3115 }
3116
3117 // If this(): at this point all final uninitialized fields will get initialized
3118 else if (name == names._this) {
3119 for (int address = firstadr; address < nextadr; address++) {
3120 VarSymbol sym = vardecls[address].sym;
3121 if (isFinalOrStrictUninitializedField(sym) && !sym.isStatic())
3122 letInit(tree.pos(), sym);
3123 }
3124 }
3125 }
3126 }
3127
3128 public void visitNewClass(JCNewClass tree) {
3129 scanExpr(tree.encl);
3130 scanExprs(tree.args);
3131 scan(tree.def);
3132 }
3133
3134 @Override
3135 public void visitLambda(JCLambda tree) {
3136 final Bits prevUninits = new Bits(uninits);
3137 final Bits prevUninitsTry = new Bits(uninitsTry);
3138 final Bits prevInits = new Bits(inits);
3139 int returnadrPrev = returnadr;
3140 int nextadrPrev = nextadr;
3141 ListBuffer<PendingExit> prevPending = pendingExits;
3175 }
3176
3177 public void visitAssert(JCAssert tree) {
3178 final Bits initsExit = new Bits(inits);
3179 final Bits uninitsExit = new Bits(uninits);
3180 scanCond(tree.cond);
3181 uninitsExit.andSet(uninitsWhenTrue);
3182 if (tree.detail != null) {
3183 inits.assign(initsWhenFalse);
3184 uninits.assign(uninitsWhenFalse);
3185 scanExpr(tree.detail);
3186 }
3187 inits.assign(initsExit);
3188 uninits.assign(uninitsExit);
3189 }
3190
3191 public void visitAssign(JCAssign tree) {
3192 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3193 scanExpr(tree.lhs);
3194 scanExpr(tree.rhs);
3195 letInit(tree.lhs, tree);
3196 }
3197
3198 // check fields accessed through this.<field> are definitely
3199 // assigned before reading their value
3200 public void visitSelect(JCFieldAccess tree) {
3201 super.visitSelect(tree);
3202 if (TreeInfo.isThisQualifier(tree.selected) &&
3203 tree.sym.kind == VAR) {
3204 checkInit(tree.pos(), (VarSymbol)tree.sym);
3205 }
3206 }
3207
3208 public void visitAssignop(JCAssignOp tree) {
3209 scanExpr(tree.lhs);
3210 scanExpr(tree.rhs);
3211 letInit(tree.lhs);
3212 }
3213
3214 public void visitUnary(JCUnary tree) {
3215 switch (tree.getTag()) {
|