< prev index next >

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

Print this page

  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 //todo: one might eliminate uninits.andSets when monotonic
  27 
  28 package com.sun.tools.javac.comp;
  29 

  30 import java.util.Map;
  31 import java.util.Map.Entry;
  32 import java.util.HashMap;
  33 import java.util.HashSet;
  34 import java.util.Set;
  35 import java.util.function.Consumer;
  36 
  37 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
  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.LintWarnings;
  42 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  43 import com.sun.tools.javac.tree.*;
  44 import com.sun.tools.javac.util.*;
  45 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  46 import com.sun.tools.javac.util.JCDiagnostic.Error;
  47 import com.sun.tools.javac.util.JCDiagnostic.Warning;
  48 
  49 import com.sun.tools.javac.code.Symbol.*;

 198  *  support for assigning to a final field via this.x.
 199  *
 200  *  <p><b>This is NOT part of any supported API.
 201  *  If you write code that depends on this, you do so at your own risk.
 202  *  This code and its internal interfaces are subject to change or
 203  *  deletion without notice.</b>
 204  */
 205 public class Flow {
 206     protected static final Context.Key<Flow> flowKey = new Context.Key<>();
 207 
 208     private final Names names;
 209     private final Log log;
 210     private final Symtab syms;
 211     private final Types types;
 212     private final Check chk;
 213     private       TreeMaker make;
 214     private final Resolve rs;
 215     private final JCDiagnostic.Factory diags;
 216     private Env<AttrContext> attrEnv;
 217     private final Infer infer;


 218 
 219     public static Flow instance(Context context) {
 220         Flow instance = context.get(flowKey);
 221         if (instance == null)
 222             instance = new Flow(context);
 223         return instance;
 224     }
 225 
 226     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
 227         new AliveAnalyzer().analyzeTree(env, make);
 228         new AssignAnalyzer().analyzeTree(env, make);
 229         new FlowAnalyzer().analyzeTree(env, make);
 230         new CaptureAnalyzer().analyzeTree(env, make);
 231     }
 232 
 233     public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
 234         Log.DiagnosticHandler diagHandler = null;
 235         //we need to disable diagnostics temporarily; the problem is that if
 236         //a lambda expression contains e.g. an unreachable statement, an error
 237         //message will be reported and will cause compilation to skip the flow analysis

 322             this.errKey = errKey;
 323             this.isFinal = isFinal;
 324         }
 325 
 326         boolean isFinal() {
 327             return isFinal;
 328         }
 329     }
 330 
 331     @SuppressWarnings("this-escape")
 332     protected Flow(Context context) {
 333         context.put(flowKey, this);
 334         names = Names.instance(context);
 335         log = Log.instance(context);
 336         syms = Symtab.instance(context);
 337         types = Types.instance(context);
 338         chk = Check.instance(context);
 339         infer = Infer.instance(context);
 340         rs = Resolve.instance(context);
 341         diags = JCDiagnostic.Factory.instance(context);


 342         Source source = Source.instance(context);


 343     }
 344 
 345     /**
 346      * Base visitor class for all visitors implementing dataflow analysis logic.
 347      * This class define the shared logic for handling jumps (break/continue statements).
 348      */
 349     abstract static class BaseAnalyzer extends TreeScanner {
 350 
 351         enum JumpKind {
 352             BREAK(JCTree.Tag.BREAK) {
 353                 @Override
 354                 JCTree getTarget(JCTree tree) {
 355                     return ((JCBreak)tree).target;
 356                 }
 357             },
 358             CONTINUE(JCTree.Tag.CONTINUE) {
 359                 @Override
 360                 JCTree getTarget(JCTree tree) {
 361                     return ((JCContinue)tree).target;
 362                 }

 459             }
 460         }
 461 
 462         public void visitPackageDef(JCPackageDecl tree) {
 463             // Do nothing for PackageDecl
 464         }
 465 
 466         protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
 467             if (swtch.hasTag(SWITCH_EXPRESSION)) {
 468                 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
 469                                                                 .setType(swtch.type));
 470                 brk.target = swtch;
 471                 scan(brk);
 472             } else {
 473                 JCBreak brk = make.at(Position.NOPOS).Break(null);
 474                 brk.target = swtch;
 475                 scan(brk);
 476             }
 477         }
 478 
 479         // Do something with all static or non-static field initializers and initialization blocks.
 480         protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {










 481             if (classDef == initScanClass)          // avoid infinite loops
 482                 return;
 483             JCClassDecl initScanClassPrev = initScanClass;
 484             initScanClass = classDef;
 485             try {
 486                 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
 487                     JCTree def = defs.head;
 488 
 489                     // Don't recurse into nested classes
 490                     if (def.hasTag(CLASSDEF))
 491                         continue;
 492 
 493                     /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
 494                      * represented in the symbol but not in the tree modifiers as they were not originally in the source
 495                      * code
 496                      */
 497                     boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
 498                     if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic))
 499                         handler.accept(def);










 500                 }
 501             } finally {
 502                 initScanClass = initScanClassPrev;
 503             }
 504         }
 505     }
 506 
 507     /**
 508      * This pass implements the first step of the dataflow analysis, namely
 509      * the liveness analysis check. This checks that every statement is reachable.
 510      * The output of this analysis pass are used by other analyzers. This analyzer
 511      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
 512      */
 513     class AliveAnalyzer extends BaseAnalyzer {
 514 
 515         /** A flag that indicates whether the last statement could
 516          *  complete normally.
 517          */
 518         private Liveness alive;
 519 

2124             }
2125 
2126             @Override
2127             public void resolveJump() {
2128                 inits.andSet(exit_inits);
2129                 uninits.andSet(exit_uninits);
2130             }
2131         }
2132 
2133         public AssignAnalyzer() {
2134             this.inits = new Bits();
2135             uninits = new Bits();
2136             uninitsTry = new Bits();
2137             initsWhenTrue = new Bits(true);
2138             initsWhenFalse = new Bits(true);
2139             uninitsWhenTrue = new Bits(true);
2140             uninitsWhenFalse = new Bits(true);
2141         }
2142 
2143         private boolean isConstructor;

