< prev index next >

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

Print this page

  38 import com.sun.tools.javac.code.*;
  39 import com.sun.tools.javac.code.Scope.WriteableScope;
  40 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  41 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  42 import com.sun.tools.javac.tree.*;
  43 import com.sun.tools.javac.util.*;
  44 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  45 import com.sun.tools.javac.util.JCDiagnostic.Error;
  46 import com.sun.tools.javac.util.JCDiagnostic.Warning;
  47 
  48 import com.sun.tools.javac.code.Symbol.*;
  49 import com.sun.tools.javac.tree.JCTree.*;
  50 
  51 import static com.sun.tools.javac.code.Flags.*;
  52 import static com.sun.tools.javac.code.Flags.BLOCK;
  53 import com.sun.tools.javac.code.Kinds.Kind;
  54 import static com.sun.tools.javac.code.Kinds.Kind.*;
  55 import com.sun.tools.javac.code.Type.TypeVar;
  56 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
  57 import static com.sun.tools.javac.code.TypeTag.VOID;


  58 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  59 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  60 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
  61 import java.util.Arrays;
  62 import java.util.Collections;
  63 import java.util.IdentityHashMap;
  64 import java.util.Iterator;
  65 import java.util.function.Predicate;
  66 import java.util.stream.Collectors;
  67 
  68 import static java.util.stream.Collectors.groupingBy;
  69 
  70 /** This pass implements dataflow analysis for Java programs though
  71  *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
  72  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
  73  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
  74  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
  75  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
  76  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
  77  *  determines that local variables accessed within the scope of an inner class/lambda

1570                     caught = chk.incl(ct.type, caught);
1571                 }
1572             }
1573 
1574             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1575             pendingExits = new ListBuffer<>();
1576             for (JCTree resource : tree.resources) {
1577                 if (resource instanceof JCVariableDecl variableDecl) {
1578                     visitVarDef(variableDecl);
1579                 } else if (resource instanceof JCExpression expression) {
1580                     scan(expression);
1581                 } else {
1582                     throw new AssertionError(tree);  // parser error
1583                 }
1584             }
1585             for (JCTree resource : tree.resources) {
1586                 List<Type> closeableSupertypes = resource.type.isCompound() ?
1587                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1588                     List.of(resource.type);
1589                 for (Type sup : closeableSupertypes) {
1590                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1591                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1592                                 attrEnv,
1593                                 types.skipTypeVars(sup, false),
1594                                 names.close,
1595                                 List.nil(),
1596                                 List.nil());
1597                         Type mt = types.memberType(resource.type, closeMethod);
1598                         if (closeMethod.kind == MTH) {
1599                             for (Type t : mt.getThrownTypes()) {
1600                                 markThrown(resource, t);
1601                             }
1602                         }
1603                     }
1604                 }
1605             }
1606             scan(tree.body);
1607             List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1608             thrown = thrownPrev;
1609             caught = caughtPrev;
1610 

2017             inLambda = true;
2018             try {
2019                 pendingExits = new ListBuffer<>();
2020                 caught = List.of(syms.throwableType);
2021                 thrown = List.nil();
2022                 scan(tree.body);
2023                 inferredThrownTypes = thrown;
2024             } finally {
2025                 pendingExits = prevPending;
2026                 caught = prevCaught;
2027                 thrown = prevThrown;
2028                 inLambda = false;
2029             }
2030         }
2031         @Override
2032         public void visitClassDef(JCClassDecl tree) {
2033             //skip
2034         }
2035     }
2036 








2037     /**
2038      * This pass implements (i) definite assignment analysis, which ensures that
2039      * each variable is assigned when used and (ii) definite unassignment analysis,
2040      * which ensures that no final variable is assigned more than once. This visitor
2041      * depends on the results of the liveliness analyzer. This pass is also used to mark
2042      * effectively-final local variables/parameters.
2043      */
2044 
2045     public class AssignAnalyzer extends BaseAnalyzer {
2046 
2047         /** The set of definitely assigned variables.
2048          */
2049         final Bits inits;
2050 
2051         /** The set of definitely unassigned variables.
2052          */
2053         final Bits uninits;
2054 
2055         /** The set of variables that are definitely unassigned everywhere
2056          *  in current try block. This variable is maintained lazily; it is

2105             final Bits inits;
2106             final Bits uninits;
2107             final Bits exit_inits = new Bits(true);
2108             final Bits exit_uninits = new Bits(true);
2109 
2110             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2111                 super(tree);
2112                 this.inits = inits;
2113                 this.uninits = uninits;
2114                 this.exit_inits.assign(inits);
2115                 this.exit_uninits.assign(uninits);
2116             }
2117 
2118             @Override
2119             public void resolveJump() {
2120                 inits.andSet(exit_inits);
2121                 uninits.andSet(exit_uninits);
2122             }
2123         }
2124 



2125         public AssignAnalyzer() {
2126             this.inits = new Bits();
2127             uninits = new Bits();
2128             uninitsTry = new Bits();
2129             initsWhenTrue = new Bits(true);
2130             initsWhenFalse = new Bits(true);
2131             uninitsWhenTrue = new Bits(true);
2132             uninitsWhenFalse = new Bits(true);
2133         }
2134 
2135         private boolean isInitialConstructor = false;
2136 
2137         @Override
2138         protected void markDead() {
2139             if (!isInitialConstructor) {
2140                 inits.inclRange(returnadr, nextadr);
2141             } else {
2142                 for (int address = returnadr; address < nextadr; address++) {
2143                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
2144                         inits.incl(address);

2230                 } else {
2231                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2232                     uninits.excl(sym.adr);
2233                 }
2234             }
2235 
2236         /** If tree is either a simple name or of the form this.name or
2237          *  C.this.name, and tree represents a trackable variable,
2238          *  record an initialization of the variable.
2239          */
2240         void letInit(JCTree tree) {
2241             tree = TreeInfo.skipParens(tree);
2242             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2243                 Symbol sym = TreeInfo.symbol(tree);
2244                 if (sym.kind == VAR) {
2245                     letInit(tree.pos(), (VarSymbol)sym);
2246                 }
2247             }
2248         }
2249 






















