< 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

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

1995             inLambda = true;
1996             try {
1997                 pendingExits = new ListBuffer<>();
1998                 caught = List.of(syms.throwableType);
1999                 thrown = List.nil();
2000                 scan(tree.body);
2001                 inferredThrownTypes = thrown;
2002             } finally {
2003                 pendingExits = prevPending;
2004                 caught = prevCaught;
2005                 thrown = prevThrown;
2006                 inLambda = false;
2007             }
2008         }
2009         @Override
2010         public void visitClassDef(JCClassDecl tree) {
2011             //skip
2012         }
2013     }
2014 








2015     /**
2016      * This pass implements (i) definite assignment analysis, which ensures that
2017      * each variable is assigned when used and (ii) definite unassignment analysis,
2018      * which ensures that no final variable is assigned more than once. This visitor
2019      * depends on the results of the liveliness analyzer. This pass is also used to mark
2020      * effectively-final local variables/parameters.
2021      */
2022 
2023     public class AssignAnalyzer extends BaseAnalyzer {
2024 
2025         /** The set of definitely assigned variables.
2026          */
2027         final Bits inits;
2028 
2029         /** The set of definitely unassigned variables.
2030          */
2031         final Bits uninits;
2032 
2033         /** The set of variables that are definitely unassigned everywhere
2034          *  in current try block. This variable is maintained lazily; it is

2083             final Bits inits;
2084             final Bits uninits;
2085             final Bits exit_inits = new Bits(true);
2086             final Bits exit_uninits = new Bits(true);
2087 
2088             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2089                 super(tree);
2090                 this.inits = inits;
2091                 this.uninits = uninits;
2092                 this.exit_inits.assign(inits);
2093                 this.exit_uninits.assign(uninits);
2094             }
2095 
2096             @Override
2097             public void resolveJump() {
2098                 inits.andSet(exit_inits);
2099                 uninits.andSet(exit_uninits);
2100             }
2101         }
2102 



2103         public AssignAnalyzer() {
2104             this.inits = new Bits();
2105             uninits = new Bits();
2106             uninitsTry = new Bits();
2107             initsWhenTrue = new Bits(true);
2108             initsWhenFalse = new Bits(true);
2109             uninitsWhenTrue = new Bits(true);
2110             uninitsWhenFalse = new Bits(true);
2111         }
2112 
2113         private boolean isInitialConstructor = false;
2114 
2115         @Override
2116         protected void markDead() {
2117             if (!isInitialConstructor) {
2118                 inits.inclRange(returnadr, nextadr);
2119             } else {
2120                 for (int address = returnadr; address < nextadr; address++) {
2121                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
2122                         inits.incl(address);

2208                 } else {
2209                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2210                     uninits.excl(sym.adr);
2211                 }
2212             }
2213 
2214         /** If tree is either a simple name or of the form this.name or
2215          *  C.this.name, and tree represents a trackable variable,
2216          *  record an initialization of the variable.
2217          */
2218         void letInit(JCTree tree) {
2219             tree = TreeInfo.skipParens(tree);
2220             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2221                 Symbol sym = TreeInfo.symbol(tree);
2222                 if (sym.kind == VAR) {
2223                     letInit(tree.pos(), (VarSymbol)sym);
2224                 }
2225             }
2226         }
2227 






















2228         /** Check that trackable variable is initialized.
2229          */
2230         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2231             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2232         }
2233 
2234         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2235             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2236                 trackable(sym) &&
2237                 !inits.isMember(sym.adr) &&
2238                 (sym.flags_field & CLASH) == 0) {
2239                     log.error(pos, errkey);
2240                 inits.incl(sym.adr);
2241             }
2242         }
2243 
2244         /** Utility method to reset several Bits instances.
2245          */
2246         private void resetBits(Bits... bits) {
2247             for (Bits b : bits) {

2413                     classDef = classDefPrev;
2414                 }
2415             } finally {
2416                 lint = lintPrev;
2417             }
2418         }
2419 
2420         public void visitMethodDef(JCMethodDecl tree) {
2421             if (tree.body == null) {
2422                 return;
2423             }
2424 
2425             /*  MemberEnter can generate synthetic methods ignore them
2426              */
2427             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2428                 return;
2429             }
2430 
2431             Lint lintPrev = lint;
2432             lint = lint.augment(tree.sym);

