< 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.resources.CompilerProperties.Fragments;
  61 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  62 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
  63 
  64 /** This pass implements dataflow analysis for Java programs though
  65  *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
  66  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
  67  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
  68  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
  69  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
  70  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
  71  *  determines that local variables accessed within the scope of an inner class/lambda
  72  *  are either final or effectively-final.
  73  *
  74  *  <p>The JLS has a number of problems in the
  75  *  specification of these flow analysis problems. This implementation
  76  *  attempts to address those issues.
  77  *
  78  *  <p>First, there is no accommodation for a finally clause that cannot
  79  *  complete normally. For liveness analysis, an intervening finally

1408                     caught = chk.incl(ct.type, caught);
1409                 }
1410             }
1411 
1412             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1413             pendingExits = new ListBuffer<>();
1414             for (JCTree resource : tree.resources) {
1415                 if (resource instanceof JCVariableDecl variableDecl) {
1416                     visitVarDef(variableDecl);
1417                 } else if (resource instanceof JCExpression expression) {
1418                     scan(expression);
1419                 } else {
1420                     throw new AssertionError(tree);  // parser error
1421                 }
1422             }
1423             for (JCTree resource : tree.resources) {
1424                 List<Type> closeableSupertypes = resource.type.isCompound() ?
1425                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1426                     List.of(resource.type);
1427                 for (Type sup : closeableSupertypes) {
1428                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1429                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1430                                 attrEnv,
1431                                 types.skipTypeVars(sup, false),
1432                                 names.close,
1433                                 List.nil(),
1434                                 List.nil());
1435                         Type mt = types.memberType(resource.type, closeMethod);
1436                         if (closeMethod.kind == MTH) {
1437                             for (Type t : mt.getThrownTypes()) {
1438                                 markThrown(resource, t);
1439                             }
1440                         }
1441                     }
1442                 }
1443             }
1444             scan(tree.body);
1445             List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1446             thrown = thrownPrev;
1447             caught = caughtPrev;
1448 

1831             inLambda = true;
1832             try {
1833                 pendingExits = new ListBuffer<>();
1834                 caught = List.of(syms.throwableType);
1835                 thrown = List.nil();
1836                 scan(tree.body);
1837                 inferredThrownTypes = thrown;
1838             } finally {
1839                 pendingExits = prevPending;
1840                 caught = prevCaught;
1841                 thrown = prevThrown;
1842                 inLambda = false;
1843             }
1844         }
1845         @Override
1846         public void visitClassDef(JCClassDecl tree) {
1847             //skip
1848         }
1849     }
1850 








1851     /**
1852      * This pass implements (i) definite assignment analysis, which ensures that
1853      * each variable is assigned when used and (ii) definite unassignment analysis,
1854      * which ensures that no final variable is assigned more than once. This visitor
1855      * depends on the results of the liveliness analyzer. This pass is also used to mark
1856      * effectively-final local variables/parameters.
1857      */
1858 
1859     public class AssignAnalyzer extends BaseAnalyzer {
1860 
1861         /** The set of definitely assigned variables.
1862          */
1863         final Bits inits;
1864 
1865         /** The set of definitely unassigned variables.
1866          */
1867         final Bits uninits;
1868 
1869         /** The set of variables that are definitely unassigned everywhere
1870          *  in current try block. This variable is maintained lazily; it is

1919             final Bits inits;
1920             final Bits uninits;
1921             final Bits exit_inits = new Bits(true);
1922             final Bits exit_uninits = new Bits(true);
1923 
1924             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
1925                 super(tree);
1926                 this.inits = inits;
1927                 this.uninits = uninits;
1928                 this.exit_inits.assign(inits);
1929                 this.exit_uninits.assign(uninits);
1930             }
1931 
1932             @Override
1933             public void resolveJump() {
1934                 inits.andSet(exit_inits);
1935                 uninits.andSet(exit_uninits);
1936             }
1937         }
1938 



1939         public AssignAnalyzer() {
1940             this.inits = new Bits();
1941             uninits = new Bits();
1942             uninitsTry = new Bits();
1943             initsWhenTrue = new Bits(true);
1944             initsWhenFalse = new Bits(true);
1945             uninitsWhenTrue = new Bits(true);
1946             uninitsWhenFalse = new Bits(true);
1947         }
1948 
1949         private boolean isInitialConstructor = false;
1950 
1951         @Override
1952         protected void markDead() {
1953             if (!isInitialConstructor) {
1954                 inits.inclRange(returnadr, nextadr);
1955             } else {
1956                 for (int address = returnadr; address < nextadr; address++) {
1957                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
1958                         inits.incl(address);

2044                 } else {
2045                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2046                     uninits.excl(sym.adr);
2047                 }
2048             }
2049 
2050         /** If tree is either a simple name or of the form this.name or
2051          *  C.this.name, and tree represents a trackable variable,
2052          *  record an initialization of the variable.
2053          */
2054         void letInit(JCTree tree) {
2055             tree = TreeInfo.skipParens(tree);
2056             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2057                 Symbol sym = TreeInfo.symbol(tree);
2058                 if (sym.kind == VAR) {
2059                     letInit(tree.pos(), (VarSymbol)sym);
2060                 }
2061             }
2062         }
2063 






