2250         /** Check that trackable variable is initialized.
2251          */
2252         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2253             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2254         }
2255 
2256         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2257             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2258                 trackable(sym) &&
2259                 !inits.isMember(sym.adr) &&
2260                 (sym.flags_field & CLASH) == 0) {
2261                     log.error(pos, errkey);
2262                 inits.incl(sym.adr);
2263             }
2264         }
2265 
2266         /** Utility method to reset several Bits instances.
2267          */
2268         private void resetBits(Bits... bits) {
2269             for (Bits b : bits) {

2435                     classDef = classDefPrev;
2436                 }
2437             } finally {
2438                 lint = lintPrev;
2439             }
2440         }
2441 
2442         public void visitMethodDef(JCMethodDecl tree) {
2443             if (tree.body == null) {
2444                 return;
2445             }
2446 
2447             /*  MemberEnter can generate synthetic methods ignore them
2448              */
2449             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2450                 return;
2451             }
2452 
2453             Lint lintPrev = lint;
2454             lint = lint.augment(tree.sym);

2455             try {
2456                 final Bits initsPrev = new Bits(inits);
2457                 final Bits uninitsPrev = new Bits(uninits);
2458                 int nextadrPrev = nextadr;
2459                 int firstadrPrev = firstadr;
2460                 int returnadrPrev = returnadr;
2461 
2462                 Assert.check(pendingExits.isEmpty());
2463                 boolean lastInitialConstructor = isInitialConstructor;
2464                 try {
2465                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2466 
2467                     if (!isInitialConstructor) {
2468                         firstadr = nextadr;






2469                     }
2470                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2471                         JCVariableDecl def = l.head;
2472                         scan(def);
2473                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2474                         /*  If we are executing the code from Gen, then there can be
2475                          *  synthetic or mandated variables, ignore them.
2476                          */
2477                         initParam(def);
2478                     }
2479                     // else we are in an instance initializer block;
2480                     // leave caught unchanged.
2481                     scan(tree.body);
2482 
2483                     boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2484                             (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2485                     if (isInitialConstructor) {
2486                         boolean isSynthesized = (tree.sym.flags() &
2487                                                  GENERATEDCONSTR) != 0;
2488                         for (int i = firstadr; i < nextadr; i++) {

2511                                     } else {
2512                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2513                                     }
2514                                 } else {
2515                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2516                                 }
2517                             }
2518                         }
2519                     }
2520                     clearPendingExits(true);
2521                 } finally {
2522                     inits.assign(initsPrev);
2523                     uninits.assign(uninitsPrev);
2524                     nextadr = nextadrPrev;
2525                     firstadr = firstadrPrev;
2526                     returnadr = returnadrPrev;
2527                     isInitialConstructor = lastInitialConstructor;
2528                 }
2529             } finally {
2530                 lint = lintPrev;

2531             }
2532         }
2533 
2534         private void clearPendingExits(boolean inMethod) {
2535             List<PendingExit> exits = pendingExits.toList();
2536             pendingExits = new ListBuffer<>();
2537             while (exits.nonEmpty()) {
2538                 PendingExit exit = exits.head;
2539                 exits = exits.tail;
2540                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2541                                  log.hasErrorOn(exit.tree.pos()),
2542                              exit.tree);
2543                 if (inMethod && isInitialConstructor) {
2544                     Assert.check(exit instanceof AssignPendingExit);
2545                     inits.assign(((AssignPendingExit) exit).exit_inits);
2546                     for (int i = firstadr; i < nextadr; i++) {
2547                         checkInit(exit.tree.pos(), vardecls[i].sym);
2548                     }
2549                 }
2550             }