2433             try {
2434                 final Bits initsPrev = new Bits(inits);
2435                 final Bits uninitsPrev = new Bits(uninits);
2436                 int nextadrPrev = nextadr;
2437                 int firstadrPrev = firstadr;
2438                 int returnadrPrev = returnadr;
2439 
2440                 Assert.check(pendingExits.isEmpty());
2441                 boolean lastInitialConstructor = isInitialConstructor;
2442                 try {
2443                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2444 
2445                     if (!isInitialConstructor) {
2446                         firstadr = nextadr;






2447                     }
2448                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2449                         JCVariableDecl def = l.head;
2450                         scan(def);
2451                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2452                         /*  If we are executing the code from Gen, then there can be
2453                          *  synthetic or mandated variables, ignore them.
2454                          */
2455                         initParam(def);
2456                     }
2457                     // else we are in an instance initializer block;
2458                     // leave caught unchanged.
2459                     scan(tree.body);
2460 
2461                     boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2462                             (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2463                     if (isInitialConstructor) {
2464                         boolean isSynthesized = (tree.sym.flags() &
2465                                                  GENERATEDCONSTR) != 0;
2466                         for (int i = firstadr; i < nextadr; i++) {

2489                                     } else {
2490                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2491                                     }
2492                                 } else {
2493                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2494                                 }
2495                             }
2496                         }
2497                     }
2498                     clearPendingExits(true);
2499                 } finally {
2500                     inits.assign(initsPrev);
2501                     uninits.assign(uninitsPrev);
2502                     nextadr = nextadrPrev;
2503                     firstadr = firstadrPrev;
2504                     returnadr = returnadrPrev;
2505                     isInitialConstructor = lastInitialConstructor;
2506                 }
2507             } finally {
2508                 lint = lintPrev;

2509             }
2510         }
2511 
2512         private void clearPendingExits(boolean inMethod) {
2513             List<PendingExit> exits = pendingExits.toList();
2514             pendingExits = new ListBuffer<>();
2515             while (exits.nonEmpty()) {
2516                 PendingExit exit = exits.head;
2517                 exits = exits.tail;
2518                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2519                                  log.hasErrorOn(exit.tree.pos()),
2520                              exit.tree);
2521                 if (inMethod && isInitialConstructor) {
2522                     Assert.check(exit instanceof AssignPendingExit);
2523                     inits.assign(((AssignPendingExit) exit).exit_inits);
2524                     for (int i = firstadr; i < nextadr; i++) {
2525                         checkInit(exit.tree.pos(), vardecls[i].sym);
2526                     }
2527                 }
2528             }

