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
1570 caught = chk.incl(ct.type, caught);
1571 }
1572 }
1573
1574 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1575 pendingExits = new ListBuffer<>();
1576 for (JCTree resource : tree.resources) {
1577 if (resource instanceof JCVariableDecl variableDecl) {
1578 visitVarDef(variableDecl);
1579 } else if (resource instanceof JCExpression expression) {
1580 scan(expression);
1581 } else {
1582 throw new AssertionError(tree); // parser error
1583 }
1584 }
1585 for (JCTree resource : tree.resources) {
1586 List<Type> closeableSupertypes = resource.type.isCompound() ?
1587 types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1588 List.of(resource.type);
1589 for (Type sup : closeableSupertypes) {
1590 if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1591 Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1592 attrEnv,
1593 types.skipTypeVars(sup, false),
1594 names.close,
1595 List.nil(),
1596 List.nil());
1597 Type mt = types.memberType(resource.type, closeMethod);
1598 if (closeMethod.kind == MTH) {
1599 for (Type t : mt.getThrownTypes()) {
1600 markThrown(resource, t);
1601 }
1602 }
1603 }
1604 }
1605 }
1606 scan(tree.body);
1607 List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1608 thrown = thrownPrev;
1609 caught = caughtPrev;
1610
2017 inLambda = true;
2018 try {
2019 pendingExits = new ListBuffer<>();
2020 caught = List.of(syms.throwableType);
2021 thrown = List.nil();
2022 scan(tree.body);
2023 inferredThrownTypes = thrown;
2024 } finally {
2025 pendingExits = prevPending;
2026 caught = prevCaught;
2027 thrown = prevThrown;
2028 inLambda = false;
2029 }
2030 }
2031 @Override
2032 public void visitClassDef(JCClassDecl tree) {
2033 //skip
2034 }
2035 }
2036
2037 /**
2038 * This pass implements (i) definite assignment analysis, which ensures that
2039 * each variable is assigned when used and (ii) definite unassignment analysis,
2040 * which ensures that no final variable is assigned more than once. This visitor
2041 * depends on the results of the liveliness analyzer. This pass is also used to mark
2042 * effectively-final local variables/parameters.
2043 */
2044
2045 public class AssignAnalyzer extends BaseAnalyzer {
2046
2047 /** The set of definitely assigned variables.
2048 */
2049 final Bits inits;
2050
2051 /** The set of definitely unassigned variables.
2052 */
2053 final Bits uninits;
2054
2055 /** The set of variables that are definitely unassigned everywhere
2056 * in current try block. This variable is maintained lazily; it is
2105 final Bits inits;
2106 final Bits uninits;
2107 final Bits exit_inits = new Bits(true);
2108 final Bits exit_uninits = new Bits(true);
2109
2110 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2111 super(tree);
2112 this.inits = inits;
2113 this.uninits = uninits;
2114 this.exit_inits.assign(inits);
2115 this.exit_uninits.assign(uninits);
2116 }
2117
2118 @Override
2119 public void resolveJump() {
2120 inits.andSet(exit_inits);
2121 uninits.andSet(exit_uninits);
2122 }
2123 }
2124
2125 public AssignAnalyzer() {
2126 this.inits = new Bits();
2127 uninits = new Bits();
2128 uninitsTry = new Bits();
2129 initsWhenTrue = new Bits(true);
2130 initsWhenFalse = new Bits(true);
2131 uninitsWhenTrue = new Bits(true);
2132 uninitsWhenFalse = new Bits(true);
2133 }
2134
2135 private boolean isInitialConstructor = false;
2136
2137 @Override
2138 protected void markDead() {
2139 if (!isInitialConstructor) {
2140 inits.inclRange(returnadr, nextadr);
2141 } else {
2142 for (int address = returnadr; address < nextadr; address++) {
2143 if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
2144 inits.incl(address);
2230 } else {
2231 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2232 uninits.excl(sym.adr);
2233 }
2234 }
2235
2236 /** If tree is either a simple name or of the form this.name or
2237 * C.this.name, and tree represents a trackable variable,
2238 * record an initialization of the variable.
2239 */
2240 void letInit(JCTree tree) {
2241 tree = TreeInfo.skipParens(tree);
2242 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2243 Symbol sym = TreeInfo.symbol(tree);
2244 if (sym.kind == VAR) {
2245 letInit(tree.pos(), (VarSymbol)sym);
2246 }
2247 }
2248 }
2249
2250 /** Check that trackable variable is initialized.
2251 */
2252 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2253 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2254 }
2255
2256 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2257 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2258 trackable(sym) &&
2259 !inits.isMember(sym.adr) &&
2260 (sym.flags_field & CLASH) == 0) {
2261 log.error(pos, errkey);
2262 inits.incl(sym.adr);
2263 }
2264 }
2265
2266 /** Utility method to reset several Bits instances.
2267 */
2268 private void resetBits(Bits... bits) {
2269 for (Bits b : bits) {
2435 classDef = classDefPrev;
2436 }
2437 } finally {
2438 lint = lintPrev;
2439 }
2440 }
2441
2442 public void visitMethodDef(JCMethodDecl tree) {
2443 if (tree.body == null) {
2444 return;
2445 }
2446
2447 /* MemberEnter can generate synthetic methods ignore them
2448 */
2449 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2450 return;
2451 }
2452
2453 Lint lintPrev = lint;
2454 lint = lint.augment(tree.sym);
2455 try {
2456 final Bits initsPrev = new Bits(inits);
2457 final Bits uninitsPrev = new Bits(uninits);
2458 int nextadrPrev = nextadr;
2459 int firstadrPrev = firstadr;
2460 int returnadrPrev = returnadr;
2461
2462 Assert.check(pendingExits.isEmpty());
2463 boolean lastInitialConstructor = isInitialConstructor;
2464 try {
2465 isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2466
2467 if (!isInitialConstructor) {
2468 firstadr = nextadr;
2469 }
2470 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2471 JCVariableDecl def = l.head;
2472 scan(def);
2473 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2474 /* If we are executing the code from Gen, then there can be
2475 * synthetic or mandated variables, ignore them.
2476 */
2477 initParam(def);
2478 }
2479 // else we are in an instance initializer block;
2480 // leave caught unchanged.
2481 scan(tree.body);
2482
2483 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2484 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2485 if (isInitialConstructor) {
2486 boolean isSynthesized = (tree.sym.flags() &
2487 GENERATEDCONSTR) != 0;
2488 for (int i = firstadr; i < nextadr; i++) {
2511 } else {
2512 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2513 }
2514 } else {
2515 checkInit(TreeInfo.diagEndPos(tree.body), var);
2516 }
2517 }
2518 }
2519 }
2520 clearPendingExits(true);
2521 } finally {
2522 inits.assign(initsPrev);
2523 uninits.assign(uninitsPrev);
2524 nextadr = nextadrPrev;
2525 firstadr = firstadrPrev;
2526 returnadr = returnadrPrev;
2527 isInitialConstructor = lastInitialConstructor;
2528 }
2529 } finally {
2530 lint = lintPrev;
2531 }
2532 }
2533
2534 private void clearPendingExits(boolean inMethod) {
2535 List<PendingExit> exits = pendingExits.toList();
2536 pendingExits = new ListBuffer<>();
2537 while (exits.nonEmpty()) {
2538 PendingExit exit = exits.head;
2539 exits = exits.tail;
2540 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2541 log.hasErrorOn(exit.tree.pos()),
2542 exit.tree);
2543 if (inMethod && isInitialConstructor) {
2544 Assert.check(exit instanceof AssignPendingExit);
2545 inits.assign(((AssignPendingExit) exit).exit_inits);
2546 for (int i = firstadr; i < nextadr; i++) {
2547 checkInit(exit.tree.pos(), vardecls[i].sym);
2548 }
2549 }
2550 }
2979
2980 @Override
2981 public void visitContinue(JCContinue tree) {
2982 recordExit(new AssignPendingExit(tree, inits, uninits));
2983 }
2984
2985 @Override
2986 public void visitReturn(JCReturn tree) {
2987 scanExpr(tree.expr);
2988 recordExit(new AssignPendingExit(tree, inits, uninits));
2989 }
2990
2991 public void visitThrow(JCThrow tree) {
2992 scanExpr(tree.expr);
2993 markDead();
2994 }
2995
2996 public void visitApply(JCMethodInvocation tree) {
2997 scanExpr(tree.meth);
2998 scanExprs(tree.args);
2999 }
3000
3001 public void visitNewClass(JCNewClass tree) {
3002 scanExpr(tree.encl);
3003 scanExprs(tree.args);
3004 scan(tree.def);
3005 }
3006
3007 @Override
3008 public void visitLambda(JCLambda tree) {
3009 final Bits prevUninits = new Bits(uninits);
3010 final Bits prevUninitsTry = new Bits(uninitsTry);
3011 final Bits prevInits = new Bits(inits);
3012 int returnadrPrev = returnadr;
3013 int nextadrPrev = nextadr;
3014 ListBuffer<PendingExit> prevPending = pendingExits;
3015 try {
3016 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
3017 // body. This is by design: a variable that was definitely unassigned before the
3018 // lambda body may end up being assigned to later on, so we cannot conclude that
3019 // the variable will be unassigned when the body is executed.
3020 uninits.excludeFrom(firstadr);
3021 returnadr = nextadr;
3022 pendingExits = new ListBuffer<>();
3023 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
3024 JCVariableDecl def = l.head;
3054 uninitsExit.andSet(uninitsWhenTrue);
3055 if (tree.detail != null) {
3056 inits.assign(initsWhenFalse);
3057 uninits.assign(uninitsWhenFalse);
3058 scanExpr(tree.detail);
3059 }
3060 inits.assign(initsExit);
3061 uninits.assign(uninitsExit);
3062 }
3063
3064 public void visitAssign(JCAssign tree) {
3065 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3066 scanExpr(tree.lhs);
3067 scanExpr(tree.rhs);
3068 letInit(tree.lhs);
3069 }
3070
3071 // check fields accessed through this.<field> are definitely
3072 // assigned before reading their value
3073 public void visitSelect(JCFieldAccess tree) {
3074 super.visitSelect(tree);
3075 if (TreeInfo.isThisQualifier(tree.selected) &&
3076 tree.sym.kind == VAR) {
3077 checkInit(tree.pos(), (VarSymbol)tree.sym);
3078 }
3079 }
3080
3081 public void visitAssignop(JCAssignOp tree) {
3082 scanExpr(tree.lhs);
3083 scanExpr(tree.rhs);
3084 letInit(tree.lhs);
3085 }
3086
3087 public void visitUnary(JCUnary tree) {
3088 switch (tree.getTag()) {
3089 case NOT:
3090 scanCond(tree.arg);
3091 final Bits t = new Bits(initsWhenFalse);
3092 initsWhenFalse.assign(initsWhenTrue);
3093 initsWhenTrue.assign(t);
3094 t.assign(uninitsWhenFalse);
3095 uninitsWhenFalse.assign(uninitsWhenTrue);
3096 uninitsWhenTrue.assign(t);
3097 break;
3121 scanCond(tree.lhs);
3122 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3123 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3124 inits.assign(initsWhenFalse);
3125 uninits.assign(uninitsWhenFalse);
3126 scanCond(tree.rhs);
3127 initsWhenTrue.andSet(initsWhenTrueLeft);
3128 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3129 break;
3130 default:
3131 scanExpr(tree.lhs);
3132 scanExpr(tree.rhs);
3133 }
3134 }
3135
3136 public void visitIdent(JCIdent tree) {
3137 if (tree.sym.kind == VAR) {
3138 checkInit(tree.pos(), (VarSymbol)tree.sym);
3139 referenced(tree.sym);
3140 }
3141 }
3142
3143 @Override
3144 public void visitTypeTest(JCInstanceOf tree) {
3145 scanExpr(tree.expr);
3146 scan(tree.pattern);
3147 }
3148
3149 @Override
3150 public void visitBindingPattern(JCBindingPattern tree) {
3151 scan(tree.var);
3152 initParam(tree.var);
3153 }
3154
3155 void referenced(Symbol sym) {
3156 unrefdResources.remove(sym);
3157 }
3158
3159 public void visitAnnotatedType(JCAnnotatedType tree) {
3160 // 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
1572 caught = chk.incl(ct.type, caught);
1573 }
1574 }
1575
1576 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1577 pendingExits = new ListBuffer<>();
1578 for (JCTree resource : tree.resources) {
1579 if (resource instanceof JCVariableDecl variableDecl) {
1580 visitVarDef(variableDecl);
1581 } else if (resource instanceof JCExpression expression) {
1582 scan(expression);
1583 } else {
1584 throw new AssertionError(tree); // parser error
1585 }
1586 }
1587 for (JCTree resource : tree.resources) {
1588 List<Type> closeableSupertypes = resource.type.isCompound() ?
1589 types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1590 List.of(resource.type);
1591 for (Type sup : closeableSupertypes) {
1592 if (types.asSuper(sup.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) != null) {
1593 Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1594 attrEnv,
1595 types.skipTypeVars(sup, false),
1596 names.close,
1597 List.nil(),
1598 List.nil());
1599 Type mt = types.memberType(resource.type, closeMethod);
1600 if (closeMethod.kind == MTH) {
1601 for (Type t : mt.getThrownTypes()) {
1602 markThrown(resource, t);
1603 }
1604 }
1605 }
1606 }
1607 }
1608 scan(tree.body);
1609 List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1610 thrown = thrownPrev;
1611 caught = caughtPrev;
1612
2019 inLambda = true;
2020 try {
2021 pendingExits = new ListBuffer<>();
2022 caught = List.of(syms.throwableType);
2023 thrown = List.nil();
2024 scan(tree.body);
2025 inferredThrownTypes = thrown;
2026 } finally {
2027 pendingExits = prevPending;
2028 caught = prevCaught;
2029 thrown = prevThrown;
2030 inLambda = false;
2031 }
2032 }
2033 @Override
2034 public void visitClassDef(JCClassDecl tree) {
2035 //skip
2036 }
2037 }
2038
2039 /** Enum to model whether constructors allowed to "leak" this reference before
2040 all instance fields are DA.
2041 */
2042 enum ThisExposability {
2043 ALLOWED, // identity Object classes - NOP
2044 BANNED, // primitive/value classes - Error
2045 }
2046
2047 /**
2048 * This pass implements (i) definite assignment analysis, which ensures that
2049 * each variable is assigned when used and (ii) definite unassignment analysis,
2050 * which ensures that no final variable is assigned more than once. This visitor
2051 * depends on the results of the liveliness analyzer. This pass is also used to mark
2052 * effectively-final local variables/parameters.
2053 */
2054
2055 public class AssignAnalyzer extends BaseAnalyzer {
2056
2057 /** The set of definitely assigned variables.
2058 */
2059 final Bits inits;
2060
2061 /** The set of definitely unassigned variables.
2062 */
2063 final Bits uninits;
2064
2065 /** The set of variables that are definitely unassigned everywhere
2066 * in current try block. This variable is maintained lazily; it is
2115 final Bits inits;
2116 final Bits uninits;
2117 final Bits exit_inits = new Bits(true);
2118 final Bits exit_uninits = new Bits(true);
2119
2120 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2121 super(tree);
2122 this.inits = inits;
2123 this.uninits = uninits;
2124 this.exit_inits.assign(inits);
2125 this.exit_uninits.assign(uninits);
2126 }
2127
2128 @Override
2129 public void resolveJump() {
2130 inits.andSet(exit_inits);
2131 uninits.andSet(exit_uninits);
2132 }
2133 }
2134
2135 // Are constructors allowed to leak this reference ?
2136 ThisExposability thisExposability = ALLOWED;
2137
2138 public AssignAnalyzer() {
2139 this.inits = new Bits();
2140 uninits = new Bits();
2141 uninitsTry = new Bits();
2142 initsWhenTrue = new Bits(true);
2143 initsWhenFalse = new Bits(true);
2144 uninitsWhenTrue = new Bits(true);
2145 uninitsWhenFalse = new Bits(true);
2146 }
2147
2148 private boolean isInitialConstructor = false;
2149
2150 @Override
2151 protected void markDead() {
2152 if (!isInitialConstructor) {
2153 inits.inclRange(returnadr, nextadr);
2154 } else {
2155 for (int address = returnadr; address < nextadr; address++) {
2156 if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
2157 inits.incl(address);
2243 } else {
2244 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2245 uninits.excl(sym.adr);
2246 }
2247 }
2248
2249 /** If tree is either a simple name or of the form this.name or
2250 * C.this.name, and tree represents a trackable variable,
2251 * record an initialization of the variable.
2252 */
2253 void letInit(JCTree tree) {
2254 tree = TreeInfo.skipParens(tree);
2255 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2256 Symbol sym = TreeInfo.symbol(tree);
2257 if (sym.kind == VAR) {
2258 letInit(tree.pos(), (VarSymbol)sym);
2259 }
2260 }
2261 }
2262
2263 void checkEmbryonicThisExposure(JCTree node) {
2264 if (this.thisExposability == ALLOWED || classDef == null)
2265 return;
2266
2267 // Note: for non-initial constructors, firstadr is post all instance fields.
2268 for (int i = firstadr; i < nextadr; i++) {
2269 VarSymbol sym = vardecls[i].sym;
2270 if (sym.owner != classDef.sym)
2271 continue;
2272 if ((sym.flags() & (FINAL | HASINIT | STATIC | PARAMETER)) != FINAL)
2273 continue;
2274 if (sym.pos < startPos || sym.adr < firstadr)
2275 continue;
2276 if (!inits.isMember(sym.adr)) {
2277 if (this.thisExposability == BANNED) {
2278 log.error(node, Errors.ThisExposedPrematurely);
2279 }
2280 return; // don't flog a dead horse.
2281 }
2282 }
2283 }
2284
2285 /** Check that trackable variable is initialized.
2286 */
2287 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2288 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2289 }
2290
2291 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2292 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2293 trackable(sym) &&
2294 !inits.isMember(sym.adr) &&
2295 (sym.flags_field & CLASH) == 0) {
2296 log.error(pos, errkey);
2297 inits.incl(sym.adr);
2298 }
2299 }
2300
2301 /** Utility method to reset several Bits instances.
2302 */
2303 private void resetBits(Bits... bits) {
2304 for (Bits b : bits) {
2470 classDef = classDefPrev;
2471 }
2472 } finally {
2473 lint = lintPrev;
2474 }
2475 }
2476
2477 public void visitMethodDef(JCMethodDecl tree) {
2478 if (tree.body == null) {
2479 return;
2480 }
2481
2482 /* MemberEnter can generate synthetic methods ignore them
2483 */
2484 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2485 return;
2486 }
2487
2488 Lint lintPrev = lint;
2489 lint = lint.augment(tree.sym);
2490 ThisExposability priorThisExposability = this.thisExposability;
2491 try {
2492 final Bits initsPrev = new Bits(inits);
2493 final Bits uninitsPrev = new Bits(uninits);
2494 int nextadrPrev = nextadr;
2495 int firstadrPrev = firstadr;
2496 int returnadrPrev = returnadr;
2497
2498 Assert.check(pendingExits.isEmpty());
2499 boolean lastInitialConstructor = isInitialConstructor;
2500 try {
2501 isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2502
2503 if (!isInitialConstructor) {
2504 firstadr = nextadr;
2505 this.thisExposability = ALLOWED;
2506 } else {
2507 if (tree.sym.owner.type.isValueClass())
2508 this.thisExposability = BANNED;
2509 else
2510 this.thisExposability = ALLOWED;
2511 }
2512 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2513 JCVariableDecl def = l.head;
2514 scan(def);
2515 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2516 /* If we are executing the code from Gen, then there can be
2517 * synthetic or mandated variables, ignore them.
2518 */
2519 initParam(def);
2520 }
2521 // else we are in an instance initializer block;
2522 // leave caught unchanged.
2523 scan(tree.body);
2524
2525 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2526 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2527 if (isInitialConstructor) {
2528 boolean isSynthesized = (tree.sym.flags() &
2529 GENERATEDCONSTR) != 0;
2530 for (int i = firstadr; i < nextadr; i++) {
2553 } else {
2554 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2555 }
2556 } else {
2557 checkInit(TreeInfo.diagEndPos(tree.body), var);
2558 }
2559 }
2560 }
2561 }
2562 clearPendingExits(true);
2563 } finally {
2564 inits.assign(initsPrev);
2565 uninits.assign(uninitsPrev);
2566 nextadr = nextadrPrev;
2567 firstadr = firstadrPrev;
2568 returnadr = returnadrPrev;
2569 isInitialConstructor = lastInitialConstructor;
2570 }
2571 } finally {
2572 lint = lintPrev;
2573 this.thisExposability = priorThisExposability;
2574 }
2575 }
2576
2577 private void clearPendingExits(boolean inMethod) {
2578 List<PendingExit> exits = pendingExits.toList();
2579 pendingExits = new ListBuffer<>();
2580 while (exits.nonEmpty()) {
2581 PendingExit exit = exits.head;
2582 exits = exits.tail;
2583 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2584 log.hasErrorOn(exit.tree.pos()),
2585 exit.tree);
2586 if (inMethod && isInitialConstructor) {
2587 Assert.check(exit instanceof AssignPendingExit);
2588 inits.assign(((AssignPendingExit) exit).exit_inits);
2589 for (int i = firstadr; i < nextadr; i++) {
2590 checkInit(exit.tree.pos(), vardecls[i].sym);
2591 }
2592 }
2593 }
3022
3023 @Override
3024 public void visitContinue(JCContinue tree) {
3025 recordExit(new AssignPendingExit(tree, inits, uninits));
3026 }
3027
3028 @Override
3029 public void visitReturn(JCReturn tree) {
3030 scanExpr(tree.expr);
3031 recordExit(new AssignPendingExit(tree, inits, uninits));
3032 }
3033
3034 public void visitThrow(JCThrow tree) {
3035 scanExpr(tree.expr);
3036 markDead();
3037 }
3038
3039 public void visitApply(JCMethodInvocation tree) {
3040 scanExpr(tree.meth);
3041 scanExprs(tree.args);
3042 if (tree.meth.hasTag(IDENT)) {
3043 JCIdent ident = (JCIdent) tree.meth;
3044 if (ident.name != names._super && !ident.sym.isStatic())
3045 checkEmbryonicThisExposure(tree);
3046 }
3047 }
3048
3049 public void visitNewClass(JCNewClass tree) {
3050 scanExpr(tree.encl);
3051 scanExprs(tree.args);
3052 scan(tree.def);
3053 if (classDef != null && tree.encl == null && tree.clazz.hasTag(IDENT)) {
3054 JCIdent clazz = (JCIdent) tree.clazz;
3055 if (!clazz.sym.isStatic() && clazz.type.getEnclosingType().tsym == classDef.sym) {
3056 checkEmbryonicThisExposure(tree);
3057 }
3058 }
3059 }
3060
3061 @Override
3062 public void visitLambda(JCLambda tree) {
3063 final Bits prevUninits = new Bits(uninits);
3064 final Bits prevUninitsTry = new Bits(uninitsTry);
3065 final Bits prevInits = new Bits(inits);
3066 int returnadrPrev = returnadr;
3067 int nextadrPrev = nextadr;
3068 ListBuffer<PendingExit> prevPending = pendingExits;
3069 try {
3070 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
3071 // body. This is by design: a variable that was definitely unassigned before the
3072 // lambda body may end up being assigned to later on, so we cannot conclude that
3073 // the variable will be unassigned when the body is executed.
3074 uninits.excludeFrom(firstadr);
3075 returnadr = nextadr;
3076 pendingExits = new ListBuffer<>();
3077 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
3078 JCVariableDecl def = l.head;
3108 uninitsExit.andSet(uninitsWhenTrue);
3109 if (tree.detail != null) {
3110 inits.assign(initsWhenFalse);
3111 uninits.assign(uninitsWhenFalse);
3112 scanExpr(tree.detail);
3113 }
3114 inits.assign(initsExit);
3115 uninits.assign(uninitsExit);
3116 }
3117
3118 public void visitAssign(JCAssign tree) {
3119 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3120 scanExpr(tree.lhs);
3121 scanExpr(tree.rhs);
3122 letInit(tree.lhs);
3123 }
3124
3125 // check fields accessed through this.<field> are definitely
3126 // assigned before reading their value
3127 public void visitSelect(JCFieldAccess tree) {
3128 ThisExposability priorThisExposability = this.thisExposability;
3129 try {
3130 if (tree.name == names._this && classDef != null && tree.sym.owner == classDef.sym) {
3131 checkEmbryonicThisExposure(tree);
3132 } else if (tree.sym.kind == VAR || tree.sym.isStatic()) {
3133 this.thisExposability = ALLOWED;
3134 }
3135 super.visitSelect(tree);
3136 if (TreeInfo.isThisQualifier(tree.selected) &&
3137 tree.sym.kind == VAR) {
3138 checkInit(tree.pos(), (VarSymbol)tree.sym);
3139 }
3140 } finally {
3141 this.thisExposability = priorThisExposability;
3142 }
3143 }
3144
3145 public void visitAssignop(JCAssignOp tree) {
3146 scanExpr(tree.lhs);
3147 scanExpr(tree.rhs);
3148 letInit(tree.lhs);
3149 }
3150
3151 public void visitUnary(JCUnary tree) {
3152 switch (tree.getTag()) {
3153 case NOT:
3154 scanCond(tree.arg);
3155 final Bits t = new Bits(initsWhenFalse);
3156 initsWhenFalse.assign(initsWhenTrue);
3157 initsWhenTrue.assign(t);
3158 t.assign(uninitsWhenFalse);
3159 uninitsWhenFalse.assign(uninitsWhenTrue);
3160 uninitsWhenTrue.assign(t);
3161 break;
3185 scanCond(tree.lhs);
3186 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3187 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3188 inits.assign(initsWhenFalse);
3189 uninits.assign(uninitsWhenFalse);
3190 scanCond(tree.rhs);
3191 initsWhenTrue.andSet(initsWhenTrueLeft);
3192 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3193 break;
3194 default:
3195 scanExpr(tree.lhs);
3196 scanExpr(tree.rhs);
3197 }
3198 }
3199
3200 public void visitIdent(JCIdent tree) {
3201 if (tree.sym.kind == VAR) {
3202 checkInit(tree.pos(), (VarSymbol)tree.sym);
3203 referenced(tree.sym);
3204 }
3205 if (tree.name == names._this) {
3206 checkEmbryonicThisExposure(tree);
3207 }
3208 }
3209
3210 @Override
3211 public void visitTypeTest(JCInstanceOf tree) {
3212 scanExpr(tree.expr);
3213 scan(tree.pattern);
3214 }
3215
3216 @Override
3217 public void visitBindingPattern(JCBindingPattern tree) {
3218 scan(tree.var);
3219 initParam(tree.var);
3220 }
3221
3222 void referenced(Symbol sym) {
3223 unrefdResources.remove(sym);
3224 }
3225
3226 public void visitAnnotatedType(JCAnnotatedType tree) {
3227 // annotations don't get scanned
|