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.Warnings;
42 import com.sun.tools.javac.tree.*;
43 import com.sun.tools.javac.util.*;
44 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
45 import com.sun.tools.javac.util.JCDiagnostic.Error;
46 import com.sun.tools.javac.util.JCDiagnostic.Warning;
47
48 import com.sun.tools.javac.code.Symbol.*;
49 import com.sun.tools.javac.tree.JCTree.*;
50
51 import static com.sun.tools.javac.code.Flags.*;
52 import static com.sun.tools.javac.code.Flags.BLOCK;
53 import com.sun.tools.javac.code.Kinds.Kind;
54 import static com.sun.tools.javac.code.Kinds.Kind.*;
55 import com.sun.tools.javac.code.Type.TypeVar;
56 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
57 import static com.sun.tools.javac.code.TypeTag.VOID;
58 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
59 import static com.sun.tools.javac.tree.JCTree.Tag.*;
60 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
61 import java.util.Arrays;
62 import java.util.Collections;
63 import java.util.IdentityHashMap;
64 import java.util.Iterator;
65 import java.util.function.Predicate;
66 import java.util.stream.Collectors;
67
68 import static java.util.stream.Collectors.groupingBy;
69
70 /** This pass implements dataflow analysis for Java programs though
71 * different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
72 * every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
73 * every checked exception that is thrown is declared or caught. Definite assignment analysis
74 * (see AssignAnalyzer) ensures that each variable is assigned when used. Definite
75 * unassignment analysis (see AssignAnalyzer) in ensures that no final variable
76 * is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
77 * determines that local variables accessed within the scope of an inner class/lambda
1579 caught = chk.incl(ct.type, caught);
1580 }
1581 }
1582
1583 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1584 pendingExits = new ListBuffer<>();
1585 for (JCTree resource : tree.resources) {
1586 if (resource instanceof JCVariableDecl variableDecl) {
1587 visitVarDef(variableDecl);
1588 } else if (resource instanceof JCExpression expression) {
1589 scan(expression);
1590 } else {
1591 throw new AssertionError(tree); // parser error
1592 }
1593 }
1594 for (JCTree resource : tree.resources) {
1595 List<Type> closeableSupertypes = resource.type.isCompound() ?
1596 types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1597 List.of(resource.type);
1598 for (Type sup : closeableSupertypes) {
1599 if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1600 Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1601 attrEnv,
1602 types.skipTypeVars(sup, false),
1603 names.close,
1604 List.nil(),
1605 List.nil());
1606 Type mt = types.memberType(resource.type, closeMethod);
1607 if (closeMethod.kind == MTH) {
1608 for (Type t : mt.getThrownTypes()) {
1609 markThrown(resource, t);
1610 }
1611 }
1612 }
1613 }
1614 }
1615 scan(tree.body);
1616 List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1617 thrown = thrownPrev;
1618 caught = caughtPrev;
1619
1995 inLambda = true;
1996 try {
1997 pendingExits = new ListBuffer<>();
1998 caught = List.of(syms.throwableType);
1999 thrown = List.nil();
2000 scan(tree.body);
2001 inferredThrownTypes = thrown;
2002 } finally {
2003 pendingExits = prevPending;
2004 caught = prevCaught;
2005 thrown = prevThrown;
2006 inLambda = false;
2007 }
2008 }
2009 @Override
2010 public void visitClassDef(JCClassDecl tree) {
2011 //skip
2012 }
2013 }
2014
2015 /**
2016 * This pass implements (i) definite assignment analysis, which ensures that
2017 * each variable is assigned when used and (ii) definite unassignment analysis,
2018 * which ensures that no final variable is assigned more than once. This visitor
2019 * depends on the results of the liveliness analyzer. This pass is also used to mark
2020 * effectively-final local variables/parameters.
2021 */
2022
2023 public class AssignAnalyzer extends BaseAnalyzer {
2024
2025 /** The set of definitely assigned variables.
2026 */
2027 final Bits inits;
2028
2029 /** The set of definitely unassigned variables.
2030 */
2031 final Bits uninits;
2032
2033 /** The set of variables that are definitely unassigned everywhere
2034 * in current try block. This variable is maintained lazily; it is
2083 final Bits inits;
2084 final Bits uninits;
2085 final Bits exit_inits = new Bits(true);
2086 final Bits exit_uninits = new Bits(true);
2087
2088 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2089 super(tree);
2090 this.inits = inits;
2091 this.uninits = uninits;
2092 this.exit_inits.assign(inits);
2093 this.exit_uninits.assign(uninits);
2094 }
2095
2096 @Override
2097 public void resolveJump() {
2098 inits.andSet(exit_inits);
2099 uninits.andSet(exit_uninits);
2100 }
2101 }
2102
2103 public AssignAnalyzer() {
2104 this.inits = new Bits();
2105 uninits = new Bits();
2106 uninitsTry = new Bits();
2107 initsWhenTrue = new Bits(true);
2108 initsWhenFalse = new Bits(true);
2109 uninitsWhenTrue = new Bits(true);
2110 uninitsWhenFalse = new Bits(true);
2111 }
2112
2113 private boolean isInitialConstructor = false;
2114
2115 @Override
2116 protected void markDead() {
2117 if (!isInitialConstructor) {
2118 inits.inclRange(returnadr, nextadr);
2119 } else {
2120 for (int address = returnadr; address < nextadr; address++) {
2121 if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
2122 inits.incl(address);
2208 } else {
2209 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2210 uninits.excl(sym.adr);
2211 }
2212 }
2213
2214 /** If tree is either a simple name or of the form this.name or
2215 * C.this.name, and tree represents a trackable variable,
2216 * record an initialization of the variable.
2217 */
2218 void letInit(JCTree tree) {
2219 tree = TreeInfo.skipParens(tree);
2220 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2221 Symbol sym = TreeInfo.symbol(tree);
2222 if (sym.kind == VAR) {
2223 letInit(tree.pos(), (VarSymbol)sym);
2224 }
2225 }
2226 }
2227
2228 /** Check that trackable variable is initialized.
2229 */
2230 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2231 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2232 }
2233
2234 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2235 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2236 trackable(sym) &&
2237 !inits.isMember(sym.adr) &&
2238 (sym.flags_field & CLASH) == 0) {
2239 log.error(pos, errkey);
2240 inits.incl(sym.adr);
2241 }
2242 }
2243
2244 /** Utility method to reset several Bits instances.
2245 */
2246 private void resetBits(Bits... bits) {
2247 for (Bits b : bits) {
2413 classDef = classDefPrev;
2414 }
2415 } finally {
2416 lint = lintPrev;
2417 }
2418 }
2419
2420 public void visitMethodDef(JCMethodDecl tree) {
2421 if (tree.body == null) {
2422 return;
2423 }
2424
2425 /* MemberEnter can generate synthetic methods ignore them
2426 */
2427 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2428 return;
2429 }
2430
2431 Lint lintPrev = lint;
2432 lint = lint.augment(tree.sym);
2433 try {
2434 final Bits initsPrev = new Bits(inits);
2435 final Bits uninitsPrev = new Bits(uninits);
2436 int nextadrPrev = nextadr;
2437 int firstadrPrev = firstadr;
2438 int returnadrPrev = returnadr;
2439
2440 Assert.check(pendingExits.isEmpty());
2441 boolean lastInitialConstructor = isInitialConstructor;
2442 try {
2443 isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2444
2445 if (!isInitialConstructor) {
2446 firstadr = nextadr;
2447 }
2448 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2449 JCVariableDecl def = l.head;
2450 scan(def);
2451 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2452 /* If we are executing the code from Gen, then there can be
2453 * synthetic or mandated variables, ignore them.
2454 */
2455 initParam(def);
2456 }
2457 // else we are in an instance initializer block;
2458 // leave caught unchanged.
2459 scan(tree.body);
2460
2461 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2462 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2463 if (isInitialConstructor) {
2464 boolean isSynthesized = (tree.sym.flags() &
2465 GENERATEDCONSTR) != 0;
2466 for (int i = firstadr; i < nextadr; i++) {
2489 } else {
2490 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2491 }
2492 } else {
2493 checkInit(TreeInfo.diagEndPos(tree.body), var);
2494 }
2495 }
2496 }
2497 }
2498 clearPendingExits(true);
2499 } finally {
2500 inits.assign(initsPrev);
2501 uninits.assign(uninitsPrev);
2502 nextadr = nextadrPrev;
2503 firstadr = firstadrPrev;
2504 returnadr = returnadrPrev;
2505 isInitialConstructor = lastInitialConstructor;
2506 }
2507 } finally {
2508 lint = lintPrev;
2509 }
2510 }
2511
2512 private void clearPendingExits(boolean inMethod) {
2513 List<PendingExit> exits = pendingExits.toList();
2514 pendingExits = new ListBuffer<>();
2515 while (exits.nonEmpty()) {
2516 PendingExit exit = exits.head;
2517 exits = exits.tail;
2518 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2519 log.hasErrorOn(exit.tree.pos()),
2520 exit.tree);
2521 if (inMethod && isInitialConstructor) {
2522 Assert.check(exit instanceof AssignPendingExit);
2523 inits.assign(((AssignPendingExit) exit).exit_inits);
2524 for (int i = firstadr; i < nextadr; i++) {
2525 checkInit(exit.tree.pos(), vardecls[i].sym);
2526 }
2527 }
2528 }
2957
2958 @Override
2959 public void visitContinue(JCContinue tree) {
2960 recordExit(new AssignPendingExit(tree, inits, uninits));
2961 }
2962
2963 @Override
2964 public void visitReturn(JCReturn tree) {
2965 scanExpr(tree.expr);
2966 recordExit(new AssignPendingExit(tree, inits, uninits));
2967 }
2968
2969 public void visitThrow(JCThrow tree) {
2970 scanExpr(tree.expr);
2971 markDead();
2972 }
2973
2974 public void visitApply(JCMethodInvocation tree) {
2975 scanExpr(tree.meth);
2976 scanExprs(tree.args);
2977 }
2978
2979 public void visitNewClass(JCNewClass tree) {
2980 scanExpr(tree.encl);
2981 scanExprs(tree.args);
2982 scan(tree.def);
2983 }
2984
2985 @Override
2986 public void visitLambda(JCLambda tree) {
2987 final Bits prevUninits = new Bits(uninits);
2988 final Bits prevUninitsTry = new Bits(uninitsTry);
2989 final Bits prevInits = new Bits(inits);
2990 int returnadrPrev = returnadr;
2991 int nextadrPrev = nextadr;
2992 ListBuffer<PendingExit> prevPending = pendingExits;
2993 try {
2994 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
2995 // body. This is by design: a variable that was definitely unassigned before the
2996 // lambda body may end up being assigned to later on, so we cannot conclude that
2997 // the variable will be unassigned when the body is executed.
2998 uninits.excludeFrom(firstadr);
2999 returnadr = nextadr;
3000 pendingExits = new ListBuffer<>();
3001 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
3002 JCVariableDecl def = l.head;
3032 uninitsExit.andSet(uninitsWhenTrue);
3033 if (tree.detail != null) {
3034 inits.assign(initsWhenFalse);
3035 uninits.assign(uninitsWhenFalse);
3036 scanExpr(tree.detail);
3037 }
3038 inits.assign(initsExit);
3039 uninits.assign(uninitsExit);
3040 }
3041
3042 public void visitAssign(JCAssign tree) {
3043 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3044 scanExpr(tree.lhs);
3045 scanExpr(tree.rhs);
3046 letInit(tree.lhs);
3047 }
3048
3049 // check fields accessed through this.<field> are definitely
3050 // assigned before reading their value
3051 public void visitSelect(JCFieldAccess tree) {
3052 super.visitSelect(tree);
3053 if (TreeInfo.isThisQualifier(tree.selected) &&
3054 tree.sym.kind == VAR) {
3055 checkInit(tree.pos(), (VarSymbol)tree.sym);
3056 }
3057 }
3058
3059 public void visitAssignop(JCAssignOp tree) {
3060 scanExpr(tree.lhs);
3061 scanExpr(tree.rhs);
3062 letInit(tree.lhs);
3063 }
3064
3065 public void visitUnary(JCUnary tree) {
3066 switch (tree.getTag()) {
3067 case NOT:
3068 scanCond(tree.arg);
3069 final Bits t = new Bits(initsWhenFalse);
3070 initsWhenFalse.assign(initsWhenTrue);
3071 initsWhenTrue.assign(t);
3072 t.assign(uninitsWhenFalse);
3073 uninitsWhenFalse.assign(uninitsWhenTrue);
3074 uninitsWhenTrue.assign(t);
3075 break;
3099 scanCond(tree.lhs);
3100 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3101 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3102 inits.assign(initsWhenFalse);
3103 uninits.assign(uninitsWhenFalse);
3104 scanCond(tree.rhs);
3105 initsWhenTrue.andSet(initsWhenTrueLeft);
3106 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3107 break;
3108 default:
3109 scanExpr(tree.lhs);
3110 scanExpr(tree.rhs);
3111 }
3112 }
3113
3114 public void visitIdent(JCIdent tree) {
3115 if (tree.sym.kind == VAR) {
3116 checkInit(tree.pos(), (VarSymbol)tree.sym);
3117 referenced(tree.sym);
3118 }
3119 }
3120
3121 @Override
3122 public void visitTypeTest(JCInstanceOf tree) {
3123 scanExpr(tree.expr);
3124 scan(tree.pattern);
3125 }
3126
3127 @Override
3128 public void visitBindingPattern(JCBindingPattern tree) {
3129 scan(tree.var);
3130 initParam(tree.var);
3131 }
3132
3133 void referenced(Symbol sym) {
3134 unrefdResources.remove(sym);
3135 }
3136
3137 public void visitAnnotatedType(JCAnnotatedType tree) {
3138 // annotations don't get scanned
|
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.Warnings;
42 import com.sun.tools.javac.tree.*;
43 import com.sun.tools.javac.util.*;
44 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
45 import com.sun.tools.javac.util.JCDiagnostic.Error;
46 import com.sun.tools.javac.util.JCDiagnostic.Warning;
47
48 import com.sun.tools.javac.code.Symbol.*;
49 import com.sun.tools.javac.tree.JCTree.*;
50
51 import static com.sun.tools.javac.code.Flags.*;
52 import static com.sun.tools.javac.code.Flags.BLOCK;
53 import com.sun.tools.javac.code.Kinds.Kind;
54 import static com.sun.tools.javac.code.Kinds.Kind.*;
55 import com.sun.tools.javac.code.Type.TypeVar;
56 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
57 import static com.sun.tools.javac.code.TypeTag.VOID;
58 import static com.sun.tools.javac.comp.Flow.ThisExposability.ALLOWED;
59 import static com.sun.tools.javac.comp.Flow.ThisExposability.BANNED;
60 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
61 import static com.sun.tools.javac.tree.JCTree.Tag.*;
62 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
63 import java.util.Arrays;
64 import java.util.Collections;
65 import java.util.IdentityHashMap;
66 import java.util.Iterator;
67 import java.util.function.Predicate;
68 import java.util.stream.Collectors;
69
70 import static java.util.stream.Collectors.groupingBy;
71
72 /** This pass implements dataflow analysis for Java programs though
73 * different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
74 * every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
75 * every checked exception that is thrown is declared or caught. Definite assignment analysis
76 * (see AssignAnalyzer) ensures that each variable is assigned when used. Definite
77 * unassignment analysis (see AssignAnalyzer) in ensures that no final variable
78 * is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
79 * determines that local variables accessed within the scope of an inner class/lambda
1581 caught = chk.incl(ct.type, caught);
1582 }
1583 }
1584
1585 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1586 pendingExits = new ListBuffer<>();
1587 for (JCTree resource : tree.resources) {
1588 if (resource instanceof JCVariableDecl variableDecl) {
1589 visitVarDef(variableDecl);
1590 } else if (resource instanceof JCExpression expression) {
1591 scan(expression);
1592 } else {
1593 throw new AssertionError(tree); // parser error
1594 }
1595 }
1596 for (JCTree resource : tree.resources) {
1597 List<Type> closeableSupertypes = resource.type.isCompound() ?
1598 types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1599 List.of(resource.type);
1600 for (Type sup : closeableSupertypes) {
1601 if (types.asSuper(sup.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) != null) {
1602 Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1603 attrEnv,
1604 types.skipTypeVars(sup, false),
1605 names.close,
1606 List.nil(),
1607 List.nil());
1608 Type mt = types.memberType(resource.type, closeMethod);
1609 if (closeMethod.kind == MTH) {
1610 for (Type t : mt.getThrownTypes()) {
1611 markThrown(resource, t);
1612 }
1613 }
1614 }
1615 }
1616 }
1617 scan(tree.body);
1618 List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1619 thrown = thrownPrev;
1620 caught = caughtPrev;
1621
1997 inLambda = true;
1998 try {
1999 pendingExits = new ListBuffer<>();
2000 caught = List.of(syms.throwableType);
2001 thrown = List.nil();
2002 scan(tree.body);
2003 inferredThrownTypes = thrown;
2004 } finally {
2005 pendingExits = prevPending;
2006 caught = prevCaught;
2007 thrown = prevThrown;
2008 inLambda = false;
2009 }
2010 }
2011 @Override
2012 public void visitClassDef(JCClassDecl tree) {
2013 //skip
2014 }
2015 }
2016
2017 /** Enum to model whether constructors allowed to "leak" this reference before
2018 all instance fields are DA.
2019 */
2020 enum ThisExposability {
2021 ALLOWED, // identity Object classes - NOP
2022 BANNED, // primitive/value classes - Error
2023 }
2024
2025 /**
2026 * This pass implements (i) definite assignment analysis, which ensures that
2027 * each variable is assigned when used and (ii) definite unassignment analysis,
2028 * which ensures that no final variable is assigned more than once. This visitor
2029 * depends on the results of the liveliness analyzer. This pass is also used to mark
2030 * effectively-final local variables/parameters.
2031 */
2032
2033 public class AssignAnalyzer extends BaseAnalyzer {
2034
2035 /** The set of definitely assigned variables.
2036 */
2037 final Bits inits;
2038
2039 /** The set of definitely unassigned variables.
2040 */
2041 final Bits uninits;
2042
2043 /** The set of variables that are definitely unassigned everywhere
2044 * in current try block. This variable is maintained lazily; it is
2093 final Bits inits;
2094 final Bits uninits;
2095 final Bits exit_inits = new Bits(true);
2096 final Bits exit_uninits = new Bits(true);
2097
2098 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2099 super(tree);
2100 this.inits = inits;
2101 this.uninits = uninits;
2102 this.exit_inits.assign(inits);
2103 this.exit_uninits.assign(uninits);
2104 }
2105
2106 @Override
2107 public void resolveJump() {
2108 inits.andSet(exit_inits);
2109 uninits.andSet(exit_uninits);
2110 }
2111 }
2112
2113 // Are constructors allowed to leak this reference ?
2114 ThisExposability thisExposability = ALLOWED;
2115
2116 public AssignAnalyzer() {
2117 this.inits = new Bits();
2118 uninits = new Bits();
2119 uninitsTry = new Bits();
2120 initsWhenTrue = new Bits(true);
2121 initsWhenFalse = new Bits(true);
2122 uninitsWhenTrue = new Bits(true);
2123 uninitsWhenFalse = new Bits(true);
2124 }
2125
2126 private boolean isInitialConstructor = false;
2127
2128 @Override
2129 protected void markDead() {
2130 if (!isInitialConstructor) {
2131 inits.inclRange(returnadr, nextadr);
2132 } else {
2133 for (int address = returnadr; address < nextadr; address++) {
2134 if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
2135 inits.incl(address);
2221 } else {
2222 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2223 uninits.excl(sym.adr);
2224 }
2225 }
2226
2227 /** If tree is either a simple name or of the form this.name or
2228 * C.this.name, and tree represents a trackable variable,
2229 * record an initialization of the variable.
2230 */
2231 void letInit(JCTree tree) {
2232 tree = TreeInfo.skipParens(tree);
2233 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2234 Symbol sym = TreeInfo.symbol(tree);
2235 if (sym.kind == VAR) {
2236 letInit(tree.pos(), (VarSymbol)sym);
2237 }
2238 }
2239 }
2240
2241 void checkEmbryonicThisExposure(JCTree node) {
2242 if (this.thisExposability == ALLOWED || classDef == null)
2243 return;
2244
2245 // Note: for non-initial constructors, firstadr is post all instance fields.
2246 for (int i = firstadr; i < nextadr; i++) {
2247 VarSymbol sym = vardecls[i].sym;
2248 if (sym.owner != classDef.sym)
2249 continue;
2250 if ((sym.flags() & (FINAL | HASINIT | STATIC | PARAMETER)) != FINAL)
2251 continue;
2252 if (sym.pos < startPos || sym.adr < firstadr)
2253 continue;
2254 if (!inits.isMember(sym.adr)) {
2255 if (this.thisExposability == BANNED) {
2256 log.error(node, Errors.ThisExposedPrematurely);
2257 }
2258 return; // don't flog a dead horse.
2259 }
2260 }
2261 }
2262
2263 /** Check that trackable variable is initialized.
2264 */
2265 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2266 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2267 }
2268
2269 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2270 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2271 trackable(sym) &&
2272 !inits.isMember(sym.adr) &&
2273 (sym.flags_field & CLASH) == 0) {
2274 log.error(pos, errkey);
2275 inits.incl(sym.adr);
2276 }
2277 }
2278
2279 /** Utility method to reset several Bits instances.
2280 */
2281 private void resetBits(Bits... bits) {
2282 for (Bits b : bits) {
2448 classDef = classDefPrev;
2449 }
2450 } finally {
2451 lint = lintPrev;
2452 }
2453 }
2454
2455 public void visitMethodDef(JCMethodDecl tree) {
2456 if (tree.body == null) {
2457 return;
2458 }
2459
2460 /* MemberEnter can generate synthetic methods ignore them
2461 */
2462 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2463 return;
2464 }
2465
2466 Lint lintPrev = lint;
2467 lint = lint.augment(tree.sym);
2468 ThisExposability priorThisExposability = this.thisExposability;
2469 try {
2470 final Bits initsPrev = new Bits(inits);
2471 final Bits uninitsPrev = new Bits(uninits);
2472 int nextadrPrev = nextadr;
2473 int firstadrPrev = firstadr;
2474 int returnadrPrev = returnadr;
2475
2476 Assert.check(pendingExits.isEmpty());
2477 boolean lastInitialConstructor = isInitialConstructor;
2478 try {
2479 isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2480
2481 if (!isInitialConstructor) {
2482 firstadr = nextadr;
2483 this.thisExposability = ALLOWED;
2484 } else {
2485 if (tree.sym.owner.type.isValueClass())
2486 this.thisExposability = BANNED;
2487 else
2488 this.thisExposability = ALLOWED;
2489 }
2490 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2491 JCVariableDecl def = l.head;
2492 scan(def);
2493 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2494 /* If we are executing the code from Gen, then there can be
2495 * synthetic or mandated variables, ignore them.
2496 */
2497 initParam(def);
2498 }
2499 // else we are in an instance initializer block;
2500 // leave caught unchanged.
2501 scan(tree.body);
2502
2503 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2504 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2505 if (isInitialConstructor) {
2506 boolean isSynthesized = (tree.sym.flags() &
2507 GENERATEDCONSTR) != 0;
2508 for (int i = firstadr; i < nextadr; i++) {
2531 } else {
2532 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2533 }
2534 } else {
2535 checkInit(TreeInfo.diagEndPos(tree.body), var);
2536 }
2537 }
2538 }
2539 }
2540 clearPendingExits(true);
2541 } finally {
2542 inits.assign(initsPrev);
2543 uninits.assign(uninitsPrev);
2544 nextadr = nextadrPrev;
2545 firstadr = firstadrPrev;
2546 returnadr = returnadrPrev;
2547 isInitialConstructor = lastInitialConstructor;
2548 }
2549 } finally {
2550 lint = lintPrev;
2551 this.thisExposability = priorThisExposability;
2552 }
2553 }
2554
2555 private void clearPendingExits(boolean inMethod) {
2556 List<PendingExit> exits = pendingExits.toList();
2557 pendingExits = new ListBuffer<>();
2558 while (exits.nonEmpty()) {
2559 PendingExit exit = exits.head;
2560 exits = exits.tail;
2561 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2562 log.hasErrorOn(exit.tree.pos()),
2563 exit.tree);
2564 if (inMethod && isInitialConstructor) {
2565 Assert.check(exit instanceof AssignPendingExit);
2566 inits.assign(((AssignPendingExit) exit).exit_inits);
2567 for (int i = firstadr; i < nextadr; i++) {
2568 checkInit(exit.tree.pos(), vardecls[i].sym);
2569 }
2570 }
2571 }
3000
3001 @Override
3002 public void visitContinue(JCContinue tree) {
3003 recordExit(new AssignPendingExit(tree, inits, uninits));
3004 }
3005
3006 @Override
3007 public void visitReturn(JCReturn tree) {
3008 scanExpr(tree.expr);
3009 recordExit(new AssignPendingExit(tree, inits, uninits));
3010 }
3011
3012 public void visitThrow(JCThrow tree) {
3013 scanExpr(tree.expr);
3014 markDead();
3015 }
3016
3017 public void visitApply(JCMethodInvocation tree) {
3018 scanExpr(tree.meth);
3019 scanExprs(tree.args);
3020 if (tree.meth.hasTag(IDENT)) {
3021 JCIdent ident = (JCIdent) tree.meth;
3022 if (ident.name != names._super && !ident.sym.isStatic())
3023 checkEmbryonicThisExposure(tree);
3024 }
3025 }
3026
3027 public void visitNewClass(JCNewClass tree) {
3028 scanExpr(tree.encl);
3029 scanExprs(tree.args);
3030 scan(tree.def);
3031 if (classDef != null && tree.encl == null && tree.clazz.hasTag(IDENT)) {
3032 JCIdent clazz = (JCIdent) tree.clazz;
3033 if (!clazz.sym.isStatic() && clazz.type.getEnclosingType().tsym == classDef.sym) {
3034 checkEmbryonicThisExposure(tree);
3035 }
3036 }
3037 }
3038
3039 @Override
3040 public void visitLambda(JCLambda tree) {
3041 final Bits prevUninits = new Bits(uninits);
3042 final Bits prevUninitsTry = new Bits(uninitsTry);
3043 final Bits prevInits = new Bits(inits);
3044 int returnadrPrev = returnadr;
3045 int nextadrPrev = nextadr;
3046 ListBuffer<PendingExit> prevPending = pendingExits;
3047 try {
3048 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
3049 // body. This is by design: a variable that was definitely unassigned before the
3050 // lambda body may end up being assigned to later on, so we cannot conclude that
3051 // the variable will be unassigned when the body is executed.
3052 uninits.excludeFrom(firstadr);
3053 returnadr = nextadr;
3054 pendingExits = new ListBuffer<>();
3055 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
3056 JCVariableDecl def = l.head;
3086 uninitsExit.andSet(uninitsWhenTrue);
3087 if (tree.detail != null) {
3088 inits.assign(initsWhenFalse);
3089 uninits.assign(uninitsWhenFalse);
3090 scanExpr(tree.detail);
3091 }
3092 inits.assign(initsExit);
3093 uninits.assign(uninitsExit);
3094 }
3095
3096 public void visitAssign(JCAssign tree) {
3097 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3098 scanExpr(tree.lhs);
3099 scanExpr(tree.rhs);
3100 letInit(tree.lhs);
3101 }
3102
3103 // check fields accessed through this.<field> are definitely
3104 // assigned before reading their value
3105 public void visitSelect(JCFieldAccess tree) {
3106 ThisExposability priorThisExposability = this.thisExposability;
3107 try {
3108 if (tree.name == names._this && classDef != null && tree.sym.owner == classDef.sym) {
3109 checkEmbryonicThisExposure(tree);
3110 } else if (tree.sym.kind == VAR || tree.sym.isStatic()) {
3111 this.thisExposability = ALLOWED;
3112 }
3113 super.visitSelect(tree);
3114 if (TreeInfo.isThisQualifier(tree.selected) &&
3115 tree.sym.kind == VAR) {
3116 checkInit(tree.pos(), (VarSymbol)tree.sym);
3117 }
3118 } finally {
3119 this.thisExposability = priorThisExposability;
3120 }
3121 }
3122
3123 public void visitAssignop(JCAssignOp tree) {
3124 scanExpr(tree.lhs);
3125 scanExpr(tree.rhs);
3126 letInit(tree.lhs);
3127 }
3128
3129 public void visitUnary(JCUnary tree) {
3130 switch (tree.getTag()) {
3131 case NOT:
3132 scanCond(tree.arg);
3133 final Bits t = new Bits(initsWhenFalse);
3134 initsWhenFalse.assign(initsWhenTrue);
3135 initsWhenTrue.assign(t);
3136 t.assign(uninitsWhenFalse);
3137 uninitsWhenFalse.assign(uninitsWhenTrue);
3138 uninitsWhenTrue.assign(t);
3139 break;
3163 scanCond(tree.lhs);
3164 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3165 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3166 inits.assign(initsWhenFalse);
3167 uninits.assign(uninitsWhenFalse);
3168 scanCond(tree.rhs);
3169 initsWhenTrue.andSet(initsWhenTrueLeft);
3170 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3171 break;
3172 default:
3173 scanExpr(tree.lhs);
3174 scanExpr(tree.rhs);
3175 }
3176 }
3177
3178 public void visitIdent(JCIdent tree) {
3179 if (tree.sym.kind == VAR) {
3180 checkInit(tree.pos(), (VarSymbol)tree.sym);
3181 referenced(tree.sym);
3182 }
3183 if (tree.name == names._this) {
3184 checkEmbryonicThisExposure(tree);
3185 }
3186 }
3187
3188 @Override
3189 public void visitTypeTest(JCInstanceOf tree) {
3190 scanExpr(tree.expr);
3191 scan(tree.pattern);
3192 }
3193
3194 @Override
3195 public void visitBindingPattern(JCBindingPattern tree) {
3196 scan(tree.var);
3197 initParam(tree.var);
3198 }
3199
3200 void referenced(Symbol sym) {
3201 unrefdResources.remove(sym);
3202 }
3203
3204 public void visitAnnotatedType(JCAnnotatedType tree) {
3205 // annotations don't get scanned
|