2979 
2980         @Override
2981         public void visitContinue(JCContinue tree) {
2982             recordExit(new AssignPendingExit(tree, inits, uninits));
2983         }
2984 
2985         @Override
2986         public void visitReturn(JCReturn tree) {
2987             scanExpr(tree.expr);
2988             recordExit(new AssignPendingExit(tree, inits, uninits));
2989         }
2990 
2991         public void visitThrow(JCThrow tree) {
2992             scanExpr(tree.expr);
2993             markDead();
2994         }
2995 
2996         public void visitApply(JCMethodInvocation tree) {
2997             scanExpr(tree.meth);
2998             scanExprs(tree.args);





2999         }
3000 
3001         public void visitNewClass(JCNewClass tree) {
3002             scanExpr(tree.encl);
3003             scanExprs(tree.args);
3004             scan(tree.def);






3005         }
3006 
3007         @Override
3008         public void visitLambda(JCLambda tree) {
3009             final Bits prevUninits = new Bits(uninits);
3010             final Bits prevUninitsTry = new Bits(uninitsTry);
3011             final Bits prevInits = new Bits(inits);
3012             int returnadrPrev = returnadr;
3013             int nextadrPrev = nextadr;
3014             ListBuffer<PendingExit> prevPending = pendingExits;
3015             try {
3016                 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
3017                 // body. This is by design: a variable that was definitely unassigned before the
3018                 // lambda body may end up being assigned to later on, so we cannot conclude that
3019                 // the variable will be unassigned when the body is executed.
3020                 uninits.excludeFrom(firstadr);
3021                 returnadr = nextadr;
3022                 pendingExits = new ListBuffer<>();
3023                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
3024                     JCVariableDecl def = l.head;

3054             uninitsExit.andSet(uninitsWhenTrue);
3055             if (tree.detail != null) {
3056                 inits.assign(initsWhenFalse);
3057                 uninits.assign(uninitsWhenFalse);
3058                 scanExpr(tree.detail);
3059             }
3060             inits.assign(initsExit);
3061             uninits.assign(uninitsExit);
3062         }
3063 
3064         public void visitAssign(JCAssign tree) {
3065             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3066                 scanExpr(tree.lhs);
3067             scanExpr(tree.rhs);
3068             letInit(tree.lhs);
3069         }
3070 
3071         // check fields accessed through this.<field> are definitely
3072         // assigned before reading their value
3073         public void visitSelect(JCFieldAccess tree) {
3074             super.visitSelect(tree);







3075             if (TreeInfo.isThisQualifier(tree.selected) &&
3076                 tree.sym.kind == VAR) {
3077                 checkInit(tree.pos(), (VarSymbol)tree.sym);



3078             }
3079         }
3080 
3081         public void visitAssignop(JCAssignOp tree) {
3082             scanExpr(tree.lhs);
3083             scanExpr(tree.rhs);
3084             letInit(tree.lhs);
3085         }
3086 
3087         public void visitUnary(JCUnary tree) {
3088             switch (tree.getTag()) {
3089             case NOT:
3090                 scanCond(tree.arg);
3091                 final Bits t = new Bits(initsWhenFalse);
3092                 initsWhenFalse.assign(initsWhenTrue);
3093                 initsWhenTrue.assign(t);
3094                 t.assign(uninitsWhenFalse);
3095                 uninitsWhenFalse.assign(uninitsWhenTrue);
3096                 uninitsWhenTrue.assign(t);
3097                 break;

3121                 scanCond(tree.lhs);
3122                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3123                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3124                 inits.assign(initsWhenFalse);
3125                 uninits.assign(uninitsWhenFalse);
3126                 scanCond(tree.rhs);
3127                 initsWhenTrue.andSet(initsWhenTrueLeft);
3128                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3129                 break;
3130             default:
3131                 scanExpr(tree.lhs);
3132                 scanExpr(tree.rhs);
3133             }
3134         }
3135 
3136         public void visitIdent(JCIdent tree) {
3137             if (tree.sym.kind == VAR) {
3138                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3139                 referenced(tree.sym);
3140             }



3141         }
3142 
3143         @Override
3144         public void visitTypeTest(JCInstanceOf tree) {
3145             scanExpr(tree.expr);
3146             scan(tree.pattern);
3147         }
3148 
3149         @Override
3150         public void visitBindingPattern(JCBindingPattern tree) {
3151             scan(tree.var);
3152             initParam(tree.var);
3153         }
3154 
3155         void referenced(Symbol sym) {
3156             unrefdResources.remove(sym);
3157         }
3158 
3159         public void visitAnnotatedType(JCAnnotatedType tree) {
3160             // annotations don't get scanned

  38 import com.sun.tools.javac.code.*;
  39 import com.sun.tools.javac.code.Scope.WriteableScope;
  40 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  41 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  42 import com.sun.tools.javac.tree.*;
  43 import com.sun.tools.javac.util.*;
  44 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  45 import com.sun.tools.javac.util.JCDiagnostic.Error;
  46 import com.sun.tools.javac.util.JCDiagnostic.Warning;
  47 
  48 import com.sun.tools.javac.code.Symbol.*;
  49 import com.sun.tools.javac.tree.JCTree.*;
  50 
  51 import static com.sun.tools.javac.code.Flags.*;
  52 import static com.sun.tools.javac.code.Flags.BLOCK;
  53 import com.sun.tools.javac.code.Kinds.Kind;
  54 import static com.sun.tools.javac.code.Kinds.Kind.*;
  55 import com.sun.tools.javac.code.Type.TypeVar;
  56 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
  57 import static com.sun.tools.javac.code.TypeTag.VOID;
  58 import static com.sun.tools.javac.comp.Flow.ThisExposability.ALLOWED;
  59 import static com.sun.tools.javac.comp.Flow.ThisExposability.BANNED;
  60 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  61 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  62 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
  63 import java.util.Arrays;
  64 import java.util.Collections;
  65 import java.util.IdentityHashMap;
  66 import java.util.Iterator;
  67 import java.util.function.Predicate;
  68 import java.util.stream.Collectors;
  69 
  70 import static java.util.stream.Collectors.groupingBy;
  71 
  72 /** This pass implements dataflow analysis for Java programs though
  73  *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
  74  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
  75  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
  76  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
  77  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
  78  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
  79  *  determines that local variables accessed within the scope of an inner class/lambda

1572                     caught = chk.incl(ct.type, caught);
1573                 }
1574             }
1575 
1576             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1577             pendingExits = new ListBuffer<>();
1578             for (JCTree resource : tree.resources) {
1579                 if (resource instanceof JCVariableDecl variableDecl) {
1580                     visitVarDef(variableDecl);
1581                 } else if (resource instanceof JCExpression expression) {
1582                     scan(expression);
1583                 } else {
1584                     throw new AssertionError(tree);  // parser error
1585                 }
1586             }
1587             for (JCTree resource : tree.resources) {
1588                 List<Type> closeableSupertypes = resource.type.isCompound() ?
1589                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1590                     List.of(resource.type);
1591                 for (Type sup : closeableSupertypes) {
1592                     if (types.asSuper(sup.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) != null) {
1593                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1594                                 attrEnv,
1595                                 types.skipTypeVars(sup, false),
1596                                 names.close,
1597                                 List.nil(),
1598                                 List.nil());
1599                         Type mt = types.memberType(resource.type, closeMethod);
1600                         if (closeMethod.kind == MTH) {
1601                             for (Type t : mt.getThrownTypes()) {
1602                                 markThrown(resource, t);
1603                             }
1604                         }
1605                     }
1606                 }
1607             }
1608             scan(tree.body);
1609             List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1610             thrown = thrownPrev;
1611             caught = caughtPrev;
1612 

2019             inLambda = true;
2020             try {
2021                 pendingExits = new ListBuffer<>();
2022                 caught = List.of(syms.throwableType);
2023                 thrown = List.nil();
2024                 scan(tree.body);
2025                 inferredThrownTypes = thrown;
2026             } finally {
2027                 pendingExits = prevPending;
2028                 caught = prevCaught;
2029                 thrown = prevThrown;
2030                 inLambda = false;
2031             }
2032         }
2033         @Override
2034         public void visitClassDef(JCClassDecl tree) {
2035             //skip
2036         }
2037     }
2038 
2039     /** Enum to model whether constructors allowed to "leak" this reference before
2040         all instance fields are DA.
2041      */
2042     enum ThisExposability {
2043         ALLOWED,     // identity Object classes - NOP
2044         BANNED,      // primitive/value classes - Error
2045     }
2046 
2047     /**
2048      * This pass implements (i) definite assignment analysis, which ensures that
2049      * each variable is assigned when used and (ii) definite unassignment analysis,
2050      * which ensures that no final variable is assigned more than once. This visitor
2051      * depends on the results of the liveliness analyzer. This pass is also used to mark
2052      * effectively-final local variables/parameters.
2053      */
2054 
2055     public class AssignAnalyzer extends BaseAnalyzer {
2056 
2057         /** The set of definitely assigned variables.
2058          */
2059         final Bits inits;
2060 
2061         /** The set of definitely unassigned variables.
2062          */
2063         final Bits uninits;
2064 
2065         /** The set of variables that are definitely unassigned everywhere
2066          *  in current try block. This variable is maintained lazily; it is

2115             final Bits inits;
2116             final Bits uninits;
2117             final Bits exit_inits = new Bits(true);
2118             final Bits exit_uninits = new Bits(true);
2119 
2120             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2121                 super(tree);
2122                 this.inits = inits;
2123                 this.uninits = uninits;
2124                 this.exit_inits.assign(inits);
2125                 this.exit_uninits.assign(uninits);
2126             }
2127 
2128             @Override
2129             public void resolveJump() {
2130                 inits.andSet(exit_inits);
2131                 uninits.andSet(exit_uninits);
2132             }
2133         }
2134 
2135         // Are constructors allowed to leak this reference ?
2136         ThisExposability thisExposability = ALLOWED;
2137 
2138         public AssignAnalyzer() {
2139             this.inits = new Bits();
2140             uninits = new Bits();
2141             uninitsTry = new Bits();
2142             initsWhenTrue = new Bits(true);
2143             initsWhenFalse = new Bits(true);
2144             uninitsWhenTrue = new Bits(true);
2145             uninitsWhenFalse = new Bits(true);
2146         }
2147 
2148         private boolean isInitialConstructor = false;
2149 
2150         @Override
2151         protected void markDead() {
2152             if (!isInitialConstructor) {
2153                 inits.inclRange(returnadr, nextadr);
2154             } else {
2155                 for (int address = returnadr; address < nextadr; address++) {
2156                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
2157                         inits.incl(address);

2243                 } else {
2244                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2245                     uninits.excl(sym.adr);
2246                 }
2247             }
2248 
2249         /** If tree is either a simple name or of the form this.name or
2250          *  C.this.name, and tree represents a trackable variable,
2251          *  record an initialization of the variable.
2252          */
2253         void letInit(JCTree tree) {
2254             tree = TreeInfo.skipParens(tree);
2255             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2256                 Symbol sym = TreeInfo.symbol(tree);
2257                 if (sym.kind == VAR) {
2258                     letInit(tree.pos(), (VarSymbol)sym);
2259                 }
2260             }
2261         }
2262 
2263         void checkEmbryonicThisExposure(JCTree node) {
2264             if (this.thisExposability == ALLOWED || classDef == null)
2265                 return;
2266 
2267             // Note: for non-initial constructors, firstadr is post all instance fields.
2268             for (int i = firstadr; i < nextadr; i++) {
2269                 VarSymbol sym = vardecls[i].sym;
2270                 if (sym.owner != classDef.sym)
2271                     continue;
2272                 if ((sym.flags() & (FINAL | HASINIT | STATIC | PARAMETER)) != FINAL)
2273                     continue;
2274                 if (sym.pos < startPos || sym.adr < firstadr)
2275                     continue;
2276                 if (!inits.isMember(sym.adr)) {
2277                     if (this.thisExposability == BANNED) {
2278                         log.error(node, Errors.ThisExposedPrematurely);
2279                     }
2280                     return; // don't flog a dead horse.
2281                 }
2282             }
2283         }
2284 
2285         /** Check that trackable variable is initialized.
2286          */
2287         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2288             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2289         }
2290 
2291         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2292             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2293                 trackable(sym) &&
2294                 !inits.isMember(sym.adr) &&
2295                 (sym.flags_field & CLASH) == 0) {
2296                     log.error(pos, errkey);
2297                 inits.incl(sym.adr);
2298             }
2299         }
2300 
2301         /** Utility method to reset several Bits instances.
2302          */
2303         private void resetBits(Bits... bits) {
2304             for (Bits b : bits) {

2470                     classDef = classDefPrev;
2471                 }
2472             } finally {
2473                 lint = lintPrev;
2474             }
2475         }
2476 
2477         public void visitMethodDef(JCMethodDecl tree) {
2478             if (tree.body == null) {
2479                 return;
2480             }
2481 
2482             /*  MemberEnter can generate synthetic methods ignore them
2483              */
2484             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2485                 return;
2486             }
2487 
2488             Lint lintPrev = lint;
2489             lint = lint.augment(tree.sym);
2490             ThisExposability priorThisExposability = this.thisExposability;
2491             try {
2492                 final Bits initsPrev = new Bits(inits);
2493                 final Bits uninitsPrev = new Bits(uninits);
2494                 int nextadrPrev = nextadr;
2495                 int firstadrPrev = firstadr;
2496                 int returnadrPrev = returnadr;
2497 
2498                 Assert.check(pendingExits.isEmpty());
2499                 boolean lastInitialConstructor = isInitialConstructor;
2500                 try {
2501                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2502 
2503                     if (!isInitialConstructor) {
2504                         firstadr = nextadr;
2505                         this.thisExposability = ALLOWED;
2506                     } else {
2507                         if (tree.sym.owner.type.isValueClass())
2508                             this.thisExposability = BANNED;
2509                         else
2510                             this.thisExposability = ALLOWED;
2511                     }
2512                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2513                         JCVariableDecl def = l.head;
2514                         scan(def);
2515                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2516                         /*  If we are executing the code from Gen, then there can be
2517                          *  synthetic or mandated variables, ignore them.
2518                          */
2519                         initParam(def);
2520                     }
2521                     // else we are in an instance initializer block;
2522                     // leave caught unchanged.
2523                     scan(tree.body);
2524 
2525                     boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2526                             (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2527                     if (isInitialConstructor) {
2528                         boolean isSynthesized = (tree.sym.flags() &
2529                                                  GENERATEDCONSTR) != 0;
2530                         for (int i = firstadr; i < nextadr; i++) {

2553                                     } else {
2554                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2555                                     }
2556                                 } else {
2557                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2558                                 }
2559                             }
2560                         }
2561                     }
2562                     clearPendingExits(true);
2563                 } finally {
2564                     inits.assign(initsPrev);
2565                     uninits.assign(uninitsPrev);
2566                     nextadr = nextadrPrev;
2567                     firstadr = firstadrPrev;
2568                     returnadr = returnadrPrev;
2569                     isInitialConstructor = lastInitialConstructor;
2570                 }
2571             } finally {
2572                 lint = lintPrev;
2573                 this.thisExposability = priorThisExposability;
2574             }
2575         }
2576 
2577         private void clearPendingExits(boolean inMethod) {
2578             List<PendingExit> exits = pendingExits.toList();
2579             pendingExits = new ListBuffer<>();
2580             while (exits.nonEmpty()) {
2581                 PendingExit exit = exits.head;
2582                 exits = exits.tail;
2583                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2584                                  log.hasErrorOn(exit.tree.pos()),
2585                              exit.tree);
2586                 if (inMethod && isInitialConstructor) {
2587                     Assert.check(exit instanceof AssignPendingExit);
2588                     inits.assign(((AssignPendingExit) exit).exit_inits);
2589                     for (int i = firstadr; i < nextadr; i++) {
2590                         checkInit(exit.tree.pos(), vardecls[i].sym);
2591                     }
2592                 }
2593             }