2064         /** Check that trackable variable is initialized.
2065          */
2066         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2067             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2068         }
2069 
2070         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2071             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2072                 trackable(sym) &&
2073                 !inits.isMember(sym.adr) &&
2074                 (sym.flags_field & CLASH) == 0) {
2075                     log.error(pos, errkey);
2076                 inits.incl(sym.adr);
2077             }
2078         }
2079 
2080         /** Utility method to reset several Bits instances.
2081          */
2082         private void resetBits(Bits... bits) {
2083             for (Bits b : bits) {

2248                     classDef = classDefPrev;
2249                 }
2250             } finally {
2251                 lint = lintPrev;
2252             }
2253         }
2254 
2255         public void visitMethodDef(JCMethodDecl tree) {
2256             if (tree.body == null) {
2257                 return;
2258             }
2259 
2260             /*  MemberEnter can generate synthetic methods ignore them
2261              */
2262             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2263                 return;
2264             }
2265 
2266             Lint lintPrev = lint;
2267             lint = lint.augment(tree.sym);

2268             try {
2269                 if (tree.body == null) {
2270                     return;
2271                 }
2272                 /*  Ignore synthetic methods, except for translated lambda methods.
2273                  */
2274                 if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
2275                     return;
2276                 }
2277 
2278                 final Bits initsPrev = new Bits(inits);
2279                 final Bits uninitsPrev = new Bits(uninits);
2280                 int nextadrPrev = nextadr;
2281                 int firstadrPrev = firstadr;
2282                 int returnadrPrev = returnadr;
2283 
2284                 Assert.check(pendingExits.isEmpty());
2285                 boolean lastInitialConstructor = isInitialConstructor;
2286                 try {
2287                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2288 
2289                     if (!isInitialConstructor) {
2290                         firstadr = nextadr;






2291                     }
2292                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2293                         JCVariableDecl def = l.head;
2294                         scan(def);
2295                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2296                         /*  If we are executing the code from Gen, then there can be
2297                          *  synthetic or mandated variables, ignore them.
2298                          */
2299                         initParam(def);
2300                     }
2301                     // else we are in an instance initializer block;
2302                     // leave caught unchanged.
2303                     scan(tree.body);
2304 
2305                     boolean isCompactConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0;
2306                     if (isInitialConstructor) {
2307                         boolean isSynthesized = (tree.sym.flags() &
2308                                                  GENERATEDCONSTR) != 0;
2309                         for (int i = firstadr; i < nextadr; i++) {
2310                             JCVariableDecl vardecl = vardecls[i];

2333                                     } else {
2334                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2335                                     }
2336                                 } else {
2337                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2338                                 }
2339                             }
2340                         }
2341                     }
2342                     clearPendingExits(true);
2343                 } finally {
2344                     inits.assign(initsPrev);
2345                     uninits.assign(uninitsPrev);
2346                     nextadr = nextadrPrev;
2347                     firstadr = firstadrPrev;
2348                     returnadr = returnadrPrev;
2349                     isInitialConstructor = lastInitialConstructor;
2350                 }
2351             } finally {
2352                 lint = lintPrev;

2353             }
2354         }
2355 
2356         private void clearPendingExits(boolean inMethod) {
2357             List<PendingExit> exits = pendingExits.toList();
2358             pendingExits = new ListBuffer<>();
2359             while (exits.nonEmpty()) {
2360                 PendingExit exit = exits.head;
2361                 exits = exits.tail;
2362                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2363                                  log.hasErrorOn(exit.tree.pos()),
2364                              exit.tree);
2365                 if (inMethod && isInitialConstructor) {
2366                     Assert.check(exit instanceof AssignPendingExit);
2367                     inits.assign(((AssignPendingExit) exit).exit_inits);
2368                     for (int i = firstadr; i < nextadr; i++) {
2369                         checkInit(exit.tree.pos(), vardecls[i].sym);
2370                     }
2371                 }
2372             }