2957 
2958         @Override
2959         public void visitContinue(JCContinue tree) {
2960             recordExit(new AssignPendingExit(tree, inits, uninits));
2961         }
2962 
2963         @Override
2964         public void visitReturn(JCReturn tree) {
2965             scanExpr(tree.expr);
2966             recordExit(new AssignPendingExit(tree, inits, uninits));
2967         }
2968 
2969         public void visitThrow(JCThrow tree) {
2970             scanExpr(tree.expr);
2971             markDead();
2972         }
2973 
2974         public void visitApply(JCMethodInvocation tree) {
2975             scanExpr(tree.meth);
2976             scanExprs(tree.args);





2977         }
2978 
2979         public void visitNewClass(JCNewClass tree) {
2980             scanExpr(tree.encl);
2981             scanExprs(tree.args);
2982             scan(tree.def);






2983         }
2984 
2985         @Override
2986         public void visitLambda(JCLambda tree) {
2987             final Bits prevUninits = new Bits(uninits);
2988             final Bits prevUninitsTry = new Bits(uninitsTry);
2989             final Bits prevInits = new Bits(inits);
2990             int returnadrPrev = returnadr;
2991             int nextadrPrev = nextadr;
2992             ListBuffer<PendingExit> prevPending = pendingExits;
2993             try {
2994                 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
2995                 // body. This is by design: a variable that was definitely unassigned before the
2996                 // lambda body may end up being assigned to later on, so we cannot conclude that
2997                 // the variable will be unassigned when the body is executed.
2998                 uninits.excludeFrom(firstadr);
2999                 returnadr = nextadr;
3000                 pendingExits = new ListBuffer<>();
3001                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
3002                     JCVariableDecl def = l.head;

3032             uninitsExit.andSet(uninitsWhenTrue);
3033             if (tree.detail != null) {
3034                 inits.assign(initsWhenFalse);
3035                 uninits.assign(uninitsWhenFalse);
3036                 scanExpr(tree.detail);
3037             }
3038             inits.assign(initsExit);
3039             uninits.assign(uninitsExit);
3040         }
3041 
3042         public void visitAssign(JCAssign tree) {
3043             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3044                 scanExpr(tree.lhs);
3045             scanExpr(tree.rhs);
3046             letInit(tree.lhs);
3047         }
3048 
3049         // check fields accessed through this.<field> are definitely
3050         // assigned before reading their value
3051         public void visitSelect(JCFieldAccess tree) {
3052             super.visitSelect(tree);







3053             if (TreeInfo.isThisQualifier(tree.selected) &&
3054                 tree.sym.kind == VAR) {
3055                 checkInit(tree.pos(), (VarSymbol)tree.sym);



3056             }
3057         }
3058 
3059         public void visitAssignop(JCAssignOp tree) {
3060             scanExpr(tree.lhs);
3061             scanExpr(tree.rhs);
3062             letInit(tree.lhs);
3063         }
3064 
3065         public void visitUnary(JCUnary tree) {
3066             switch (tree.getTag()) {
3067             case NOT:
3068                 scanCond(tree.arg);
3069                 final Bits t = new Bits(initsWhenFalse);
3070                 initsWhenFalse.assign(initsWhenTrue);
3071                 initsWhenTrue.assign(t);
3072                 t.assign(uninitsWhenFalse);
3073                 uninitsWhenFalse.assign(uninitsWhenTrue);
3074                 uninitsWhenTrue.assign(t);
3075                 break;

3099                 scanCond(tree.lhs);
3100                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3101                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3102                 inits.assign(initsWhenFalse);
3103                 uninits.assign(uninitsWhenFalse);
3104                 scanCond(tree.rhs);
3105                 initsWhenTrue.andSet(initsWhenTrueLeft);
3106                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3107                 break;
3108             default:
3109                 scanExpr(tree.lhs);
3110                 scanExpr(tree.rhs);
3111             }
3112         }
3113 
3114         public void visitIdent(JCIdent tree) {
3115             if (tree.sym.kind == VAR) {
3116                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3117                 referenced(tree.sym);
3118             }



3119         }
3120 
3121         @Override
3122         public void visitTypeTest(JCInstanceOf tree) {
3123             scanExpr(tree.expr);
3124             scan(tree.pattern);
3125         }
3126 
3127         @Override
3128         public void visitBindingPattern(JCBindingPattern tree) {
3129             scan(tree.var);
3130             initParam(tree.var);
3131         }
3132 
3133         void referenced(Symbol sym) {
3134             unrefdResources.remove(sym);
3135         }
3136 
3137         public void visitAnnotatedType(JCAnnotatedType tree) {
3138             // 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

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

1997             inLambda = true;
1998             try {
1999                 pendingExits = new ListBuffer<>();
2000                 caught = List.of(syms.throwableType);
2001                 thrown = List.nil();
2002                 scan(tree.body);
2003                 inferredThrownTypes = thrown;
2004             } finally {
2005                 pendingExits = prevPending;
2006                 caught = prevCaught;
2007                 thrown = prevThrown;
2008                 inLambda = false;
2009             }
2010         }
2011         @Override
2012         public void visitClassDef(JCClassDecl tree) {
2013             //skip
2014         }
2015     }
2016 
2017     /** Enum to model whether constructors allowed to "leak" this reference before
2018         all instance fields are DA.
2019      */
2020     enum ThisExposability {
2021         ALLOWED,     // identity Object classes - NOP
2022         BANNED,      // primitive/value classes - Error
2023     }
2024 
2025     /**
2026      * This pass implements (i) definite assignment analysis, which ensures that
2027      * each variable is assigned when used and (ii) definite unassignment analysis,
2028      * which ensures that no final variable is assigned more than once. This visitor
2029      * depends on the results of the liveliness analyzer. This pass is also used to mark
2030      * effectively-final local variables/parameters.
2031      */
2032 
2033     public class AssignAnalyzer extends BaseAnalyzer {
2034 
2035         /** The set of definitely assigned variables.
2036          */
2037         final Bits inits;
2038 
2039         /** The set of definitely unassigned variables.
2040          */
2041         final Bits uninits;
2042 
2043         /** The set of variables that are definitely unassigned everywhere
2044          *  in current try block. This variable is maintained lazily; it is

2093             final Bits inits;
2094             final Bits uninits;
2095             final Bits exit_inits = new Bits(true);
2096             final Bits exit_uninits = new Bits(true);
2097 
2098             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
2099                 super(tree);
2100                 this.inits = inits;
2101                 this.uninits = uninits;
2102                 this.exit_inits.assign(inits);
2103                 this.exit_uninits.assign(uninits);
2104             }
2105 
2106             @Override
2107             public void resolveJump() {
2108                 inits.andSet(exit_inits);
2109                 uninits.andSet(exit_uninits);
2110             }
2111         }
2112 
2113         // Are constructors allowed to leak this reference ?
2114         ThisExposability thisExposability = ALLOWED;
2115 
2116         public AssignAnalyzer() {
2117             this.inits = new Bits();
2118             uninits = new Bits();
2119             uninitsTry = new Bits();
2120             initsWhenTrue = new Bits(true);
2121             initsWhenFalse = new Bits(true);
2122             uninitsWhenTrue = new Bits(true);
2123             uninitsWhenFalse = new Bits(true);
2124         }
2125 
2126         private boolean isInitialConstructor = false;
2127 
2128         @Override
2129         protected void markDead() {
2130             if (!isInitialConstructor) {
2131                 inits.inclRange(returnadr, nextadr);
2132             } else {
2133                 for (int address = returnadr; address < nextadr; address++) {
2134                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
2135                         inits.incl(address);

2221                 } else {
2222                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2223                     uninits.excl(sym.adr);
2224                 }
2225             }
2226 
2227         /** If tree is either a simple name or of the form this.name or
2228          *  C.this.name, and tree represents a trackable variable,
2229          *  record an initialization of the variable.
2230          */
2231         void letInit(JCTree tree) {
2232             tree = TreeInfo.skipParens(tree);
2233             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2234                 Symbol sym = TreeInfo.symbol(tree);
2235                 if (sym.kind == VAR) {
2236                     letInit(tree.pos(), (VarSymbol)sym);
2237                 }
2238             }
2239         }
2240 
2241         void checkEmbryonicThisExposure(JCTree node) {
2242             if (this.thisExposability == ALLOWED || classDef == null)
2243                 return;
2244 
2245             // Note: for non-initial constructors, firstadr is post all instance fields.
2246             for (int i = firstadr; i < nextadr; i++) {
2247                 VarSymbol sym = vardecls[i].sym;
2248                 if (sym.owner != classDef.sym)
2249                     continue;
2250                 if ((sym.flags() & (FINAL | HASINIT | STATIC | PARAMETER)) != FINAL)
2251                     continue;
2252                 if (sym.pos < startPos || sym.adr < firstadr)
2253                     continue;
2254                 if (!inits.isMember(sym.adr)) {
2255                     if (this.thisExposability == BANNED) {
2256                         log.error(node, Errors.ThisExposedPrematurely);
2257                     }
2258                     return; // don't flog a dead horse.
2259                 }
2260             }
2261         }
2262 
2263         /** Check that trackable variable is initialized.
2264          */
2265         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2266             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2267         }
2268 
2269         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2270             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2271                 trackable(sym) &&
2272                 !inits.isMember(sym.adr) &&
2273                 (sym.flags_field & CLASH) == 0) {
2274                     log.error(pos, errkey);
2275                 inits.incl(sym.adr);
2276             }
2277         }
2278 
2279         /** Utility method to reset several Bits instances.
2280          */
2281         private void resetBits(Bits... bits) {
2282             for (Bits b : bits) {

2448                     classDef = classDefPrev;
2449                 }
2450             } finally {
2451                 lint = lintPrev;
2452             }
2453         }
2454 
2455         public void visitMethodDef(JCMethodDecl tree) {
2456             if (tree.body == null) {
2457                 return;
2458             }
2459 
2460             /*  MemberEnter can generate synthetic methods ignore them
2461              */
2462             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2463                 return;
2464             }
2465 
2466             Lint lintPrev = lint;
2467             lint = lint.augment(tree.sym);
2468             ThisExposability priorThisExposability = this.thisExposability;
2469             try {
2470                 final Bits initsPrev = new Bits(inits);
2471                 final Bits uninitsPrev = new Bits(uninits);
2472                 int nextadrPrev = nextadr;
2473                 int firstadrPrev = firstadr;
2474                 int returnadrPrev = returnadr;
2475 
2476                 Assert.check(pendingExits.isEmpty());
2477                 boolean lastInitialConstructor = isInitialConstructor;
2478                 try {
2479                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2480 
2481                     if (!isInitialConstructor) {
2482                         firstadr = nextadr;
2483                         this.thisExposability = ALLOWED;
2484                     } else {
2485                         if (tree.sym.owner.type.isValueClass())
2486                             this.thisExposability = BANNED;
2487                         else
2488                             this.thisExposability = ALLOWED;
2489                     }
2490                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2491                         JCVariableDecl def = l.head;
2492                         scan(def);
2493                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2494                         /*  If we are executing the code from Gen, then there can be
2495                          *  synthetic or mandated variables, ignore them.
2496                          */
2497                         initParam(def);
2498                     }
2499                     // else we are in an instance initializer block;
2500                     // leave caught unchanged.
2501                     scan(tree.body);
2502 
2503                     boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2504                             (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2505                     if (isInitialConstructor) {
2506                         boolean isSynthesized = (tree.sym.flags() &
2507                                                  GENERATEDCONSTR) != 0;
2508                         for (int i = firstadr; i < nextadr; i++) {

2531                                     } else {
2532                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2533                                     }
2534                                 } else {
2535                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2536                                 }
2537                             }
2538                         }
2539                     }
2540                     clearPendingExits(true);
2541                 } finally {
2542                     inits.assign(initsPrev);
2543                     uninits.assign(uninitsPrev);
2544                     nextadr = nextadrPrev;
2545                     firstadr = firstadrPrev;
2546                     returnadr = returnadrPrev;
2547                     isInitialConstructor = lastInitialConstructor;
2548                 }
2549             } finally {
2550                 lint = lintPrev;
2551                 this.thisExposability = priorThisExposability;
2552             }
2553         }
2554 
2555         private void clearPendingExits(boolean inMethod) {
2556             List<PendingExit> exits = pendingExits.toList();
2557             pendingExits = new ListBuffer<>();
2558             while (exits.nonEmpty()) {
2559                 PendingExit exit = exits.head;
2560                 exits = exits.tail;
2561                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2562                                  log.hasErrorOn(exit.tree.pos()),
2563                              exit.tree);
2564                 if (inMethod && isInitialConstructor) {
2565                     Assert.check(exit instanceof AssignPendingExit);
2566                     inits.assign(((AssignPendingExit) exit).exit_inits);
2567                     for (int i = firstadr; i < nextadr; i++) {
2568                         checkInit(exit.tree.pos(), vardecls[i].sym);
2569                     }
2570                 }
2571             }