2144 
2145         @Override
2146         protected void markDead() {
2147             inits.inclRange(returnadr, nextadr);
2148             uninits.inclRange(returnadr, nextadr);
2149         }
2150 
2151         /*-------------- Processing variables ----------------------*/
2152 
2153         /** Do we need to track init/uninit state of this symbol?
2154          *  I.e. is symbol either a local or a blank final variable?
2155          */
2156         protected boolean trackable(VarSymbol sym) {
2157             return
2158                 sym.pos >= startPos &&
2159                 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2160                 isFinalUninitializedField(sym)));
2161         }
2162 
2163         boolean isFinalUninitializedField(VarSymbol sym) {
2164             return sym.owner.kind == TYP &&
2165                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&

2166                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2167         }
2168 
2169         /** Initialize new trackable variable by setting its address field
2170          *  to the next available sequence number and entering it under that
2171          *  index into the vars array.
2172          */
2173         void newVar(JCVariableDecl varDecl) {
2174             VarSymbol sym = varDecl.sym;
2175             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2176             if ((sym.flags() & FINAL) == 0) {
2177                 sym.flags_field |= EFFECTIVELY_FINAL;
2178             }
2179             sym.adr = nextadr;
2180             vardecls[nextadr] = varDecl;
2181             inits.excl(nextadr);
2182             uninits.incl(nextadr);
2183             nextadr++;
2184         }
2185 

