40 import com.sun.tools.javac.code.Scope.WriteableScope;
41 import com.sun.tools.javac.code.Source.Feature;
42 import com.sun.tools.javac.resources.CompilerProperties.Errors;
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.*;
51 import com.sun.tools.javac.tree.JCTree.*;
52
53 import static com.sun.tools.javac.code.Flags.*;
54 import static com.sun.tools.javac.code.Flags.BLOCK;
55 import static com.sun.tools.javac.code.Kinds.Kind.*;
56 import com.sun.tools.javac.code.Type.TypeVar;
57 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
58 import static com.sun.tools.javac.code.TypeTag.NONE;
59 import static com.sun.tools.javac.code.TypeTag.VOID;
60 import com.sun.tools.javac.code.Types.UniqueType;
61 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
62 import static com.sun.tools.javac.tree.JCTree.Tag.*;
63 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
64
65 /** This pass implements dataflow analysis for Java programs though
66 * different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
67 * every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
68 * every checked exception that is thrown is declared or caught. Definite assignment analysis
69 * (see AssignAnalyzer) ensures that each variable is assigned when used. Definite
70 * unassignment analysis (see AssignAnalyzer) in ensures that no final variable
71 * is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
72 * determines that local variables accessed within the scope of an inner class/lambda
73 * are either final or effectively-final.
74 *
75 * <p>The JLS has a number of problems in the
76 * specification of these flow analysis problems. This implementation
77 * attempts to address those issues.
78 *
79 * <p>First, there is no accommodation for a finally clause that cannot
1429 caught = chk.incl(ct.type, caught);
1430 }
1431 }
1432
1433 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1434 pendingExits = new ListBuffer<>();
1435 for (JCTree resource : tree.resources) {
1436 if (resource instanceof JCVariableDecl variableDecl) {
1437 visitVarDef(variableDecl);
1438 } else if (resource instanceof JCExpression expression) {
1439 scan(expression);
1440 } else {
1441 throw new AssertionError(tree); // parser error
1442 }
1443 }
1444 for (JCTree resource : tree.resources) {
1445 List<Type> closeableSupertypes = resource.type.isCompound() ?
1446 types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1447 List.of(resource.type);
1448 for (Type sup : closeableSupertypes) {
1449 if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1450 Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1451 attrEnv,
1452 types.skipTypeVars(sup, false),
1453 names.close,
1454 List.nil(),
1455 List.nil());
1456 Type mt = types.memberType(resource.type, closeMethod);
1457 if (closeMethod.kind == MTH) {
1458 for (Type t : mt.getThrownTypes()) {
1459 markThrown(resource, t);
1460 }
1461 }
1462 }
1463 }
1464 }
1465 scan(tree.body);
1466 List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1467 thrown = thrownPrev;
1468 caught = caughtPrev;
1469
1852 inLambda = true;
1853 try {
1854 pendingExits = new ListBuffer<>();
1855 caught = List.of(syms.throwableType);
1856 thrown = List.nil();
1857 scan(tree.body);
1858 inferredThrownTypes = thrown;
1859 } finally {
1860 pendingExits = prevPending;
1861 caught = prevCaught;
1862 thrown = prevThrown;
1863 inLambda = false;
1864 }
1865 }
1866 @Override
1867 public void visitClassDef(JCClassDecl tree) {
1868 //skip
1869 }
1870 }
1871
1872 /**
1873 * This pass implements (i) definite assignment analysis, which ensures that
1874 * each variable is assigned when used and (ii) definite unassignment analysis,
1875 * which ensures that no final variable is assigned more than once. This visitor
1876 * depends on the results of the liveliness analyzer. This pass is also used to mark
1877 * effectively-final local variables/parameters.
1878 */
1879
1880 public class AssignAnalyzer extends BaseAnalyzer {
1881
1882 /** The set of definitely assigned variables.
1883 */
1884 final Bits inits;
1885
1886 /** The set of definitely unassigned variables.
1887 */
1888 final Bits uninits;
1889
1890 /** The set of variables that are definitely unassigned everywhere
1891 * in current try block. This variable is maintained lazily; it is
1940 final Bits inits;
1941 final Bits uninits;
1942 final Bits exit_inits = new Bits(true);
1943 final Bits exit_uninits = new Bits(true);
1944
1945 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
1946 super(tree);
1947 this.inits = inits;
1948 this.uninits = uninits;
1949 this.exit_inits.assign(inits);
1950 this.exit_uninits.assign(uninits);
1951 }
1952
1953 @Override
1954 public void resolveJump() {
1955 inits.andSet(exit_inits);
1956 uninits.andSet(exit_uninits);
1957 }
1958 }
1959
1960 public AssignAnalyzer() {
1961 this.inits = new Bits();
1962 uninits = new Bits();
1963 uninitsTry = new Bits();
1964 initsWhenTrue = new Bits(true);
1965 initsWhenFalse = new Bits(true);
1966 uninitsWhenTrue = new Bits(true);
1967 uninitsWhenFalse = new Bits(true);
1968 }
1969
1970 private boolean isInitialConstructor = false;
1971
1972 @Override
1973 protected void markDead() {
1974 if (!isInitialConstructor) {
1975 inits.inclRange(returnadr, nextadr);
1976 } else {
1977 for (int address = returnadr; address < nextadr; address++) {
1978 if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
1979 inits.incl(address);
2064 } else {
2065 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2066 uninits.excl(sym.adr);
2067 }
2068 }
2069
2070 /** If tree is either a simple name or of the form this.name or
2071 * C.this.name, and tree represents a trackable variable,
2072 * record an initialization of the variable.
2073 */
2074 void letInit(JCTree tree) {
2075 tree = TreeInfo.skipParens(tree);
2076 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2077 Symbol sym = TreeInfo.symbol(tree);
2078 if (sym.kind == VAR) {
2079 letInit(tree.pos(), (VarSymbol)sym);
2080 }
2081 }
2082 }
2083
2084 /** Check that trackable variable is initialized.
2085 */
2086 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2087 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2088 }
2089
2090 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2091 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2092 trackable(sym) &&
2093 !inits.isMember(sym.adr) &&
2094 (sym.flags_field & CLASH) == 0) {
2095 log.error(pos, errkey);
2096 inits.incl(sym.adr);
2097 }
2098 }
2099
2100 /** Utility method to reset several Bits instances.
2101 */
2102 private void resetBits(Bits... bits) {
2103 for (Bits b : bits) {
2264 classDef = classDefPrev;
2265 }
2266 } finally {
2267 lint = lintPrev;
2268 }
2269 }
2270
2271 public void visitMethodDef(JCMethodDecl tree) {
2272 if (tree.body == null) {
2273 return;
2274 }
2275
2276 /* MemberEnter can generate synthetic methods ignore them
2277 */
2278 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2279 return;
2280 }
2281
2282 Lint lintPrev = lint;
2283 lint = lint.augment(tree.sym);
2284 try {
2285 final Bits initsPrev = new Bits(inits);
2286 final Bits uninitsPrev = new Bits(uninits);
2287 int nextadrPrev = nextadr;
2288 int firstadrPrev = firstadr;
2289 int returnadrPrev = returnadr;
2290
2291 Assert.check(pendingExits.isEmpty());
2292 boolean lastInitialConstructor = isInitialConstructor;
2293 try {
2294 isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2295
2296 if (!isInitialConstructor) {
2297 firstadr = nextadr;
2298 }
2299 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2300 JCVariableDecl def = l.head;
2301 scan(def);
2302 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2303 /* If we are executing the code from Gen, then there can be
2304 * synthetic or mandated variables, ignore them.
2305 */
2306 initParam(def);
2307 }
2308 // else we are in an instance initializer block;
2309 // leave caught unchanged.
2310 scan(tree.body);
2311
2312 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2313 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2314 if (isInitialConstructor) {
2315 boolean isSynthesized = (tree.sym.flags() &
2316 GENERATEDCONSTR) != 0;
2317 for (int i = firstadr; i < nextadr; i++) {
2341 } else {
2342 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2343 }
2344 } else {
2345 checkInit(TreeInfo.diagEndPos(tree.body), var);
2346 }
2347 }
2348 }
2349 }
2350 clearPendingExits(true);
2351 } finally {
2352 inits.assign(initsPrev);
2353 uninits.assign(uninitsPrev);
2354 nextadr = nextadrPrev;
2355 firstadr = firstadrPrev;
2356 returnadr = returnadrPrev;
2357 isInitialConstructor = lastInitialConstructor;
2358 }
2359 } finally {
2360 lint = lintPrev;
2361 }
2362 }
2363
2364 private void clearPendingExits(boolean inMethod) {
2365 List<PendingExit> exits = pendingExits.toList();
2366 pendingExits = new ListBuffer<>();
2367 while (exits.nonEmpty()) {
2368 PendingExit exit = exits.head;
2369 exits = exits.tail;
2370 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2371 log.hasErrorOn(exit.tree.pos()),
2372 exit.tree);
2373 if (inMethod && isInitialConstructor) {
2374 Assert.check(exit instanceof AssignPendingExit);
2375 inits.assign(((AssignPendingExit) exit).exit_inits);
2376 for (int i = firstadr; i < nextadr; i++) {
2377 checkInit(exit.tree.pos(), vardecls[i].sym);
2378 }
2379 }
2380 }
2820
2821 @Override
2822 public void visitContinue(JCContinue tree) {
2823 recordExit(new AssignPendingExit(tree, inits, uninits));
2824 }
2825
2826 @Override
2827 public void visitReturn(JCReturn tree) {
2828 scanExpr(tree.expr);
2829 recordExit(new AssignPendingExit(tree, inits, uninits));
2830 }
2831
2832 public void visitThrow(JCThrow tree) {
2833 scanExpr(tree.expr);
2834 markDead();
2835 }
2836
2837 public void visitApply(JCMethodInvocation tree) {
2838 scanExpr(tree.meth);
2839 scanExprs(tree.args);
2840 }
2841
2842 public void visitNewClass(JCNewClass tree) {
2843 scanExpr(tree.encl);
2844 scanExprs(tree.args);
2845 scan(tree.def);
2846 }
2847
2848 @Override
2849 public void visitLambda(JCLambda tree) {
2850 final Bits prevUninits = new Bits(uninits);
2851 final Bits prevInits = new Bits(inits);
2852 int returnadrPrev = returnadr;
2853 int nextadrPrev = nextadr;
2854 ListBuffer<PendingExit> prevPending = pendingExits;
2855 try {
2856 returnadr = nextadr;
2857 pendingExits = new ListBuffer<>();
2858 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2859 JCVariableDecl def = l.head;
2860 scan(def);
2861 inits.incl(def.sym.adr);
2862 uninits.excl(def.sym.adr);
2863 }
2864 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
2865 scanExpr(tree.body);
2888 uninitsExit.andSet(uninitsWhenTrue);
2889 if (tree.detail != null) {
2890 inits.assign(initsWhenFalse);
2891 uninits.assign(uninitsWhenFalse);
2892 scanExpr(tree.detail);
2893 }
2894 inits.assign(initsExit);
2895 uninits.assign(uninitsExit);
2896 }
2897
2898 public void visitAssign(JCAssign tree) {
2899 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2900 scanExpr(tree.lhs);
2901 scanExpr(tree.rhs);
2902 letInit(tree.lhs);
2903 }
2904
2905 // check fields accessed through this.<field> are definitely
2906 // assigned before reading their value
2907 public void visitSelect(JCFieldAccess tree) {
2908 super.visitSelect(tree);
2909 if (TreeInfo.isThisQualifier(tree.selected) &&
2910 tree.sym.kind == VAR) {
2911 checkInit(tree.pos(), (VarSymbol)tree.sym);
2912 }
2913 }
2914
2915 public void visitAssignop(JCAssignOp tree) {
2916 scanExpr(tree.lhs);
2917 scanExpr(tree.rhs);
2918 letInit(tree.lhs);
2919 }
2920
2921 public void visitUnary(JCUnary tree) {
2922 switch (tree.getTag()) {
2923 case NOT:
2924 scanCond(tree.arg);
2925 final Bits t = new Bits(initsWhenFalse);
2926 initsWhenFalse.assign(initsWhenTrue);
2927 initsWhenTrue.assign(t);
2928 t.assign(uninitsWhenFalse);
2929 uninitsWhenFalse.assign(uninitsWhenTrue);
2930 uninitsWhenTrue.assign(t);
2931 break;
2955 scanCond(tree.lhs);
2956 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
2957 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
2958 inits.assign(initsWhenFalse);
2959 uninits.assign(uninitsWhenFalse);
2960 scanCond(tree.rhs);
2961 initsWhenTrue.andSet(initsWhenTrueLeft);
2962 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
2963 break;
2964 default:
2965 scanExpr(tree.lhs);
2966 scanExpr(tree.rhs);
2967 }
2968 }
2969
2970 public void visitIdent(JCIdent tree) {
2971 if (tree.sym.kind == VAR) {
2972 checkInit(tree.pos(), (VarSymbol)tree.sym);
2973 referenced(tree.sym);
2974 }
2975 }
2976
2977 @Override
2978 public void visitTypeTest(JCInstanceOf tree) {
2979 scanExpr(tree.expr);
2980 scan(tree.pattern);
2981 }
2982
2983 @Override
2984 public void visitBindingPattern(JCBindingPattern tree) {
2985 scan(tree.var);
2986 initParam(tree.var);
2987 }
2988
2989 @Override
2990 public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
2991 scan(tree.pat);
2992 scan(tree.guard);
2993 }
2994
|
40 import com.sun.tools.javac.code.Scope.WriteableScope;
41 import com.sun.tools.javac.code.Source.Feature;
42 import com.sun.tools.javac.resources.CompilerProperties.Errors;
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.*;
51 import com.sun.tools.javac.tree.JCTree.*;
52
53 import static com.sun.tools.javac.code.Flags.*;
54 import static com.sun.tools.javac.code.Flags.BLOCK;
55 import static com.sun.tools.javac.code.Kinds.Kind.*;
56 import com.sun.tools.javac.code.Type.TypeVar;
57 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
58 import static com.sun.tools.javac.code.TypeTag.NONE;
59 import static com.sun.tools.javac.code.TypeTag.VOID;
60 import static com.sun.tools.javac.comp.Flow.ThisExposability.ALLOWED;
61 import static com.sun.tools.javac.comp.Flow.ThisExposability.BANNED;
62 import com.sun.tools.javac.code.Types.UniqueType;
63 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
64 import static com.sun.tools.javac.tree.JCTree.Tag.*;
65 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
66
67 /** This pass implements dataflow analysis for Java programs though
68 * different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
69 * every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
70 * every checked exception that is thrown is declared or caught. Definite assignment analysis
71 * (see AssignAnalyzer) ensures that each variable is assigned when used. Definite
72 * unassignment analysis (see AssignAnalyzer) in ensures that no final variable
73 * is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
74 * determines that local variables accessed within the scope of an inner class/lambda
75 * are either final or effectively-final.
76 *
77 * <p>The JLS has a number of problems in the
78 * specification of these flow analysis problems. This implementation
79 * attempts to address those issues.
80 *
81 * <p>First, there is no accommodation for a finally clause that cannot
1431 caught = chk.incl(ct.type, caught);
1432 }
1433 }
1434
1435 ListBuffer<PendingExit> prevPendingExits = pendingExits;
1436 pendingExits = new ListBuffer<>();
1437 for (JCTree resource : tree.resources) {
1438 if (resource instanceof JCVariableDecl variableDecl) {
1439 visitVarDef(variableDecl);
1440 } else if (resource instanceof JCExpression expression) {
1441 scan(expression);
1442 } else {
1443 throw new AssertionError(tree); // parser error
1444 }
1445 }
1446 for (JCTree resource : tree.resources) {
1447 List<Type> closeableSupertypes = resource.type.isCompound() ?
1448 types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1449 List.of(resource.type);
1450 for (Type sup : closeableSupertypes) {
1451 if (types.asSuper(sup.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) != null) {
1452 Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1453 attrEnv,
1454 types.skipTypeVars(sup, false),
1455 names.close,
1456 List.nil(),
1457 List.nil());
1458 Type mt = types.memberType(resource.type, closeMethod);
1459 if (closeMethod.kind == MTH) {
1460 for (Type t : mt.getThrownTypes()) {
1461 markThrown(resource, t);
1462 }
1463 }
1464 }
1465 }
1466 }
1467 scan(tree.body);
1468 List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1469 thrown = thrownPrev;
1470 caught = caughtPrev;
1471
1854 inLambda = true;
1855 try {
1856 pendingExits = new ListBuffer<>();
1857 caught = List.of(syms.throwableType);
1858 thrown = List.nil();
1859 scan(tree.body);
1860 inferredThrownTypes = thrown;
1861 } finally {
1862 pendingExits = prevPending;
1863 caught = prevCaught;
1864 thrown = prevThrown;
1865 inLambda = false;
1866 }
1867 }
1868 @Override
1869 public void visitClassDef(JCClassDecl tree) {
1870 //skip
1871 }
1872 }
1873
1874 /** Enum to model whether constructors allowed to "leak" this reference before
1875 all instance fields are DA.
1876 */
1877 enum ThisExposability {
1878 ALLOWED, // identity Object classes - NOP
1879 BANNED, // primitive/value classes - Error
1880 }
1881
1882 /**
1883 * This pass implements (i) definite assignment analysis, which ensures that
1884 * each variable is assigned when used and (ii) definite unassignment analysis,
1885 * which ensures that no final variable is assigned more than once. This visitor
1886 * depends on the results of the liveliness analyzer. This pass is also used to mark
1887 * effectively-final local variables/parameters.
1888 */
1889
1890 public class AssignAnalyzer extends BaseAnalyzer {
1891
1892 /** The set of definitely assigned variables.
1893 */
1894 final Bits inits;
1895
1896 /** The set of definitely unassigned variables.
1897 */
1898 final Bits uninits;
1899
1900 /** The set of variables that are definitely unassigned everywhere
1901 * in current try block. This variable is maintained lazily; it is
1950 final Bits inits;
1951 final Bits uninits;
1952 final Bits exit_inits = new Bits(true);
1953 final Bits exit_uninits = new Bits(true);
1954
1955 public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
1956 super(tree);
1957 this.inits = inits;
1958 this.uninits = uninits;
1959 this.exit_inits.assign(inits);
1960 this.exit_uninits.assign(uninits);
1961 }
1962
1963 @Override
1964 public void resolveJump() {
1965 inits.andSet(exit_inits);
1966 uninits.andSet(exit_uninits);
1967 }
1968 }
1969
1970 // Are constructors allowed to leak this reference ?
1971 ThisExposability thisExposability = ALLOWED;
1972
1973 public AssignAnalyzer() {
1974 this.inits = new Bits();
1975 uninits = new Bits();
1976 uninitsTry = new Bits();
1977 initsWhenTrue = new Bits(true);
1978 initsWhenFalse = new Bits(true);
1979 uninitsWhenTrue = new Bits(true);
1980 uninitsWhenFalse = new Bits(true);
1981 }
1982
1983 private boolean isInitialConstructor = false;
1984
1985 @Override
1986 protected void markDead() {
1987 if (!isInitialConstructor) {
1988 inits.inclRange(returnadr, nextadr);
1989 } else {
1990 for (int address = returnadr; address < nextadr; address++) {
1991 if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
1992 inits.incl(address);
2077 } else {
2078 //log.rawWarning(pos, "unreachable assignment");//DEBUG
2079 uninits.excl(sym.adr);
2080 }
2081 }
2082
2083 /** If tree is either a simple name or of the form this.name or
2084 * C.this.name, and tree represents a trackable variable,
2085 * record an initialization of the variable.
2086 */
2087 void letInit(JCTree tree) {
2088 tree = TreeInfo.skipParens(tree);
2089 if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2090 Symbol sym = TreeInfo.symbol(tree);
2091 if (sym.kind == VAR) {
2092 letInit(tree.pos(), (VarSymbol)sym);
2093 }
2094 }
2095 }
2096
2097 void checkEmbryonicThisExposure(JCTree node) {
2098 if (this.thisExposability == ALLOWED || classDef == null)
2099 return;
2100
2101 // Note: for non-initial constructors, firstadr is post all instance fields.
2102 for (int i = firstadr; i < nextadr; i++) {
2103 VarSymbol sym = vardecls[i].sym;
2104 if (sym.owner != classDef.sym)
2105 continue;
2106 if ((sym.flags() & (FINAL | HASINIT | STATIC | PARAMETER)) != FINAL)
2107 continue;
2108 if (sym.pos < startPos || sym.adr < firstadr)
2109 continue;
2110 if (!inits.isMember(sym.adr)) {
2111 if (this.thisExposability == BANNED) {
2112 log.error(node, Errors.ThisExposedPrematurely);
2113 }
2114 return; // don't flog a dead horse.
2115 }
2116 }
2117 }
2118
2119 /** Check that trackable variable is initialized.
2120 */
2121 void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2122 checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2123 }
2124
2125 void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2126 if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2127 trackable(sym) &&
2128 !inits.isMember(sym.adr) &&
2129 (sym.flags_field & CLASH) == 0) {
2130 log.error(pos, errkey);
2131 inits.incl(sym.adr);
2132 }
2133 }
2134
2135 /** Utility method to reset several Bits instances.
2136 */
2137 private void resetBits(Bits... bits) {
2138 for (Bits b : bits) {
2299 classDef = classDefPrev;
2300 }
2301 } finally {
2302 lint = lintPrev;
2303 }
2304 }
2305
2306 public void visitMethodDef(JCMethodDecl tree) {
2307 if (tree.body == null) {
2308 return;
2309 }
2310
2311 /* MemberEnter can generate synthetic methods ignore them
2312 */
2313 if ((tree.sym.flags() & SYNTHETIC) != 0) {
2314 return;
2315 }
2316
2317 Lint lintPrev = lint;
2318 lint = lint.augment(tree.sym);
2319 ThisExposability priorThisExposability = this.thisExposability;
2320 try {
2321 final Bits initsPrev = new Bits(inits);
2322 final Bits uninitsPrev = new Bits(uninits);
2323 int nextadrPrev = nextadr;
2324 int firstadrPrev = firstadr;
2325 int returnadrPrev = returnadr;
2326
2327 Assert.check(pendingExits.isEmpty());
2328 boolean lastInitialConstructor = isInitialConstructor;
2329 try {
2330 isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2331
2332 if (!isInitialConstructor) {
2333 firstadr = nextadr;
2334 this.thisExposability = ALLOWED;
2335 } else {
2336 if (tree.sym.owner.type.isValueClass())
2337 this.thisExposability = BANNED;
2338 else
2339 this.thisExposability = ALLOWED;
2340 }
2341 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2342 JCVariableDecl def = l.head;
2343 scan(def);
2344 Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2345 /* If we are executing the code from Gen, then there can be
2346 * synthetic or mandated variables, ignore them.
2347 */
2348 initParam(def);
2349 }
2350 // else we are in an instance initializer block;
2351 // leave caught unchanged.
2352 scan(tree.body);
2353
2354 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2355 (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2356 if (isInitialConstructor) {
2357 boolean isSynthesized = (tree.sym.flags() &
2358 GENERATEDCONSTR) != 0;
2359 for (int i = firstadr; i < nextadr; i++) {
2383 } else {
2384 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2385 }
2386 } else {
2387 checkInit(TreeInfo.diagEndPos(tree.body), var);
2388 }
2389 }
2390 }
2391 }
2392 clearPendingExits(true);
2393 } finally {
2394 inits.assign(initsPrev);
2395 uninits.assign(uninitsPrev);
2396 nextadr = nextadrPrev;
2397 firstadr = firstadrPrev;
2398 returnadr = returnadrPrev;
2399 isInitialConstructor = lastInitialConstructor;
2400 }
2401 } finally {
2402 lint = lintPrev;
2403 this.thisExposability = priorThisExposability;
2404 }
2405 }
2406
2407 private void clearPendingExits(boolean inMethod) {
2408 List<PendingExit> exits = pendingExits.toList();
2409 pendingExits = new ListBuffer<>();
2410 while (exits.nonEmpty()) {
2411 PendingExit exit = exits.head;
2412 exits = exits.tail;
2413 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2414 log.hasErrorOn(exit.tree.pos()),
2415 exit.tree);
2416 if (inMethod && isInitialConstructor) {
2417 Assert.check(exit instanceof AssignPendingExit);
2418 inits.assign(((AssignPendingExit) exit).exit_inits);
2419 for (int i = firstadr; i < nextadr; i++) {
2420 checkInit(exit.tree.pos(), vardecls[i].sym);
2421 }
2422 }
2423 }
2863
2864 @Override
2865 public void visitContinue(JCContinue tree) {
2866 recordExit(new AssignPendingExit(tree, inits, uninits));
2867 }
2868
2869 @Override
2870 public void visitReturn(JCReturn tree) {
2871 scanExpr(tree.expr);
2872 recordExit(new AssignPendingExit(tree, inits, uninits));
2873 }
2874
2875 public void visitThrow(JCThrow tree) {
2876 scanExpr(tree.expr);
2877 markDead();
2878 }
2879
2880 public void visitApply(JCMethodInvocation tree) {
2881 scanExpr(tree.meth);
2882 scanExprs(tree.args);
2883 if (tree.meth.hasTag(IDENT)) {
2884 JCIdent ident = (JCIdent) tree.meth;
2885 if (ident.name != names._super && !ident.sym.isStatic())
2886 checkEmbryonicThisExposure(tree);
2887 }
2888 }
2889
2890 public void visitNewClass(JCNewClass tree) {
2891 scanExpr(tree.encl);
2892 scanExprs(tree.args);
2893 scan(tree.def);
2894 if (classDef != null && tree.encl == null && tree.clazz.hasTag(IDENT)) {
2895 JCIdent clazz = (JCIdent) tree.clazz;
2896 if (!clazz.sym.isStatic() && clazz.type.getEnclosingType().tsym == classDef.sym) {
2897 checkEmbryonicThisExposure(tree);
2898 }
2899 }
2900 }
2901
2902 @Override
2903 public void visitLambda(JCLambda tree) {
2904 final Bits prevUninits = new Bits(uninits);
2905 final Bits prevInits = new Bits(inits);
2906 int returnadrPrev = returnadr;
2907 int nextadrPrev = nextadr;
2908 ListBuffer<PendingExit> prevPending = pendingExits;
2909 try {
2910 returnadr = nextadr;
2911 pendingExits = new ListBuffer<>();
2912 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2913 JCVariableDecl def = l.head;
2914 scan(def);
2915 inits.incl(def.sym.adr);
2916 uninits.excl(def.sym.adr);
2917 }
2918 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
2919 scanExpr(tree.body);
2942 uninitsExit.andSet(uninitsWhenTrue);
2943 if (tree.detail != null) {
2944 inits.assign(initsWhenFalse);
2945 uninits.assign(uninitsWhenFalse);
2946 scanExpr(tree.detail);
2947 }
2948 inits.assign(initsExit);
2949 uninits.assign(uninitsExit);
2950 }
2951
2952 public void visitAssign(JCAssign tree) {
2953 if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2954 scanExpr(tree.lhs);
2955 scanExpr(tree.rhs);
2956 letInit(tree.lhs);
2957 }
2958
2959 // check fields accessed through this.<field> are definitely
2960 // assigned before reading their value
2961 public void visitSelect(JCFieldAccess tree) {
2962 ThisExposability priorThisExposability = this.thisExposability;
2963 try {
2964 if (tree.name == names._this && classDef != null && tree.sym.owner == classDef.sym) {
2965 checkEmbryonicThisExposure(tree);
2966 } else if (tree.sym.kind == VAR || tree.sym.isStatic()) {
2967 this.thisExposability = ALLOWED;
2968 }
2969 super.visitSelect(tree);
2970 if (TreeInfo.isThisQualifier(tree.selected) &&
2971 tree.sym.kind == VAR) {
2972 checkInit(tree.pos(), (VarSymbol)tree.sym);
2973 }
2974 } finally {
2975 this.thisExposability = priorThisExposability;
2976 }
2977 }
2978
2979 public void visitAssignop(JCAssignOp tree) {
2980 scanExpr(tree.lhs);
2981 scanExpr(tree.rhs);
2982 letInit(tree.lhs);
2983 }
2984
2985 public void visitUnary(JCUnary tree) {
2986 switch (tree.getTag()) {
2987 case NOT:
2988 scanCond(tree.arg);
2989 final Bits t = new Bits(initsWhenFalse);
2990 initsWhenFalse.assign(initsWhenTrue);
2991 initsWhenTrue.assign(t);
2992 t.assign(uninitsWhenFalse);
2993 uninitsWhenFalse.assign(uninitsWhenTrue);
2994 uninitsWhenTrue.assign(t);
2995 break;
3019 scanCond(tree.lhs);
3020 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3021 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3022 inits.assign(initsWhenFalse);
3023 uninits.assign(uninitsWhenFalse);
3024 scanCond(tree.rhs);
3025 initsWhenTrue.andSet(initsWhenTrueLeft);
3026 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3027 break;
3028 default:
3029 scanExpr(tree.lhs);
3030 scanExpr(tree.rhs);
3031 }
3032 }
3033
3034 public void visitIdent(JCIdent tree) {
3035 if (tree.sym.kind == VAR) {
3036 checkInit(tree.pos(), (VarSymbol)tree.sym);
3037 referenced(tree.sym);
3038 }
3039 if (tree.name == names._this) {
3040 checkEmbryonicThisExposure(tree);
3041 }
3042 }
3043
3044 @Override
3045 public void visitTypeTest(JCInstanceOf tree) {
3046 scanExpr(tree.expr);
3047 scan(tree.pattern);
3048 }
3049
3050 @Override
3051 public void visitBindingPattern(JCBindingPattern tree) {
3052 scan(tree.var);
3053 initParam(tree.var);
3054 }
3055
3056 @Override
3057 public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
3058 scan(tree.pat);
3059 scan(tree.guard);
3060 }
3061
|