3000 
3001         @Override
3002         public void visitContinue(JCContinue tree) {
3003             recordExit(new AssignPendingExit(tree, inits, uninits));
3004         }
3005 
3006         @Override
3007         public void visitReturn(JCReturn tree) {
3008             scanExpr(tree.expr);
3009             recordExit(new AssignPendingExit(tree, inits, uninits));
3010         }
3011 
3012         public void visitThrow(JCThrow tree) {
3013             scanExpr(tree.expr);
3014             markDead();
3015         }
3016 
3017         public void visitApply(JCMethodInvocation tree) {
3018             scanExpr(tree.meth);
3019             scanExprs(tree.args);
3020             if (tree.meth.hasTag(IDENT)) {
3021                 JCIdent ident = (JCIdent) tree.meth;
3022                 if (ident.name != names._super && !ident.sym.isStatic())
3023                     checkEmbryonicThisExposure(tree);
3024             }
3025         }
3026 
3027         public void visitNewClass(JCNewClass tree) {
3028             scanExpr(tree.encl);
3029             scanExprs(tree.args);
3030             scan(tree.def);
3031             if (classDef != null && tree.encl == null && tree.clazz.hasTag(IDENT)) {
3032                 JCIdent clazz = (JCIdent) tree.clazz;
3033                 if (!clazz.sym.isStatic() && clazz.type.getEnclosingType().tsym == classDef.sym) {
3034                     checkEmbryonicThisExposure(tree);
3035                 }
3036             }
3037         }
3038 
3039         @Override
3040         public void visitLambda(JCLambda tree) {
3041             final Bits prevUninits = new Bits(uninits);
3042             final Bits prevUninitsTry = new Bits(uninitsTry);
3043             final Bits prevInits = new Bits(inits);
3044             int returnadrPrev = returnadr;
3045             int nextadrPrev = nextadr;
3046             ListBuffer<PendingExit> prevPending = pendingExits;
3047             try {
3048                 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
3049                 // body. This is by design: a variable that was definitely unassigned before the
3050                 // lambda body may end up being assigned to later on, so we cannot conclude that
3051                 // the variable will be unassigned when the body is executed.
3052                 uninits.excludeFrom(firstadr);
3053                 returnadr = nextadr;
3054                 pendingExits = new ListBuffer<>();
3055                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
3056                     JCVariableDecl def = l.head;

3086             uninitsExit.andSet(uninitsWhenTrue);
3087             if (tree.detail != null) {
3088                 inits.assign(initsWhenFalse);
3089                 uninits.assign(uninitsWhenFalse);
3090                 scanExpr(tree.detail);
3091             }
3092             inits.assign(initsExit);
3093             uninits.assign(uninitsExit);
3094         }
3095 
3096         public void visitAssign(JCAssign tree) {
3097             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3098                 scanExpr(tree.lhs);
3099             scanExpr(tree.rhs);
3100             letInit(tree.lhs);
3101         }
3102 
3103         // check fields accessed through this.<field> are definitely
3104         // assigned before reading their value
3105         public void visitSelect(JCFieldAccess tree) {
3106             ThisExposability priorThisExposability = this.thisExposability;
3107             try {
3108                 if (tree.name == names._this && classDef != null && tree.sym.owner == classDef.sym) {
3109                     checkEmbryonicThisExposure(tree);
3110                 } else if (tree.sym.kind == VAR || tree.sym.isStatic()) {
3111                     this.thisExposability = ALLOWED;
3112                 }
3113                 super.visitSelect(tree);
3114             if (TreeInfo.isThisQualifier(tree.selected) &&
3115                 tree.sym.kind == VAR) {
3116                     checkInit(tree.pos(), (VarSymbol)tree.sym);
3117                 }
3118             } finally {
3119                  this.thisExposability = priorThisExposability;
3120             }
3121         }
3122 
3123         public void visitAssignop(JCAssignOp tree) {
3124             scanExpr(tree.lhs);
3125             scanExpr(tree.rhs);
3126             letInit(tree.lhs);
3127         }
3128 
3129         public void visitUnary(JCUnary tree) {
3130             switch (tree.getTag()) {
3131             case NOT:
3132                 scanCond(tree.arg);
3133                 final Bits t = new Bits(initsWhenFalse);
3134                 initsWhenFalse.assign(initsWhenTrue);
3135                 initsWhenTrue.assign(t);
3136                 t.assign(uninitsWhenFalse);
3137                 uninitsWhenFalse.assign(uninitsWhenTrue);
3138                 uninitsWhenTrue.assign(t);
3139                 break;

3163                 scanCond(tree.lhs);
3164                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
3165                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
3166                 inits.assign(initsWhenFalse);
3167                 uninits.assign(uninitsWhenFalse);
3168                 scanCond(tree.rhs);
3169                 initsWhenTrue.andSet(initsWhenTrueLeft);
3170                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
3171                 break;
3172             default:
3173                 scanExpr(tree.lhs);
3174                 scanExpr(tree.rhs);
3175             }
3176         }
3177 
3178         public void visitIdent(JCIdent tree) {
3179             if (tree.sym.kind == VAR) {
3180                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3181                 referenced(tree.sym);
3182             }
3183             if (tree.name == names._this) {
3184                 checkEmbryonicThisExposure(tree);
3185             }
3186         }
3187 
3188         @Override
3189         public void visitTypeTest(JCInstanceOf tree) {
3190             scanExpr(tree.expr);
3191             scan(tree.pattern);
3192         }
3193 
3194         @Override
3195         public void visitBindingPattern(JCBindingPattern tree) {
3196             scan(tree.var);
3197             initParam(tree.var);
3198         }
3199 
3200         void referenced(Symbol sym) {
3201             unrefdResources.remove(sym);
3202         }
3203 
3204         public void visitAnnotatedType(JCAnnotatedType tree) {
3205             // annotations don't get scanned
< prev index next >