3022 
3023         @Override
3024         public void visitContinue(JCContinue tree) {
3025             recordExit(new AssignPendingExit(tree, inits, uninits));
3026         }
3027 
3028         @Override
3029         public void visitReturn(JCReturn tree) {
3030             scanExpr(tree.expr);
3031             recordExit(new AssignPendingExit(tree, inits, uninits));
3032         }
3033 
3034         public void visitThrow(JCThrow tree) {
3035             scanExpr(tree.expr);
3036             markDead();
3037         }
3038 
3039         public void visitApply(JCMethodInvocation tree) {
3040             scanExpr(tree.meth);
3041             scanExprs(tree.args);
3042             if (tree.meth.hasTag(IDENT)) {
3043                 JCIdent ident = (JCIdent) tree.meth;
3044                 if (ident.name != names._super && !ident.sym.isStatic())
3045                     checkEmbryonicThisExposure(tree);
3046             }
3047         }
3048 
3049         public void visitNewClass(JCNewClass tree) {
3050             scanExpr(tree.encl);
3051             scanExprs(tree.args);
3052             scan(tree.def);
3053             if (classDef != null && tree.encl == null && tree.clazz.hasTag(IDENT)) {
3054                 JCIdent clazz = (JCIdent) tree.clazz;
3055                 if (!clazz.sym.isStatic() && clazz.type.getEnclosingType().tsym == classDef.sym) {
3056                     checkEmbryonicThisExposure(tree);
3057                 }
3058             }
3059         }
3060 
3061         @Override
3062         public void visitLambda(JCLambda tree) {
3063             final Bits prevUninits = new Bits(uninits);
3064             final Bits prevUninitsTry = new Bits(uninitsTry);
3065             final Bits prevInits = new Bits(inits);
3066             int returnadrPrev = returnadr;
3067             int nextadrPrev = nextadr;
3068             ListBuffer<PendingExit> prevPending = pendingExits;
3069             try {
3070                 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
3071                 // body. This is by design: a variable that was definitely unassigned before the
3072                 // lambda body may end up being assigned to later on, so we cannot conclude that
3073                 // the variable will be unassigned when the body is executed.
3074                 uninits.excludeFrom(firstadr);
3075                 returnadr = nextadr;
3076                 pendingExits = new ListBuffer<>();
3077                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
3078                     JCVariableDecl def = l.head;

3108             uninitsExit.andSet(uninitsWhenTrue);
3109             if (tree.detail != null) {
3110                 inits.assign(initsWhenFalse);
3111                 uninits.assign(uninitsWhenFalse);
3112                 scanExpr(tree.detail);
3113             }
3114             inits.assign(initsExit);
3115             uninits.assign(uninitsExit);
3116         }
3117 
3118         public void visitAssign(JCAssign tree) {
3119             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3120                 scanExpr(tree.lhs);
3121             scanExpr(tree.rhs);
3122             letInit(tree.lhs);
3123         }
3124 
3125         // check fields accessed through this.<field> are definitely
3126         // assigned before reading their value
3127         public void visitSelect(JCFieldAccess tree) {
3128             ThisExposability priorThisExposability = this.thisExposability;
3129             try {
3130                 if (tree.name == names._this && classDef != null && tree.sym.owner == classDef.sym) {
3131                     checkEmbryonicThisExposure(tree);
3132                 } else if (tree.sym.kind == VAR || tree.sym.isStatic()) {
3133                     this.thisExposability = ALLOWED;
3134                 }
3135                 super.visitSelect(tree);
3136             if (TreeInfo.isThisQualifier(tree.selected) &&
3137                 tree.sym.kind == VAR) {
3138                     checkInit(tree.pos(), (VarSymbol)tree.sym);
3139                 }
3140             } finally {
3141                  this.thisExposability = priorThisExposability;
3142             }
3143         }
3144 
3145         public void visitAssignop(JCAssignOp tree) {
3146             scanExpr(tree.lhs);
3147             scanExpr(tree.rhs);
3148             letInit(tree.lhs);
3149         }
3150 
3151         public void visitUnary(JCUnary tree) {
3152             switch (tree.getTag()) {
3153             case NOT:
3154                 scanCond(tree.arg);
3155                 final Bits t = new Bits(initsWhenFalse);
3156                 initsWhenFalse.assign(initsWhenTrue);
3157                 initsWhenTrue.assign(t);
3158                 t.assign(uninitsWhenFalse);
3159                 uninitsWhenFalse.assign(uninitsWhenTrue);
3160                 uninitsWhenTrue.assign(t);
3161                 break;

3185                 scanCond(tree.lhs);
3186                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3187                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3188                 inits.assign(initsWhenFalse);
3189                 uninits.assign(uninitsWhenFalse);
3190                 scanCond(tree.rhs);
3191                 initsWhenTrue.andSet(initsWhenTrueLeft);
3192                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3193                 break;
3194             default:
3195                 scanExpr(tree.lhs);
3196                 scanExpr(tree.rhs);
3197             }
3198         }
3199 
3200         public void visitIdent(JCIdent tree) {
3201             if (tree.sym.kind == VAR) {
3202                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3203                 referenced(tree.sym);
3204             }
3205             if (tree.name == names._this) {
3206                 checkEmbryonicThisExposure(tree);
3207             }
3208         }
3209 
3210         @Override
3211         public void visitTypeTest(JCInstanceOf tree) {
3212             scanExpr(tree.expr);
3213             scan(tree.pattern);
3214         }
3215 
3216         @Override
3217         public void visitBindingPattern(JCBindingPattern tree) {
3218             scan(tree.var);
3219             initParam(tree.var);
3220         }
3221 
3222         void referenced(Symbol sym) {
3223             unrefdResources.remove(sym);
3224         }
3225 
3226         public void visitAnnotatedType(JCAnnotatedType tree) {
3227             // annotations don't get scanned
< prev index next >