< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java

Print this page

  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 
< prev index next >