2808 
2809         @Override
2810         public void visitContinue(JCContinue tree) {
2811             recordExit(new AssignPendingExit(tree, inits, uninits));
2812         }
2813 
2814         @Override
2815         public void visitReturn(JCReturn tree) {
2816             scanExpr(tree.expr);
2817             recordExit(new AssignPendingExit(tree, inits, uninits));
2818         }
2819 
2820         public void visitThrow(JCThrow tree) {
2821             scanExpr(tree.expr);
2822             markDead();
2823         }
2824 
2825         public void visitApply(JCMethodInvocation tree) {
2826             scanExpr(tree.meth);
2827             scanExprs(tree.args);





2828         }
2829 
2830         public void visitNewClass(JCNewClass tree) {
2831             scanExpr(tree.encl);
2832             scanExprs(tree.args);
2833             scan(tree.def);






2834         }
2835 
2836         @Override
2837         public void visitLambda(JCLambda tree) {
2838             final Bits prevUninits = new Bits(uninits);
2839             final Bits prevInits = new Bits(inits);
2840             int returnadrPrev = returnadr;
2841             int nextadrPrev = nextadr;
2842             ListBuffer<PendingExit> prevPending = pendingExits;
2843             try {
2844                 returnadr = nextadr;
2845                 pendingExits = new ListBuffer<>();
2846                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2847                     JCVariableDecl def = l.head;
2848                     scan(def);
2849                     inits.incl(def.sym.adr);
2850                     uninits.excl(def.sym.adr);
2851                 }
2852                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
2853                     scanExpr(tree.body);

2876             uninitsExit.andSet(uninitsWhenTrue);
2877             if (tree.detail != null) {
2878                 inits.assign(initsWhenFalse);
2879                 uninits.assign(uninitsWhenFalse);
2880                 scanExpr(tree.detail);
2881             }
2882             inits.assign(initsExit);
2883             uninits.assign(uninitsExit);
2884         }
2885 
2886         public void visitAssign(JCAssign tree) {
2887             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2888                 scanExpr(tree.lhs);
2889             scanExpr(tree.rhs);
2890             letInit(tree.lhs);
2891         }
2892 
2893         // check fields accessed through this.<field> are definitely
2894         // assigned before reading their value
2895         public void visitSelect(JCFieldAccess tree) {
2896             super.visitSelect(tree);







2897             if (TreeInfo.isThisQualifier(tree.selected) &&
2898                 tree.sym.kind == VAR) {
2899                 checkInit(tree.pos(), (VarSymbol)tree.sym);



2900             }
2901         }
2902 
2903         public void visitAssignop(JCAssignOp tree) {
2904             scanExpr(tree.lhs);
2905             scanExpr(tree.rhs);
2906             letInit(tree.lhs);
2907         }
2908 
2909         public void visitUnary(JCUnary tree) {
2910             switch (tree.getTag()) {
2911             case NOT:
2912                 scanCond(tree.arg);
2913                 final Bits t = new Bits(initsWhenFalse);
2914                 initsWhenFalse.assign(initsWhenTrue);
2915                 initsWhenTrue.assign(t);
2916                 t.assign(uninitsWhenFalse);
2917                 uninitsWhenFalse.assign(uninitsWhenTrue);
2918                 uninitsWhenTrue.assign(t);
2919                 break;

2943                 scanCond(tree.lhs);
2944                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
2945                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
2946                 inits.assign(initsWhenFalse);
2947                 uninits.assign(uninitsWhenFalse);
2948                 scanCond(tree.rhs);
2949                 initsWhenTrue.andSet(initsWhenTrueLeft);
2950                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
2951                 break;
2952             default:
2953                 scanExpr(tree.lhs);
2954                 scanExpr(tree.rhs);
2955             }
2956         }
2957 
2958         public void visitIdent(JCIdent tree) {
2959             if (tree.sym.kind == VAR) {
2960                 checkInit(tree.pos(), (VarSymbol)tree.sym);
2961                 referenced(tree.sym);
2962             }



2963         }
2964 
2965         @Override
2966         public void visitTypeTest(JCInstanceOf tree) {
2967             scanExpr(tree.expr);
2968             scan(tree.pattern);
2969         }
2970 
2971         @Override
2972         public void visitBindingPattern(JCBindingPattern tree) {
2973             scan(tree.var);
2974             initParam(tree.var);
2975         }
2976 
2977         @Override
2978         public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
2979             scan(tree.pat);
2980             scan(tree.guard);
2981         }
2982 

  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.resources.CompilerProperties.Fragments;
  63 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  64 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
  65 
  66 /** This pass implements dataflow analysis for Java programs though
  67  *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
  68  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
  69  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
  70  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
  71  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
  72  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
  73  *  determines that local variables accessed within the scope of an inner class/lambda
  74  *  are either final or effectively-final.
  75  *
  76  *  <p>The JLS has a number of problems in the
  77  *  specification of these flow analysis problems. This implementation
  78  *  attempts to address those issues.
  79  *
  80  *  <p>First, there is no accommodation for a finally clause that cannot
  81  *  complete normally. For liveness analysis, an intervening finally

1410                     caught = chk.incl(ct.type, caught);
1411                 }
1412             }
1413 
1414             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1415             pendingExits = new ListBuffer<>();
1416             for (JCTree resource : tree.resources) {
1417                 if (resource instanceof JCVariableDecl variableDecl) {
1418                     visitVarDef(variableDecl);
1419                 } else if (resource instanceof JCExpression expression) {
1420                     scan(expression);
1421                 } else {
1422                     throw new AssertionError(tree);  // parser error
1423                 }
1424             }
1425             for (JCTree resource : tree.resources) {
1426                 List<Type> closeableSupertypes = resource.type.isCompound() ?
1427                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1428                     List.of(resource.type);
1429                 for (Type sup : closeableSupertypes) {
1430                     if (types.asSuper(sup.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) != null) {
1431                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1432                                 attrEnv,
1433                                 types.skipTypeVars(sup, false),
1434                                 names.close,
1435                                 List.nil(),
1436                                 List.nil());
1437                         Type mt = types.memberType(resource.type, closeMethod);
1438                         if (closeMethod.kind == MTH) {
1439                             for (Type t : mt.getThrownTypes()) {
1440                                 markThrown(resource, t);
1441                             }
1442                         }
1443                     }
1444                 }
1445             }
1446             scan(tree.body);
1447             List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1448             thrown = thrownPrev;
1449             caught = caughtPrev;
1450 

1833             inLambda = true;
1834             try {
1835                 pendingExits = new ListBuffer<>();
1836                 caught = List.of(syms.throwableType);
1837                 thrown = List.nil();
1838                 scan(tree.body);
1839                 inferredThrownTypes = thrown;
1840             } finally {
1841                 pendingExits = prevPending;
1842                 caught = prevCaught;
1843                 thrown = prevThrown;
1844                 inLambda = false;
1845             }
1846         }
1847         @Override
1848         public void visitClassDef(JCClassDecl tree) {
1849             //skip
1850         }
1851     }
1852 
1853     /** Enum to model whether constructors allowed to "leak" this reference before
1854         all instance fields are DA.
1855      */
1856     enum ThisExposability {
1857         ALLOWED,     // identity Object classes - NOP
1858         BANNED,      // primitive/value classes - Error
1859     }
1860 
1861     /**
1862      * This pass implements (i) definite assignment analysis, which ensures that
1863      * each variable is assigned when used and (ii) definite unassignment analysis,
1864      * which ensures that no final variable is assigned more than once. This visitor
1865      * depends on the results of the liveliness analyzer. This pass is also used to mark
1866      * effectively-final local variables/parameters.
1867      */
1868 
1869     public class AssignAnalyzer extends BaseAnalyzer {
1870 
1871         /** The set of definitely assigned variables.
1872          */
1873         final Bits inits;
1874 
1875         /** The set of definitely unassigned variables.
1876          */
1877         final Bits uninits;
1878 
1879         /** The set of variables that are definitely unassigned everywhere
1880          *  in current try block. This variable is maintained lazily; it is

1929             final Bits inits;
1930             final Bits uninits;
1931             final Bits exit_inits = new Bits(true);
1932             final Bits exit_uninits = new Bits(true);
1933 
1934             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
1935                 super(tree);
1936                 this.inits = inits;
1937                 this.uninits = uninits;
1938                 this.exit_inits.assign(inits);
1939                 this.exit_uninits.assign(uninits);
1940             }
1941 
1942             @Override
1943             public void resolveJump() {
1944                 inits.andSet(exit_inits);
1945                 uninits.andSet(exit_uninits);
1946             }
1947         }
1948 
1949         // Are constructors allowed to leak this reference ?
1950         ThisExposability thisExposability = ALLOWED;
1951 
1952         public AssignAnalyzer() {
1953             this.inits = new Bits();
1954             uninits = new Bits();
1955             uninitsTry = new Bits();
1956             initsWhenTrue = new Bits(true);
1957             initsWhenFalse = new Bits(true);
1958             uninitsWhenTrue = new Bits(true);
1959             uninitsWhenFalse = new Bits(true);
1960         }
1961 
1962         private boolean isInitialConstructor = false;
1963 
1964         @Override
1965         protected void markDead() {
1966             if (!isInitialConstructor) {
1967                 inits.inclRange(returnadr, nextadr);
1968             } else {
1969                 for (int address = returnadr; address < nextadr; address++) {
1970                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
1971                         inits.incl(address);

2057                 } else {
2058                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2059                     uninits.excl(sym.adr);
2060                 }
2061             }
2062 
2063         /** If tree is either a simple name or of the form this.name or
2064          *  C.this.name, and tree represents a trackable variable,
2065          *  record an initialization of the variable.
2066          */
2067         void letInit(JCTree tree) {
2068             tree = TreeInfo.skipParens(tree);
2069             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2070                 Symbol sym = TreeInfo.symbol(tree);
2071                 if (sym.kind == VAR) {
2072                     letInit(tree.pos(), (VarSymbol)sym);
2073                 }
2074             }
2075         }
2076 
2077         void checkEmbryonicThisExposure(JCTree node) {
2078             if (this.thisExposability == ALLOWED || classDef == null)
2079                 return;
2080 
2081             // Note: for non-initial constructors, firstadr is post all instance fields.
2082             for (int i = firstadr; i < nextadr; i++) {
2083                 VarSymbol sym = vardecls[i].sym;
2084                 if (sym.owner != classDef.sym)
2085                     continue;
2086                 if ((sym.flags() & (FINAL | HASINIT | STATIC | PARAMETER)) != FINAL)
2087                     continue;
2088                 if (sym.pos < startPos || sym.adr < firstadr)
2089                     continue;
2090                 if (!inits.isMember(sym.adr)) {
2091                     if (this.thisExposability == BANNED) {
2092                         log.error(node, Errors.ThisExposedPrematurely);
2093                     }
2094                     return; // don't flog a dead horse.
2095                 }
2096             }
2097         }
2098 
2099         /** Check that trackable variable is initialized.
2100          */
2101         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2102             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2103         }
2104 
2105         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2106             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2107                 trackable(sym) &&
2108                 !inits.isMember(sym.adr) &&
2109                 (sym.flags_field & CLASH) == 0) {
2110                     log.error(pos, errkey);
2111                 inits.incl(sym.adr);
2112             }
2113         }
2114 
2115         /** Utility method to reset several Bits instances.
2116          */
2117         private void resetBits(Bits... bits) {
2118             for (Bits b : bits) {

2283                     classDef = classDefPrev;
2284                 }
2285             } finally {
2286                 lint = lintPrev;
2287             }
2288         }
2289 
2290         public void visitMethodDef(JCMethodDecl tree) {
2291             if (tree.body == null) {
2292                 return;
2293             }
2294 
2295             /*  MemberEnter can generate synthetic methods ignore them
2296              */
2297             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2298                 return;
2299             }
2300 
2301             Lint lintPrev = lint;
2302             lint = lint.augment(tree.sym);
2303             ThisExposability priorThisExposability = this.thisExposability;
2304             try {
2305                 if (tree.body == null) {
2306                     return;
2307                 }
2308                 /*  Ignore synthetic methods, except for translated lambda methods.
2309                  */
2310                 if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
2311                     return;
2312                 }
2313 
2314                 final Bits initsPrev = new Bits(inits);
2315                 final Bits uninitsPrev = new Bits(uninits);
2316                 int nextadrPrev = nextadr;
2317                 int firstadrPrev = firstadr;
2318                 int returnadrPrev = returnadr;
2319 
2320                 Assert.check(pendingExits.isEmpty());
2321                 boolean lastInitialConstructor = isInitialConstructor;
2322                 try {
2323                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2324 
2325                     if (!isInitialConstructor) {
2326                         firstadr = nextadr;
2327                         this.thisExposability = ALLOWED;
2328                     } else {
2329                         if (tree.sym.owner.type.isValueClass())
2330                             this.thisExposability = BANNED;
2331                         else
2332                             this.thisExposability = ALLOWED;
2333                     }
2334                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2335                         JCVariableDecl def = l.head;
2336                         scan(def);
2337                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2338                         /*  If we are executing the code from Gen, then there can be
2339                          *  synthetic or mandated variables, ignore them.
2340                          */
2341                         initParam(def);
2342                     }
2343                     // else we are in an instance initializer block;
2344                     // leave caught unchanged.
2345                     scan(tree.body);
2346 
2347                     boolean isCompactConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0;
2348                     if (isInitialConstructor) {
2349                         boolean isSynthesized = (tree.sym.flags() &
2350                                                  GENERATEDCONSTR) != 0;
2351                         for (int i = firstadr; i < nextadr; i++) {
2352                             JCVariableDecl vardecl = vardecls[i];

2375                                     } else {
2376                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2377                                     }
2378                                 } else {
2379                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2380                                 }
2381                             }
2382                         }
2383                     }
2384                     clearPendingExits(true);
2385                 } finally {
2386                     inits.assign(initsPrev);
2387                     uninits.assign(uninitsPrev);
2388                     nextadr = nextadrPrev;
2389                     firstadr = firstadrPrev;
2390                     returnadr = returnadrPrev;
2391                     isInitialConstructor = lastInitialConstructor;
2392                 }
2393             } finally {
2394                 lint = lintPrev;
2395                 this.thisExposability = priorThisExposability;
2396             }
2397         }
2398 
2399         private void clearPendingExits(boolean inMethod) {
2400             List<PendingExit> exits = pendingExits.toList();
2401             pendingExits = new ListBuffer<>();
2402             while (exits.nonEmpty()) {
2403                 PendingExit exit = exits.head;
2404                 exits = exits.tail;
2405                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2406                                  log.hasErrorOn(exit.tree.pos()),
2407                              exit.tree);
2408                 if (inMethod && isInitialConstructor) {
2409                     Assert.check(exit instanceof AssignPendingExit);
2410                     inits.assign(((AssignPendingExit) exit).exit_inits);
2411                     for (int i = firstadr; i < nextadr; i++) {
2412                         checkInit(exit.tree.pos(), vardecls[i].sym);
2413                     }
2414                 }
2415             }

