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
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) {
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() &&
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
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
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 lint = Lint.instance(context);
343 infer = Infer.instance(context);
344 rs = Resolve.instance(context);
345 diags = JCDiagnostic.Factory.instance(context);
346 unsetFieldsInfo = UnsetFieldsInfo.instance(context);
347 }
348
349 /**
350 * Base visitor class for all visitors implementing dataflow analysis logic.
351 * This class define the shared logic for handling jumps (break/continue statements).
352 */
353 abstract static class BaseAnalyzer extends TreeScanner {
354
355 enum JumpKind {
356 BREAK(JCTree.Tag.BREAK) {
357 @Override
358 JCTree getTarget(JCTree tree) {
359 return ((JCBreak)tree).target;
360 }
361 },
362 CONTINUE(JCTree.Tag.CONTINUE) {
363 @Override
364 JCTree getTarget(JCTree tree) {
365 return ((JCContinue)tree).target;
366 }
463 }
464 }
465
466 public void visitPackageDef(JCPackageDecl tree) {
467 // Do nothing for PackageDecl
468 }
469
470 protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
471 if (swtch.hasTag(SWITCH_EXPRESSION)) {
472 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
473 .setType(swtch.type));
474 brk.target = swtch;
475 scan(brk);
476 } else {
477 JCBreak brk = make.at(Position.NOPOS).Break(null);
478 brk.target = swtch;
479 scan(brk);
480 }
481 }
482
483 // Do something with static or non-static field initializers and initialization blocks.
484 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
485 forEachInitializer(classDef, isStatic, false, handler);
486 }
487
488 /* Do something with static or non-static field initializers and initialization blocks.
489 * the `earlyOnly` argument will determine if we will deal or not with early variable instance
490 * initializers we want to process only those before a super() invocation and ignore them after
491 * it.
492 */
493 protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, boolean earlyOnly,
494 Consumer<? super JCTree> handler) {
495 if (classDef == initScanClass) // avoid infinite loops
496 return;
497 JCClassDecl initScanClassPrev = initScanClass;
498 initScanClass = classDef;
499 try {
500 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
501 JCTree def = defs.head;
502
503 // Don't recurse into nested classes
504 if (def.hasTag(CLASSDEF))
505 continue;
506
507 /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
508 * represented in the symbol but not in the tree modifiers as they were not originally in the source
509 * code
510 */
511 boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
512 if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic)) {
513 if (def instanceof JCVariableDecl varDecl) {
514 boolean isEarly = varDecl.init != null &&
515 varDecl.sym.isStrict() &&
516 !varDecl.sym.isStatic();
517 if (isEarly == earlyOnly) {
518 handler.accept(def);
519 }
520 } else if (!earlyOnly) {
521 handler.accept(def);
522 }
523 }
524 }
525 } finally {
526 initScanClass = initScanClassPrev;
527 }
528 }
529 }
530
531 /**
532 * This pass implements the first step of the dataflow analysis, namely
533 * the liveness analysis check. This checks that every statement is reachable.
534 * The output of this analysis pass are used by other analyzers. This analyzer
535 * sets the 'finallyCanCompleteNormally' field in the JCTry class.
536 */
537 class AliveAnalyzer extends BaseAnalyzer {
538
539 /** A flag that indicates whether the last statement could
540 * complete normally.
541 */
542 private Liveness alive;
543
2198 uninitsWhenFalse = new Bits(true);
2199 }
2200
2201 private boolean isConstructor;
2202
2203 @Override
2204 protected void markDead() {
2205 inits.inclRange(returnadr, nextadr);
2206 uninits.inclRange(returnadr, nextadr);
2207 }
2208
2209 /*-------------- Processing variables ----------------------*/
2210
2211 /** Do we need to track init/uninit state of this symbol?
2212 * I.e. is symbol either a local or a blank final variable?
2213 */
2214 protected boolean trackable(VarSymbol sym) {
2215 return
2216 sym.pos >= startPos &&
2217 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2218 isFinalOrStrictUninitializedField(sym)));
2219 }
2220
2221 boolean isFinalOrStrictUninitializedField(VarSymbol sym) {
2222 return sym.owner.kind == TYP &&
2223 (((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL ||
2224 (sym.flags() & (STRICT | HASINIT | PARAMETER)) == STRICT) &&
2225 classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2226 }
2227
2228 /** Initialize new trackable variable by setting its address field
2229 * to the next available sequence number and entering it under that
2230 * index into the vars array.
2231 */
2232 void newVar(JCVariableDecl varDecl) {
2233 VarSymbol sym = varDecl.sym;
2234 vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2235 if ((sym.flags() & FINAL) == 0) {
2236 sym.flags_field |= EFFECTIVELY_FINAL;
2237 }
2238 sym.adr = nextadr;
2239 vardecls[nextadr] = varDecl;
2240 inits.excl(nextadr);
2241 uninits.incl(nextadr);
2242 nextadr++;
2243 }
2244
2276 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2277 }
2278 }
2279 //where
2280 void uninit(VarSymbol sym) {
2281 if (!inits.isMember(sym.adr)) {
2282 // reachable assignment
2283 uninits.excl(sym.adr);
2284 uninitsTry.excl(sym.adr);
2285 } else {
2286 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2287 uninits.excl(sym.adr);
2288 }
2289 }
2290
2291 /** If tree is either a simple name or of the form this.name or
2292 * C.this.name, and tree represents a trackable variable,
2293 * record an initialization of the variable.
2294 */
2295 void letInit(JCTree tree) {
2296 letInit(tree, (JCAssign) null);
2297 }
2298
2299 void letInit(JCTree tree, JCAssign assign) {
2300 tree = TreeInfo.skipParens(tree);
2301 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2302 Symbol sym = TreeInfo.symbol(tree);
2303 if (sym.kind == VAR) {
2304 letInit(tree.pos(), (VarSymbol)sym);
2305 if (isConstructor && sym.isStrict()) {
2306 /* we are initializing a strict field inside of a constructor, we now need to find which fields
2307 * haven't been initialized yet
2308 */
2309 unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, assign != null ? assign : tree, findUninitStrictFields());
2310 }
2311 }
2312 }
2313 }
2314
2315 /** Check that trackable variable is initialized.
2316 */
2317 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2318 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2319 }
2320
2321 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2322 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2323 trackable(sym) &&
2324 !inits.isMember(sym.adr) &&
2325 (sym.flags_field & CLASH) == 0) {
2326 log.error(pos, errkey);
2327 inits.incl(sym.adr);
2328 }
2329 }
2330
2331 /** Utility method to reset several Bits instances.
2332 */
2333 private void resetBits(Bits... bits) {
2334 for (Bits b : bits) {
2335 b.reset();
2336 }
2337 }
2338
2339 /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2340 */
2341 void split(boolean setToNull) {
2342 initsWhenFalse.assign(inits);
2343 uninitsWhenFalse.assign(uninits);
2344 initsWhenTrue.assign(inits);
2345 uninitsWhenTrue.assign(uninits);
2346 if (setToNull) {
2522 Assert.check(pendingExits.isEmpty());
2523 boolean isConstructorPrev = isConstructor;
2524 try {
2525 isConstructor = TreeInfo.isConstructor(tree);
2526
2527 // We only track field initialization inside constructors
2528 if (!isConstructor) {
2529 firstadr = nextadr;
2530 }
2531
2532 // Mark all method parameters as DA
2533 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2534 JCVariableDecl def = l.head;
2535 scan(def);
2536 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2537 /* If we are executing the code from Gen, then there can be
2538 * synthetic or mandated variables, ignore them.
2539 */
2540 initParam(def);
2541 }
2542 if (isConstructor) {
2543 Set<VarSymbol> unsetFields = findUninitStrictFields();
2544 if (unsetFields != null && !unsetFields.isEmpty()) {
2545 unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
2546 }
2547 }
2548
2549 // else we are in an instance initializer block;
2550 // leave caught unchanged.
2551 scan(tree.body);
2552
2553 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2554 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2555 if (isConstructor) {
2556 boolean isSynthesized = (tree.sym.flags() &
2557 GENERATEDCONSTR) != 0;
2558 for (int i = firstadr; i < nextadr; i++) {
2559 JCVariableDecl vardecl = vardecls[i];
2560 VarSymbol var = vardecl.sym;
2561 if (var.owner == classDef.sym && !var.isStatic()) {
2562 // choose the diagnostic position based on whether
2563 // the ctor is default(synthesized) or not
2564 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2565 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2566 var, Errors.VarNotInitializedInDefaultConstructor(var));
2567 } else if (isCompactOrGeneratedRecordConstructor) {
2568 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2584 } else {
2585 checkInit(TreeInfo.diagEndPos(tree.body), var);
2586 }
2587 }
2588 }
2589 }
2590 clearPendingExits(true);
2591 } finally {
2592 inits.assign(initsPrev);
2593 uninits.assign(uninitsPrev);
2594 nextadr = nextadrPrev;
2595 firstadr = firstadrPrev;
2596 returnadr = returnadrPrev;
2597 isConstructor = isConstructorPrev;
2598 }
2599 } finally {
2600 lint = lintPrev;
2601 }
2602 }
2603
2604 Set<VarSymbol> findUninitStrictFields() {
2605 Set<VarSymbol> unsetFields = new LinkedHashSet<>();
2606 for (int i = uninits.nextBit(0); i >= 0; i = uninits.nextBit(i + 1)) {
2607 JCVariableDecl variableDecl = vardecls[i];
2608 if (variableDecl.sym.isStrict()) {
2609 unsetFields.add(variableDecl.sym);
2610 }
2611 }
2612 return unsetFields;
2613 }
2614
2615 private void clearPendingExits(boolean inMethod) {
2616 List<PendingExit> exits = pendingExits.toList();
2617 pendingExits = new ListBuffer<>();
2618 while (exits.nonEmpty()) {
2619 PendingExit exit = exits.head;
2620 exits = exits.tail;
2621 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2622 log.hasErrorOn(exit.tree.pos()),
2623 exit.tree);
2624 if (inMethod && isConstructor) {
2625 Assert.check(exit instanceof AssignPendingExit);
2626 inits.assign(((AssignPendingExit) exit).exit_inits);
2627 for (int i = firstadr; i < nextadr; i++) {
2628 checkInit(exit.tree.pos(), vardecls[i].sym);
2629 }
2630 }
2631 }
2632 }
2633 protected void initParam(JCVariableDecl def) {
2634 inits.incl(def.sym.adr);
3058 }
3059 }
3060
3061 @Override
3062 public void visitContinue(JCContinue tree) {
3063 recordExit(new AssignPendingExit(tree, inits, uninits));
3064 }
3065
3066 @Override
3067 public void visitReturn(JCReturn tree) {
3068 scanExpr(tree.expr);
3069 recordExit(new AssignPendingExit(tree, inits, uninits));
3070 }
3071
3072 public void visitThrow(JCThrow tree) {
3073 scanExpr(tree.expr);
3074 markDead();
3075 }
3076
3077 public void visitApply(JCMethodInvocation tree) {
3078 Name name = TreeInfo.name(tree.meth);
3079 // let's process early initializers
3080 if (name == names._super) {
3081 forEachInitializer(classDef, false, true, def -> {
3082 scan(def);
3083 clearPendingExits(false);
3084 });
3085 }
3086 scanExpr(tree.meth);
3087 scanExprs(tree.args);
3088
3089 // Handle superclass constructor invocations
3090 if (isConstructor) {
3091
3092 // If super(): at this point all initialization blocks will execute
3093
3094 if (name == names._super) {
3095 // strict fields should have been initialized at this point
3096 for (int i = firstadr; i < nextadr; i++) {
3097 JCVariableDecl vardecl = vardecls[i];
3098 VarSymbol var = vardecl.sym;
3099 boolean isInstanceRecordField = var.enclClass().isRecord() &&
3100 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
3101 var.owner.kind == TYP;
3102 if (var.owner == classDef.sym && !var.isStatic() && var.isStrict() && !isInstanceRecordField) {
3103 checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
3104 }
3105 }
3106 forEachInitializer(classDef, false, def -> {
3107 scan(def);
3108 clearPendingExits(false);
3109 });
3110 }
3111
3112 // If this(): at this point all final uninitialized fields will get initialized
3113 else if (name == names._this) {
3114 for (int address = firstadr; address < nextadr; address++) {
3115 VarSymbol sym = vardecls[address].sym;
3116 if (isFinalOrStrictUninitializedField(sym) && !sym.isStatic())
3117 letInit(tree.pos(), sym);
3118 }
3119 }
3120 }
3121 }
3122
3123 public void visitNewClass(JCNewClass tree) {
3124 scanExpr(tree.encl);
3125 scanExprs(tree.args);
3126 scan(tree.def);
3127 }
3128
3129 @Override
3130 public void visitLambda(JCLambda tree) {
3131 final Bits prevUninits = new Bits(uninits);
3132 final Bits prevUninitsTry = new Bits(uninitsTry);
3133 final Bits prevInits = new Bits(inits);
3134 int returnadrPrev = returnadr;
3135 int nextadrPrev = nextadr;
3136 ListBuffer<PendingExit> prevPending = pendingExits;
3170 }
3171
3172 public void visitAssert(JCAssert tree) {
3173 final Bits initsExit = new Bits(inits);
3174 final Bits uninitsExit = new Bits(uninits);
3175 scanCond(tree.cond);
3176 uninitsExit.andSet(uninitsWhenTrue);
3177 if (tree.detail != null) {
3178 inits.assign(initsWhenFalse);
3179 uninits.assign(uninitsWhenFalse);
3180 scanExpr(tree.detail);
3181 }
3182 inits.assign(initsExit);
3183 uninits.assign(uninitsExit);
3184 }
3185
3186 public void visitAssign(JCAssign tree) {
3187 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3188 scanExpr(tree.lhs);
3189 scanExpr(tree.rhs);
3190 letInit(tree.lhs, tree);
3191 }
3192
3193 // check fields accessed through this.<field> are definitely
3194 // assigned before reading their value
3195 public void visitSelect(JCFieldAccess tree) {
3196 super.visitSelect(tree);
3197 if (TreeInfo.isThisQualifier(tree.selected) &&
3198 tree.sym.kind == VAR) {
3199 checkInit(tree.pos(), (VarSymbol)tree.sym);
3200 }
3201 }
3202
3203 public void visitAssignop(JCAssignOp tree) {
3204 scanExpr(tree.lhs);
3205 scanExpr(tree.rhs);
3206 letInit(tree.lhs);
3207 }
3208
3209 public void visitUnary(JCUnary tree) {
3210 switch (tree.getTag()) {
|