2217                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2218             }
2219         }
2220         //where
2221             void uninit(VarSymbol sym) {
2222                 if (!inits.isMember(sym.adr)) {
2223                     // reachable assignment
2224                     uninits.excl(sym.adr);
2225                     uninitsTry.excl(sym.adr);
2226                 } else {
2227                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2228                     uninits.excl(sym.adr);
2229                 }
2230             }
2231 
2232         /** If tree is either a simple name or of the form this.name or
2233          *  C.this.name, and tree represents a trackable variable,
2234          *  record an initialization of the variable.
2235          */
2236         void letInit(JCTree tree) {




2237             tree = TreeInfo.skipParens(tree);
2238             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2239                 Symbol sym = TreeInfo.symbol(tree);
2240                 if (sym.kind == VAR) {
2241                     letInit(tree.pos(), (VarSymbol)sym);






2242                 }
2243             }
2244         }
2245 
2246         /** Check that trackable variable is initialized.
2247          */
2248         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2249             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2250         }
2251 
2252         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2253             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2254                 trackable(sym) &&
2255                 !inits.isMember(sym.adr) &&
2256                 (sym.flags_field & CLASH) == 0) {
2257                     log.error(pos, errkey);
2258                 inits.incl(sym.adr);
2259             }
2260         }
2261 
2262         /** Utility method to reset several Bits instances.
2263          */
2264         private void resetBits(Bits... bits) {
2265             for (Bits b : bits) {
2266                 b.reset();
2267             }
2268         }
2269 
2270         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2271          */
2272         void split(boolean setToNull) {
2273             initsWhenFalse.assign(inits);
2274             uninitsWhenFalse.assign(uninits);
2275             initsWhenTrue.assign(inits);
2276             uninitsWhenTrue.assign(uninits);
2277             if (setToNull) {

2426 
2427         public void visitMethodDef(JCMethodDecl tree) {
2428             if (tree.body == null) {
2429                 return;
2430             }
2431 
2432             /*  MemberEnter can generate synthetic methods ignore them
2433              */
2434             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2435                 return;
2436             }
2437 
2438             final Bits initsPrev = new Bits(inits);
2439             final Bits uninitsPrev = new Bits(uninits);
2440             int nextadrPrev = nextadr;
2441             int firstadrPrev = firstadr;
2442             int returnadrPrev = returnadr;
2443 
2444             Assert.check(pendingExits.isEmpty());
2445             boolean isConstructorPrev = isConstructor;

2446             try {
2447                 isConstructor = TreeInfo.isConstructor(tree);


2448 
2449                 // We only track field initialization inside constructors
2450                 if (!isConstructor) {
2451                     firstadr = nextadr;
2452                 }
2453 
2454                 // Mark all method parameters as DA
2455                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2456                     JCVariableDecl def = l.head;
2457                     scan(def);
2458                     Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2459                     /*  If we are executing the code from Gen, then there can be
2460                      *  synthetic or mandated variables, ignore them.
2461                      */
2462                     initParam(def);
2463                 }







2464                 // else we are in an instance initializer block;
2465                 // leave caught unchanged.
2466                 scan(tree.body);
2467 
2468                 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2469                         (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2470                 if (isConstructor) {
2471                     boolean isSynthesized = (tree.sym.flags() &
2472                                              GENERATEDCONSTR) != 0;
2473                     for (int i = firstadr; i < nextadr; i++) {
2474                         JCVariableDecl vardecl = vardecls[i];
2475                         VarSymbol var = vardecl.sym;
2476                         if (var.owner == classDef.sym && !var.isStatic()) {
2477                             // choose the diagnostic position based on whether
2478                             // the ctor is default(synthesized) or not
2479                             if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2480                                 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2481                                         var, Errors.VarNotInitializedInDefaultConstructor(var));
2482                             } else if (isCompactOrGeneratedRecordConstructor) {
2483                                 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2484                                         (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2485                                         var.owner.kind == TYP;
2486                                 if (isInstanceRecordField) {
2487                                     boolean notInitialized = !inits.isMember(var.adr);
2488                                     if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2489                                     /*  this way we indicate Lower that it should generate an initialization for this field

2493                                     } else {
2494                                         checkInit(TreeInfo.diagEndPos(tree.body), var);
2495                                     }
2496                                 } else {
2497                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2498                                 }
2499                             } else {
2500                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
2501                             }
2502                         }
2503                     }
2504                 }
2505                 clearPendingExits(true);
2506             } finally {
2507                 inits.assign(initsPrev);
2508                 uninits.assign(uninitsPrev);
2509                 nextadr = nextadrPrev;
2510                 firstadr = firstadrPrev;
2511                 returnadr = returnadrPrev;
2512                 isConstructor = isConstructorPrev;

2513             }
2514         }
2515 











2516         private void clearPendingExits(boolean inMethod) {
2517             List<PendingExit> exits = pendingExits.toList();
2518             pendingExits = new ListBuffer<>();
2519             while (exits.nonEmpty()) {
2520                 PendingExit exit = exits.head;
2521                 exits = exits.tail;
2522                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2523                                  log.hasErrorOn(exit.tree.pos()),
2524                              exit.tree);
2525                 if (inMethod && isConstructor) {
2526                     Assert.check(exit instanceof AssignPendingExit);
2527                     inits.assign(((AssignPendingExit) exit).exit_inits);
2528                     for (int i = firstadr; i < nextadr; i++) {
2529                         checkInit(exit.tree.pos(), vardecls[i].sym);
2530                     }
2531                 }
2532             }
2533         }
2534         protected void initParam(JCVariableDecl def) {
2535             inits.incl(def.sym.adr);

2952             }
2953         }
2954 
2955         @Override
2956         public void visitContinue(JCContinue tree) {
2957             recordExit(new AssignPendingExit(tree, inits, uninits));
2958         }
2959 
2960         @Override
2961         public void visitReturn(JCReturn tree) {
2962             scanExpr(tree.expr);
2963             recordExit(new AssignPendingExit(tree, inits, uninits));
2964         }
2965 
2966         public void visitThrow(JCThrow tree) {
2967             scanExpr(tree.expr);
2968             markDead();
2969         }
2970 
2971         public void visitApply(JCMethodInvocation tree) {








2972             scanExpr(tree.meth);
2973             scanExprs(tree.args);
2974 
2975             // Handle superclass constructor invocations
2976             if (isConstructor) {
2977 
2978                 // If super(): at this point all initialization blocks will execute
2979                 Name name = TreeInfo.name(tree.meth);
2980                 if (name == names._super) {








2981                     forEachInitializer(classDef, false, def -> {
2982                         scan(def);
2983                         clearPendingExits(false);
2984                     });
2985                 }
2986 
2987                 // If this(): at this point all final uninitialized fields will get initialized
2988                 else if (name == names._this) {
2989                     for (int address = firstadr; address < nextadr; address++) {
2990                         VarSymbol sym = vardecls[address].sym;
2991                         if (isFinalUninitializedField(sym) && !sym.isStatic())
2992                             letInit(tree.pos(), sym);
2993                     }
2994                 }
2995             }
2996         }
2997 
2998         public void visitNewClass(JCNewClass tree) {
2999             scanExpr(tree.encl);
3000             scanExprs(tree.args);
3001             scan(tree.def);
3002         }
3003 
3004         @Override
3005         public void visitLambda(JCLambda tree) {
3006             final Bits prevUninits = new Bits(uninits);
3007             final Bits prevUninitsTry = new Bits(uninitsTry);
3008             final Bits prevInits = new Bits(inits);
3009             int returnadrPrev = returnadr;
3010             int nextadrPrev = nextadr;
3011             ListBuffer<PendingExit> prevPending = pendingExits;

3045         }
3046 
3047         public void visitAssert(JCAssert tree) {
3048             final Bits initsExit = new Bits(inits);
3049             final Bits uninitsExit = new Bits(uninits);
3050             scanCond(tree.cond);
3051             uninitsExit.andSet(uninitsWhenTrue);
3052             if (tree.detail != null) {
3053                 inits.assign(initsWhenFalse);
3054                 uninits.assign(uninitsWhenFalse);
3055                 scanExpr(tree.detail);
3056             }
3057             inits.assign(initsExit);
3058             uninits.assign(uninitsExit);
3059         }
3060 
3061         public void visitAssign(JCAssign tree) {
3062             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3063                 scanExpr(tree.lhs);
3064             scanExpr(tree.rhs);
3065             letInit(tree.lhs);
3066         }
3067 
3068         // check fields accessed through this.<field> are definitely
3069         // assigned before reading their value
3070         public void visitSelect(JCFieldAccess tree) {
3071             super.visitSelect(tree);
3072             if (TreeInfo.isThisQualifier(tree.selected) &&
3073                 tree.sym.kind == VAR) {
3074                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3075             }
3076         }
3077 
3078         public void visitAssignop(JCAssignOp tree) {
3079             scanExpr(tree.lhs);
3080             scanExpr(tree.rhs);
3081             letInit(tree.lhs);
3082         }
3083 
3084         public void visitUnary(JCUnary tree) {
3085             switch (tree.getTag()) {

  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 //todo: one might eliminate uninits.andSets when monotonic
  27 
  28 package com.sun.tools.javac.comp;
  29 
  30 import java.util.LinkedHashSet;
  31 import java.util.Map;
  32 import java.util.Map.Entry;
  33 import java.util.HashMap;
  34 import java.util.HashSet;
  35 import java.util.Set;
  36 import java.util.function.Consumer;
  37 
  38 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
  39 import com.sun.tools.javac.code.*;
  40 import com.sun.tools.javac.code.Scope.WriteableScope;
  41 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  42 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
  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.*;

 199  *  support for assigning to a final field via this.x.
 200  *
 201  *  <p><b>This is NOT part of any supported API.
 202  *  If you write code that depends on this, you do so at your own risk.
 203  *  This code and its internal interfaces are subject to change or
 204  *  deletion without notice.</b>
 205  */
 206 public class Flow {
 207     protected static final Context.Key<Flow> flowKey = new Context.Key<>();
 208 
 209     private final Names names;
 210     private final Log log;
 211     private final Symtab syms;
 212     private final Types types;
 213     private final Check chk;
 214     private       TreeMaker make;
 215     private final Resolve rs;
 216     private final JCDiagnostic.Factory diags;
 217     private Env<AttrContext> attrEnv;
 218     private final Infer infer;
 219     private final UnsetFieldsInfo unsetFieldsInfo;
 220     private final boolean allowValueClasses;
 221 
 222     public static Flow instance(Context context) {
 223         Flow instance = context.get(flowKey);
 224         if (instance == null)
 225             instance = new Flow(context);
 226         return instance;
 227     }
 228 
 229     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
 230         new AliveAnalyzer().analyzeTree(env, make);
 231         new AssignAnalyzer().analyzeTree(env, make);
 232         new FlowAnalyzer().analyzeTree(env, make);
 233         new CaptureAnalyzer().analyzeTree(env, make);
 234     }
 235 
 236     public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
 237         Log.DiagnosticHandler diagHandler = null;
 238         //we need to disable diagnostics temporarily; the problem is that if
 239         //a lambda expression contains e.g. an unreachable statement, an error
 240         //message will be reported and will cause compilation to skip the flow analysis

 325             this.errKey = errKey;
 326             this.isFinal = isFinal;
 327         }
 328 
 329         boolean isFinal() {
 330             return isFinal;
 331         }
 332     }
 333 
 334     @SuppressWarnings("this-escape")
 335     protected Flow(Context context) {
 336         context.put(flowKey, this);
 337         names = Names.instance(context);
 338         log = Log.instance(context);
 339         syms = Symtab.instance(context);
 340         types = Types.instance(context);
 341         chk = Check.instance(context);
 342         infer = Infer.instance(context);
 343         rs = Resolve.instance(context);
 344         diags = JCDiagnostic.Factory.instance(context);
 345         unsetFieldsInfo = UnsetFieldsInfo.instance(context);
 346         Preview preview = Preview.instance(context);
 347         Source source = Source.instance(context);
 348         allowValueClasses = (!preview.isPreview(Source.Feature.VALUE_CLASSES) || preview.isEnabled()) &&
 349                 Source.Feature.VALUE_CLASSES.allowedInSource(source);
 350     }
 351 
 352     /**
 353      * Base visitor class for all visitors implementing dataflow analysis logic.
 354      * This class define the shared logic for handling jumps (break/continue statements).
 355      */
 356     abstract static class BaseAnalyzer extends TreeScanner {
 357 
 358         enum JumpKind {
 359             BREAK(JCTree.Tag.BREAK) {
 360                 @Override
 361                 JCTree getTarget(JCTree tree) {
 362                     return ((JCBreak)tree).target;
 363                 }
 364             },
 365             CONTINUE(JCTree.Tag.CONTINUE) {
 366                 @Override
 367                 JCTree getTarget(JCTree tree) {
 368                     return ((JCContinue)tree).target;
 369                 }

 466             }
 467         }
 468 
 469         public void visitPackageDef(JCPackageDecl tree) {
 470             // Do nothing for PackageDecl
 471         }
 472 
 473         protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
 474             if (swtch.hasTag(SWITCH_EXPRESSION)) {
 475                 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
 476                                                                 .setType(swtch.type));
 477                 brk.target = swtch;
 478                 scan(brk);
 479             } else {
 480                 JCBreak brk = make.at(Position.NOPOS).Break(null);
 481                 brk.target = swtch;
 482                 scan(brk);
 483             }
 484         }
 485 
 486         // Do something with static or non-static field initializers and initialization blocks.
 487         protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {
 488             forEachInitializer(classDef, isStatic, false, handler);
 489         }
 490 
 491         /* Do something with static or non-static field initializers and initialization blocks.
 492          * the `earlyOnly` argument will determine if we will deal or not with early variable instance
 493          * initializers we want to process only those before a super() invocation and ignore them after
 494          * it.
 495          */
 496         protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, boolean earlyOnly,
 497                                           Consumer<? super JCTree> handler) {
 498             if (classDef == initScanClass)          // avoid infinite loops
 499                 return;
 500             JCClassDecl initScanClassPrev = initScanClass;
 501             initScanClass = classDef;
 502             try {
 503                 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
 504                     JCTree def = defs.head;
 505 
 506                     // Don't recurse into nested classes
 507                     if (def.hasTag(CLASSDEF))
 508                         continue;
 509 
 510                     /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
 511                      * represented in the symbol but not in the tree modifiers as they were not originally in the source
 512                      * code
 513                      */
 514                     boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
 515                     if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic)) {
 516                         if (def instanceof JCVariableDecl varDecl) {
 517                             boolean isEarly = varDecl.init != null &&
 518                                     varDecl.sym.isStrict() &&
 519                                     !varDecl.sym.isStatic();
 520                             if (isEarly == earlyOnly) {
 521                                 handler.accept(def);
 522                             }
 523                         } else if (!earlyOnly) {
 524                             handler.accept(def);
 525                         }
 526                     }
 527                 }
 528             } finally {
 529                 initScanClass = initScanClassPrev;
 530             }
 531         }
 532     }
 533 
 534     /**
 535      * This pass implements the first step of the dataflow analysis, namely
 536      * the liveness analysis check. This checks that every statement is reachable.
 537      * The output of this analysis pass are used by other analyzers. This analyzer
 538      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
 539      */
 540     class AliveAnalyzer extends BaseAnalyzer {
 541 
 542         /** A flag that indicates whether the last statement could
 543          *  complete normally.
 544          */
 545         private Liveness alive;
 546 

2151             }
2152 
2153             @Override
2154             public void resolveJump() {
2155                 inits.andSet(exit_inits);
2156                 uninits.andSet(exit_uninits);
2157             }
2158         }
2159 
2160         public AssignAnalyzer() {
2161             this.inits = new Bits();
2162             uninits = new Bits();
2163             uninitsTry = new Bits();
2164             initsWhenTrue = new Bits(true);
2165             initsWhenFalse = new Bits(true);
2166             uninitsWhenTrue = new Bits(true);
2167             uninitsWhenFalse = new Bits(true);
2168         }
2169 
2170         private boolean isConstructor;
2171         private boolean isCompactOrGeneratedRecordConstructor;
2172 
2173         @Override
2174         protected void markDead() {
2175             inits.inclRange(returnadr, nextadr);
2176             uninits.inclRange(returnadr, nextadr);
2177         }
2178 
2179         /*-------------- Processing variables ----------------------*/
2180 
2181         /** Do we need to track init/uninit state of this symbol?
2182          *  I.e. is symbol either a local or a blank final variable?
2183          */
2184         protected boolean trackable(VarSymbol sym) {
2185             return
2186                 sym.pos >= startPos &&
2187                 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2188                 isFinalOrStrictUninitializedField(sym)));
2189         }
2190 
2191         boolean isFinalOrStrictUninitializedField(VarSymbol sym) {
2192             return sym.owner.kind == TYP &&
2193                    (((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL ||
2194                      (sym.flags() & (STRICT | HASINIT | PARAMETER)) == STRICT) &&
2195                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2196         }
2197 
2198         /** Initialize new trackable variable by setting its address field
2199          *  to the next available sequence number and entering it under that
2200          *  index into the vars array.
2201          */
2202         void newVar(JCVariableDecl varDecl) {
2203             VarSymbol sym = varDecl.sym;
2204             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2205             if ((sym.flags() & FINAL) == 0) {
2206                 sym.flags_field |= EFFECTIVELY_FINAL;
2207             }
2208             sym.adr = nextadr;
2209             vardecls[nextadr] = varDecl;
2210             inits.excl(nextadr);
2211             uninits.incl(nextadr);
2212             nextadr++;
2213         }
2214 

2246                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2247             }
2248         }
2249         //where
2250             void uninit(VarSymbol sym) {
2251                 if (!inits.isMember(sym.adr)) {
2252                     // reachable assignment
2253                     uninits.excl(sym.adr);
2254                     uninitsTry.excl(sym.adr);
2255                 } else {
2256                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2257                     uninits.excl(sym.adr);
2258                 }
2259             }
2260 
2261         /** If tree is either a simple name or of the form this.name or
2262          *  C.this.name, and tree represents a trackable variable,
2263          *  record an initialization of the variable.
2264          */
2265         void letInit(JCTree tree) {
2266             letInit(tree, (JCAssign) null);
2267         }
2268 
2269         void letInit(JCTree tree, JCAssign assign) {
2270             tree = TreeInfo.skipParens(tree);
2271             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2272                 Symbol sym = TreeInfo.symbol(tree);
2273                 if (sym.kind == VAR) {
2274                     letInit(tree.pos(), (VarSymbol)sym);
2275                     if (isConstructor && sym.isStrict()) {
2276                         /* we are initializing a strict field inside of a constructor, we now need to find which fields
2277                          * haven't been initialized yet
2278                          */
2279                         unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, assign != null ? assign : tree, findUninitStrictFields());
2280                     }
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) {
2305                 b.reset();
2306             }
2307         }
2308 
2309         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2310          */
2311         void split(boolean setToNull) {
2312             initsWhenFalse.assign(inits);
2313             uninitsWhenFalse.assign(uninits);
2314             initsWhenTrue.assign(inits);
2315             uninitsWhenTrue.assign(uninits);
2316             if (setToNull) {

2465 
2466         public void visitMethodDef(JCMethodDecl tree) {
2467             if (tree.body == null) {
2468                 return;
2469             }
2470 
2471             /*  MemberEnter can generate synthetic methods ignore them
2472              */
2473             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2474                 return;
2475             }
2476 
2477             final Bits initsPrev = new Bits(inits);
2478             final Bits uninitsPrev = new Bits(uninits);
2479             int nextadrPrev = nextadr;
2480             int firstadrPrev = firstadr;
2481             int returnadrPrev = returnadr;
2482 
2483             Assert.check(pendingExits.isEmpty());
2484             boolean isConstructorPrev = isConstructor;
2485             boolean isCompactOrGeneratedRecordConstructorPrev = isCompactOrGeneratedRecordConstructor;
2486             try {
2487                 isConstructor = TreeInfo.isConstructor(tree);
2488                 isCompactOrGeneratedRecordConstructor = isConstructor && ((tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2489                          (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD));
2490 
2491                 // We only track field initialization inside constructors
2492                 if (!isConstructor) {
2493                     firstadr = nextadr;
2494                 }
2495 
2496                 // Mark all method parameters as DA
2497                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2498                     JCVariableDecl def = l.head;
2499                     scan(def);
2500                     Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2501                     /*  If we are executing the code from Gen, then there can be
2502                      *  synthetic or mandated variables, ignore them.
2503                      */
2504                     initParam(def);
2505                 }
2506                 if (isConstructor) {
2507                     Set<VarSymbol> unsetFields = findUninitStrictFields();
2508                     if (unsetFields != null && !unsetFields.isEmpty()) {
2509                         unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
2510                     }
2511                 }
2512 
2513                 // else we are in an instance initializer block;
2514                 // leave caught unchanged.
2515                 scan(tree.body);
2516 


2517                 if (isConstructor) {
2518                     boolean isSynthesized = (tree.sym.flags() &
2519                                              GENERATEDCONSTR) != 0;
2520                     for (int i = firstadr; i < nextadr; i++) {
2521                         JCVariableDecl vardecl = vardecls[i];
2522                         VarSymbol var = vardecl.sym;
2523                         if (var.owner == classDef.sym && !var.isStatic()) {
2524                             // choose the diagnostic position based on whether
2525                             // the ctor is default(synthesized) or not
2526                             if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2527                                 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2528                                         var, Errors.VarNotInitializedInDefaultConstructor(var));
2529                             } else if (isCompactOrGeneratedRecordConstructor) {
2530                                 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2531                                         (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2532                                         var.owner.kind == TYP;
2533                                 if (isInstanceRecordField) {
2534                                     boolean notInitialized = !inits.isMember(var.adr);
2535                                     if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2536                                     /*  this way we indicate Lower that it should generate an initialization for this field

2540                                     } else {
2541                                         checkInit(TreeInfo.diagEndPos(tree.body), var);
2542                                     }
2543                                 } else {
2544                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2545                                 }
2546                             } else {
2547                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
2548                             }
2549                         }
2550                     }
2551                 }
2552                 clearPendingExits(true);
2553             } finally {
2554                 inits.assign(initsPrev);
2555                 uninits.assign(uninitsPrev);
2556                 nextadr = nextadrPrev;
2557                 firstadr = firstadrPrev;
2558                 returnadr = returnadrPrev;
2559                 isConstructor = isConstructorPrev;
2560                 isCompactOrGeneratedRecordConstructor = isCompactOrGeneratedRecordConstructorPrev;
2561             }
2562         }
2563 
2564         Set<VarSymbol> findUninitStrictFields() {
2565             Set<VarSymbol> unsetFields = new LinkedHashSet<>();
2566             for (int i = uninits.nextBit(0); i >= 0; i = uninits.nextBit(i + 1)) {
2567                 JCVariableDecl variableDecl = vardecls[i];
2568                 if (variableDecl.sym.isStrict()) {
2569                     unsetFields.add(variableDecl.sym);
2570                 }
2571             }
2572             return unsetFields;
2573         }
2574 
2575         private void clearPendingExits(boolean inMethod) {
2576             List<PendingExit> exits = pendingExits.toList();
2577             pendingExits = new ListBuffer<>();
2578             while (exits.nonEmpty()) {
2579                 PendingExit exit = exits.head;
2580                 exits = exits.tail;
2581                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2582                                  log.hasErrorOn(exit.tree.pos()),
2583                              exit.tree);
2584                 if (inMethod && isConstructor) {
2585                     Assert.check(exit instanceof AssignPendingExit);
2586                     inits.assign(((AssignPendingExit) exit).exit_inits);
2587                     for (int i = firstadr; i < nextadr; i++) {
2588                         checkInit(exit.tree.pos(), vardecls[i].sym);
2589                     }
2590                 }
2591             }
2592         }
2593         protected void initParam(JCVariableDecl def) {
2594             inits.incl(def.sym.adr);

3011             }
3012         }
3013 
3014         @Override
3015         public void visitContinue(JCContinue tree) {
3016             recordExit(new AssignPendingExit(tree, inits, uninits));
3017         }
3018 
3019         @Override
3020         public void visitReturn(JCReturn tree) {
3021             scanExpr(tree.expr);
3022             recordExit(new AssignPendingExit(tree, inits, uninits));
3023         }
3024 
3025         public void visitThrow(JCThrow tree) {
3026             scanExpr(tree.expr);
3027             markDead();
3028         }
3029 
3030         public void visitApply(JCMethodInvocation tree) {
3031             Name name = TreeInfo.name(tree.meth);
3032             // let's process early initializers
3033             if (name == names._super) {
3034                 forEachInitializer(classDef, false, true, def -> {
3035                     scan(def);
3036                     clearPendingExits(false);
3037                 });
3038             }
3039             scanExpr(tree.meth);
3040             scanExprs(tree.args);
3041 
3042             // Handle superclass constructor invocations
3043             if (isConstructor) {
3044 
3045                 // If super(): at this point all initialization blocks will execute
3046 
3047                 if (name == names._super) {
3048                     // strict fields should have been initialized at this point
3049                     for (int i = firstadr; i < nextadr; i++) {
3050                         JCVariableDecl vardecl = vardecls[i];
3051                         VarSymbol var = vardecl.sym;
3052                         if (allowValueClasses && (var.owner == classDef.sym && !var.isStatic() && (var.isStrict() || ((var.flags_field & RECORD) != 0)) && !isCompactOrGeneratedRecordConstructor)) {
3053                             checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
3054                         }
3055                     }
3056                     forEachInitializer(classDef, false, def -> {
3057                         scan(def);
3058                         clearPendingExits(false);
3059                     });
3060                 }
3061 
3062                 // If this(): at this point all final uninitialized fields will get initialized
3063                 else if (name == names._this) {
3064                     for (int address = firstadr; address < nextadr; address++) {
3065                         VarSymbol sym = vardecls[address].sym;
3066                         if (isFinalOrStrictUninitializedField(sym) && !sym.isStatic())
3067                             letInit(tree.pos(), sym);
3068                     }
3069                 }
3070             }
3071         }
3072 
3073         public void visitNewClass(JCNewClass tree) {
3074             scanExpr(tree.encl);
3075             scanExprs(tree.args);
3076             scan(tree.def);
3077         }
3078 
3079         @Override
3080         public void visitLambda(JCLambda tree) {
3081             final Bits prevUninits = new Bits(uninits);
3082             final Bits prevUninitsTry = new Bits(uninitsTry);
3083             final Bits prevInits = new Bits(inits);
3084             int returnadrPrev = returnadr;
3085             int nextadrPrev = nextadr;
3086             ListBuffer<PendingExit> prevPending = pendingExits;

3120         }
3121 
3122         public void visitAssert(JCAssert tree) {
3123             final Bits initsExit = new Bits(inits);
3124             final Bits uninitsExit = new Bits(uninits);
3125             scanCond(tree.cond);
3126             uninitsExit.andSet(uninitsWhenTrue);
3127             if (tree.detail != null) {
3128                 inits.assign(initsWhenFalse);
3129                 uninits.assign(uninitsWhenFalse);
3130                 scanExpr(tree.detail);
3131             }
3132             inits.assign(initsExit);
3133             uninits.assign(uninitsExit);
3134         }
3135 
3136         public void visitAssign(JCAssign tree) {
3137             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3138                 scanExpr(tree.lhs);
3139             scanExpr(tree.rhs);
3140             letInit(tree.lhs, tree);
3141         }
3142 
3143         // check fields accessed through this.<field> are definitely
3144         // assigned before reading their value
3145         public void visitSelect(JCFieldAccess tree) {
3146             super.visitSelect(tree);
3147             if (TreeInfo.isThisQualifier(tree.selected) &&
3148                 tree.sym.kind == VAR) {
3149                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3150             }
3151         }
3152 
3153         public void visitAssignop(JCAssignOp tree) {
3154             scanExpr(tree.lhs);
3155             scanExpr(tree.rhs);
3156             letInit(tree.lhs);
3157         }
3158 
3159         public void visitUnary(JCUnary tree) {
3160             switch (tree.getTag()) {
< prev index next >