2851 
2852         @Override
2853         public void visitContinue(JCContinue tree) {
2854             recordExit(new AssignPendingExit(tree, inits, uninits));
2855         }
2856 
2857         @Override
2858         public void visitReturn(JCReturn tree) {
2859             scanExpr(tree.expr);
2860             recordExit(new AssignPendingExit(tree, inits, uninits));
2861         }
2862 
2863         public void visitThrow(JCThrow tree) {
2864             scanExpr(tree.expr);
2865             markDead();
2866         }
2867 
2868         public void visitApply(JCMethodInvocation tree) {
2869             scanExpr(tree.meth);
2870             scanExprs(tree.args);
2871             if (tree.meth.hasTag(IDENT)) {
2872                 JCIdent ident = (JCIdent) tree.meth;
2873                 if (ident.name != names._super && !ident.sym.isStatic())
2874                     checkEmbryonicThisExposure(tree);
2875             }
2876         }
2877 
2878         public void visitNewClass(JCNewClass tree) {
2879             scanExpr(tree.encl);
2880             scanExprs(tree.args);
2881             scan(tree.def);
2882             if (classDef != null && tree.encl == null && tree.clazz.hasTag(IDENT)) {
2883                 JCIdent clazz = (JCIdent) tree.clazz;
2884                 if (!clazz.sym.isStatic() && clazz.type.getEnclosingType().tsym == classDef.sym) {
2885                     checkEmbryonicThisExposure(tree);
2886                 }
2887             }
2888         }
2889 
2890         @Override
2891         public void visitLambda(JCLambda tree) {
2892             final Bits prevUninits = new Bits(uninits);
2893             final Bits prevInits = new Bits(inits);
2894             int returnadrPrev = returnadr;
2895             int nextadrPrev = nextadr;
2896             ListBuffer<PendingExit> prevPending = pendingExits;
2897             try {
2898                 returnadr = nextadr;
2899                 pendingExits = new ListBuffer<>();
2900                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2901                     JCVariableDecl def = l.head;
2902                     scan(def);
2903                     inits.incl(def.sym.adr);
2904                     uninits.excl(def.sym.adr);
2905                 }
2906                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
2907                     scanExpr(tree.body);

2930             uninitsExit.andSet(uninitsWhenTrue);
2931             if (tree.detail != null) {
2932                 inits.assign(initsWhenFalse);
2933                 uninits.assign(uninitsWhenFalse);
2934                 scanExpr(tree.detail);
2935             }
2936             inits.assign(initsExit);
2937             uninits.assign(uninitsExit);
2938         }
2939 
2940         public void visitAssign(JCAssign tree) {
2941             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2942                 scanExpr(tree.lhs);
2943             scanExpr(tree.rhs);
2944             letInit(tree.lhs);
2945         }
2946 
2947         // check fields accessed through this.<field> are definitely
2948         // assigned before reading their value
2949         public void visitSelect(JCFieldAccess tree) {
2950             ThisExposability priorThisExposability = this.thisExposability;
2951             try {
2952                 if (tree.name == names._this && classDef != null && tree.sym.owner == classDef.sym) {
2953                     checkEmbryonicThisExposure(tree);
2954                 } else if (tree.sym.kind == VAR || tree.sym.isStatic()) {
2955                     this.thisExposability = ALLOWED;
2956                 }
2957                 super.visitSelect(tree);
2958             if (TreeInfo.isThisQualifier(tree.selected) &&
2959                 tree.sym.kind == VAR) {
2960                     checkInit(tree.pos(), (VarSymbol)tree.sym);
2961                 }
2962             } finally {
2963                  this.thisExposability = priorThisExposability;
2964             }
2965         }
2966 
2967         public void visitAssignop(JCAssignOp tree) {
2968             scanExpr(tree.lhs);
2969             scanExpr(tree.rhs);
2970             letInit(tree.lhs);
2971         }
2972 
2973         public void visitUnary(JCUnary tree) {
2974             switch (tree.getTag()) {
2975             case NOT:
2976                 scanCond(tree.arg);
2977                 final Bits t = new Bits(initsWhenFalse);
2978                 initsWhenFalse.assign(initsWhenTrue);
2979                 initsWhenTrue.assign(t);
2980                 t.assign(uninitsWhenFalse);
2981                 uninitsWhenFalse.assign(uninitsWhenTrue);
2982                 uninitsWhenTrue.assign(t);
2983                 break;

3007                 scanCond(tree.lhs);
3008                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3009                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3010                 inits.assign(initsWhenFalse);
3011                 uninits.assign(uninitsWhenFalse);
3012                 scanCond(tree.rhs);
3013                 initsWhenTrue.andSet(initsWhenTrueLeft);
3014                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3015                 break;
3016             default:
3017                 scanExpr(tree.lhs);
3018                 scanExpr(tree.rhs);
3019             }
3020         }
3021 
3022         public void visitIdent(JCIdent tree) {
3023             if (tree.sym.kind == VAR) {
3024                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3025                 referenced(tree.sym);
3026             }
3027             if (tree.name == names._this) {
3028                 checkEmbryonicThisExposure(tree);
3029             }
3030         }
3031 
3032         @Override
3033         public void visitTypeTest(JCInstanceOf tree) {
3034             scanExpr(tree.expr);
3035             scan(tree.pattern);
3036         }
3037 
3038         @Override
3039         public void visitBindingPattern(JCBindingPattern tree) {
3040             scan(tree.var);
3041             initParam(tree.var);
3042         }
3043 
3044         @Override
3045         public void visitPatternCaseLabel(JCPatternCaseLabel tree) {
3046             scan(tree.pat);
3047             scan(tree.guard);
3048         }
3049 
< prev index next >