< 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.*;

 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       Lint lint;
 218     private final Infer infer;

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

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

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










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










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

2176             uninitsWhenFalse = new Bits(true);
2177         }
2178 
2179         private boolean isConstructor;
2180 
2181         @Override
2182         protected void markDead() {
2183             inits.inclRange(returnadr, nextadr);
2184             uninits.inclRange(returnadr, nextadr);
2185         }
2186 
2187         /*-------------- Processing variables ----------------------*/
2188 
2189         /** Do we need to track init/uninit state of this symbol?
2190          *  I.e. is symbol either a local or a blank final variable?
2191          */
2192         protected boolean trackable(VarSymbol sym) {
2193             return
2194                 sym.pos >= startPos &&
2195                 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2196                 isFinalUninitializedField(sym)));
2197         }
2198 
2199         boolean isFinalUninitializedField(VarSymbol sym) {
2200             return sym.owner.kind == TYP &&
2201                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&

2202                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2203         }
2204 
2205         /** Initialize new trackable variable by setting its address field
2206          *  to the next available sequence number and entering it under that
2207          *  index into the vars array.
2208          */
2209         void newVar(JCVariableDecl varDecl) {
2210             VarSymbol sym = varDecl.sym;
2211             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2212             if ((sym.flags() & FINAL) == 0) {
2213                 sym.flags_field |= EFFECTIVELY_FINAL;
2214             }
2215             sym.adr = nextadr;
2216             vardecls[nextadr] = varDecl;
2217             inits.excl(nextadr);
2218             uninits.incl(nextadr);
2219             nextadr++;
2220         }
2221 

2253                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2254             }
2255         }
2256         //where
2257             void uninit(VarSymbol sym) {
2258                 if (!inits.isMember(sym.adr)) {
2259                     // reachable assignment
2260                     uninits.excl(sym.adr);
2261                     uninitsTry.excl(sym.adr);
2262                 } else {
2263                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2264                     uninits.excl(sym.adr);
2265                 }
2266             }
2267 
2268         /** If tree is either a simple name or of the form this.name or
2269          *  C.this.name, and tree represents a trackable variable,
2270          *  record an initialization of the variable.
2271          */
2272         void letInit(JCTree tree) {




2273             tree = TreeInfo.skipParens(tree);
2274             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2275                 Symbol sym = TreeInfo.symbol(tree);
2276                 if (sym.kind == VAR) {
2277                     letInit(tree.pos(), (VarSymbol)sym);






2278                 }
2279             }
2280         }
2281 
2282         /** Check that trackable variable is initialized.
2283          */
2284         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2285             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2286         }
2287 
2288         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2289             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2290                 trackable(sym) &&
2291                 !inits.isMember(sym.adr) &&
2292                 (sym.flags_field & CLASH) == 0) {
2293                     log.error(pos, errkey);
2294                 inits.incl(sym.adr);
2295             }
2296         }
2297 
2298         /** Utility method to reset several Bits instances.
2299          */
2300         private void resetBits(Bits... bits) {
2301             for (Bits b : bits) {
2302                 b.reset();
2303             }
2304         }
2305 
2306         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2307          */
2308         void split(boolean setToNull) {
2309             initsWhenFalse.assign(inits);
2310             uninitsWhenFalse.assign(uninits);
2311             initsWhenTrue.assign(inits);
2312             uninitsWhenTrue.assign(uninits);
2313             if (setToNull) {

2489                 Assert.check(pendingExits.isEmpty());
2490                 boolean isConstructorPrev = isConstructor;
2491                 try {
2492                     isConstructor = TreeInfo.isConstructor(tree);
2493 
2494                     // We only track field initialization inside constructors
2495                     if (!isConstructor) {
2496                         firstadr = nextadr;
2497                     }
2498 
2499                     // Mark all method parameters as DA
2500                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2501                         JCVariableDecl def = l.head;
2502                         scan(def);
2503                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2504                         /*  If we are executing the code from Gen, then there can be
2505                          *  synthetic or mandated variables, ignore them.
2506                          */
2507                         initParam(def);
2508                     }







2509                     // else we are in an instance initializer block;
2510                     // leave caught unchanged.
2511                     scan(tree.body);
2512 
2513                     boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2514                             (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2515                     if (isConstructor) {
2516                         boolean isSynthesized = (tree.sym.flags() &
2517                                                  GENERATEDCONSTR) != 0;
2518                         for (int i = firstadr; i < nextadr; i++) {
2519                             JCVariableDecl vardecl = vardecls[i];
2520                             VarSymbol var = vardecl.sym;
2521                             if (var.owner == classDef.sym && !var.isStatic()) {
2522                                 // choose the diagnostic position based on whether
2523                                 // the ctor is default(synthesized) or not
2524                                 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2525                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2526                                             var, Errors.VarNotInitializedInDefaultConstructor(var));
2527                                 } else if (isCompactOrGeneratedRecordConstructor) {
2528                                     boolean isInstanceRecordField = var.enclClass().isRecord() &&

2544                                 } else {
2545                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2546                                 }
2547                             }
2548                         }
2549                     }
2550                     clearPendingExits(true);
2551                 } finally {
2552                     inits.assign(initsPrev);
2553                     uninits.assign(uninitsPrev);
2554                     nextadr = nextadrPrev;
2555                     firstadr = firstadrPrev;
2556                     returnadr = returnadrPrev;
2557                     isConstructor = isConstructorPrev;
2558                 }
2559             } finally {
2560                 lint = lintPrev;
2561             }
2562         }
2563 











2564         private void clearPendingExits(boolean inMethod) {
2565             List<PendingExit> exits = pendingExits.toList();
2566             pendingExits = new ListBuffer<>();
2567             while (exits.nonEmpty()) {
2568                 PendingExit exit = exits.head;
2569                 exits = exits.tail;
2570                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2571                                  log.hasErrorOn(exit.tree.pos()),
2572                              exit.tree);
2573                 if (inMethod && isConstructor) {
2574                     Assert.check(exit instanceof AssignPendingExit);
2575                     inits.assign(((AssignPendingExit) exit).exit_inits);
2576                     for (int i = firstadr; i < nextadr; i++) {
2577                         checkInit(exit.tree.pos(), vardecls[i].sym);
2578                     }
2579                 }
2580             }
2581         }
2582         protected void initParam(JCVariableDecl def) {
2583             inits.incl(def.sym.adr);

3007             }
3008         }
3009 
3010         @Override
3011         public void visitContinue(JCContinue tree) {
3012             recordExit(new AssignPendingExit(tree, inits, uninits));
3013         }
3014 
3015         @Override
3016         public void visitReturn(JCReturn tree) {
3017             scanExpr(tree.expr);
3018             recordExit(new AssignPendingExit(tree, inits, uninits));
3019         }
3020 
3021         public void visitThrow(JCThrow tree) {
3022             scanExpr(tree.expr);
3023             markDead();
3024         }
3025 
3026         public void visitApply(JCMethodInvocation tree) {








3027             scanExpr(tree.meth);
3028             scanExprs(tree.args);
3029 
3030             // Handle superclass constructor invocations
3031             if (isConstructor) {
3032 
3033                 // If super(): at this point all initialization blocks will execute
3034                 Name name = TreeInfo.name(tree.meth);
3035                 if (name == names._super) {











3036                     forEachInitializer(classDef, false, def -> {
3037                         scan(def);
3038                         clearPendingExits(false);
3039                     });
3040                 }
3041 
3042                 // If this(): at this point all final uninitialized fields will get initialized
3043                 else if (name == names._this) {
3044                     for (int address = firstadr; address < nextadr; address++) {
3045                         VarSymbol sym = vardecls[address].sym;
3046                         if (isFinalUninitializedField(sym) && !sym.isStatic())
3047                             letInit(tree.pos(), sym);
3048                     }
3049                 }
3050             }
3051         }
3052 
3053         public void visitNewClass(JCNewClass tree) {
3054             scanExpr(tree.encl);
3055             scanExprs(tree.args);
3056             scan(tree.def);
3057         }
3058 
3059         @Override
3060         public void visitLambda(JCLambda tree) {
3061             final Bits prevUninits = new Bits(uninits);
3062             final Bits prevUninitsTry = new Bits(uninitsTry);
3063             final Bits prevInits = new Bits(inits);
3064             int returnadrPrev = returnadr;
3065             int nextadrPrev = nextadr;
3066             ListBuffer<PendingExit> prevPending = pendingExits;

3100         }
3101 
3102         public void visitAssert(JCAssert tree) {
3103             final Bits initsExit = new Bits(inits);
3104             final Bits uninitsExit = new Bits(uninits);
3105             scanCond(tree.cond);
3106             uninitsExit.andSet(uninitsWhenTrue);
3107             if (tree.detail != null) {
3108                 inits.assign(initsWhenFalse);
3109                 uninits.assign(uninitsWhenFalse);
3110                 scanExpr(tree.detail);
3111             }
3112             inits.assign(initsExit);
3113             uninits.assign(uninitsExit);
3114         }
3115 
3116         public void visitAssign(JCAssign tree) {
3117             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3118                 scanExpr(tree.lhs);
3119             scanExpr(tree.rhs);
3120             letInit(tree.lhs);
3121         }
3122 
3123         // check fields accessed through this.<field> are definitely
3124         // assigned before reading their value
3125         public void visitSelect(JCFieldAccess tree) {
3126             super.visitSelect(tree);
3127             if (TreeInfo.isThisQualifier(tree.selected) &&
3128                 tree.sym.kind == VAR) {
3129                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3130             }
3131         }
3132 
3133         public void visitAssignop(JCAssignOp tree) {
3134             scanExpr(tree.lhs);
3135             scanExpr(tree.rhs);
3136             letInit(tree.lhs);
3137         }
3138 
3139         public void visitUnary(JCUnary tree) {
3140             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.*;

 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       Lint lint;
 219     private final Infer infer;
 220     private final UnsetFieldsInfo unsetFieldsInfo;
 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

 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         lint = Lint.instance(context);
 343         infer = Infer.instance(context);
 344         rs = Resolve.instance(context);
 345         diags = JCDiagnostic.Factory.instance(context);
 346         unsetFieldsInfo = UnsetFieldsInfo.instance(context);
 347     }
 348 
 349     /**
 350      * Base visitor class for all visitors implementing dataflow analysis logic.
 351      * This class define the shared logic for handling jumps (break/continue statements).
 352      */
 353     abstract static class BaseAnalyzer extends TreeScanner {
 354 
 355         enum JumpKind {
 356             BREAK(JCTree.Tag.BREAK) {
 357                 @Override
 358                 JCTree getTarget(JCTree tree) {
 359                     return ((JCBreak)tree).target;
 360                 }
 361             },
 362             CONTINUE(JCTree.Tag.CONTINUE) {
 363                 @Override
 364                 JCTree getTarget(JCTree tree) {
 365                     return ((JCContinue)tree).target;
 366                 }

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

2198             uninitsWhenFalse = new Bits(true);
2199         }
2200 
2201         private boolean isConstructor;
2202 
2203         @Override
2204         protected void markDead() {
2205             inits.inclRange(returnadr, nextadr);
2206             uninits.inclRange(returnadr, nextadr);
2207         }
2208 
2209         /*-------------- Processing variables ----------------------*/
2210 
2211         /** Do we need to track init/uninit state of this symbol?
2212          *  I.e. is symbol either a local or a blank final variable?
2213          */
2214         protected boolean trackable(VarSymbol sym) {
2215             return
2216                 sym.pos >= startPos &&
2217                 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
2218                 isFinalOrStrictUninitializedField(sym)));
2219         }
2220 
2221         boolean isFinalOrStrictUninitializedField(VarSymbol sym) {
2222             return sym.owner.kind == TYP &&
2223                    (((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL ||
2224                      (sym.flags() & (STRICT | HASINIT | PARAMETER)) == STRICT) &&
2225                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
2226         }
2227 
2228         /** Initialize new trackable variable by setting its address field
2229          *  to the next available sequence number and entering it under that
2230          *  index into the vars array.
2231          */
2232         void newVar(JCVariableDecl varDecl) {
2233             VarSymbol sym = varDecl.sym;
2234             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
2235             if ((sym.flags() & FINAL) == 0) {
2236                 sym.flags_field |= EFFECTIVELY_FINAL;
2237             }
2238             sym.adr = nextadr;
2239             vardecls[nextadr] = varDecl;
2240             inits.excl(nextadr);
2241             uninits.incl(nextadr);
2242             nextadr++;
2243         }
2244 

2276                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
2277             }
2278         }
2279         //where
2280             void uninit(VarSymbol sym) {
2281                 if (!inits.isMember(sym.adr)) {
2282                     // reachable assignment
2283                     uninits.excl(sym.adr);
2284                     uninitsTry.excl(sym.adr);
2285                 } else {
2286                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
2287                     uninits.excl(sym.adr);
2288                 }
2289             }
2290 
2291         /** If tree is either a simple name or of the form this.name or
2292          *  C.this.name, and tree represents a trackable variable,
2293          *  record an initialization of the variable.
2294          */
2295         void letInit(JCTree tree) {
2296             letInit(tree, (JCAssign) null);
2297         }
2298 
2299         void letInit(JCTree tree, JCAssign assign) {
2300             tree = TreeInfo.skipParens(tree);
2301             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
2302                 Symbol sym = TreeInfo.symbol(tree);
2303                 if (sym.kind == VAR) {
2304                     letInit(tree.pos(), (VarSymbol)sym);
2305                     if (isConstructor && sym.isStrict()) {
2306                         /* we are initializing a strict field inside of a constructor, we now need to find which fields
2307                          * haven't been initialized yet
2308                          */
2309                         unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, assign != null ? assign : tree, findUninitStrictFields());
2310                     }
2311                 }
2312             }
2313         }
2314 
2315         /** Check that trackable variable is initialized.
2316          */
2317         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
2318             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
2319         }
2320 
2321         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
2322             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
2323                 trackable(sym) &&
2324                 !inits.isMember(sym.adr) &&
2325                 (sym.flags_field & CLASH) == 0) {
2326                 log.error(pos, errkey);
2327                 inits.incl(sym.adr);
2328             }
2329         }
2330 
2331         /** Utility method to reset several Bits instances.
2332          */
2333         private void resetBits(Bits... bits) {
2334             for (Bits b : bits) {
2335                 b.reset();
2336             }
2337         }
2338 
2339         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
2340          */
2341         void split(boolean setToNull) {
2342             initsWhenFalse.assign(inits);
2343             uninitsWhenFalse.assign(uninits);
2344             initsWhenTrue.assign(inits);
2345             uninitsWhenTrue.assign(uninits);
2346             if (setToNull) {

2522                 Assert.check(pendingExits.isEmpty());
2523                 boolean isConstructorPrev = isConstructor;
2524                 try {
2525                     isConstructor = TreeInfo.isConstructor(tree);
2526 
2527                     // We only track field initialization inside constructors
2528                     if (!isConstructor) {
2529                         firstadr = nextadr;
2530                     }
2531 
2532                     // Mark all method parameters as DA
2533                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2534                         JCVariableDecl def = l.head;
2535                         scan(def);
2536                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2537                         /*  If we are executing the code from Gen, then there can be
2538                          *  synthetic or mandated variables, ignore them.
2539                          */
2540                         initParam(def);
2541                     }
2542                     if (isConstructor) {
2543                         Set<VarSymbol> unsetFields = findUninitStrictFields();
2544                         if (unsetFields != null && !unsetFields.isEmpty()) {
2545                             unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
2546                         }
2547                     }
2548 
2549                     // else we are in an instance initializer block;
2550                     // leave caught unchanged.
2551                     scan(tree.body);
2552 
2553                     boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2554                             (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2555                     if (isConstructor) {
2556                         boolean isSynthesized = (tree.sym.flags() &
2557                                                  GENERATEDCONSTR) != 0;
2558                         for (int i = firstadr; i < nextadr; i++) {
2559                             JCVariableDecl vardecl = vardecls[i];
2560                             VarSymbol var = vardecl.sym;
2561                             if (var.owner == classDef.sym && !var.isStatic()) {
2562                                 // choose the diagnostic position based on whether
2563                                 // the ctor is default(synthesized) or not
2564                                 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2565                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2566                                             var, Errors.VarNotInitializedInDefaultConstructor(var));
2567                                 } else if (isCompactOrGeneratedRecordConstructor) {
2568                                     boolean isInstanceRecordField = var.enclClass().isRecord() &&

2584                                 } else {
2585                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2586                                 }
2587                             }
2588                         }
2589                     }
2590                     clearPendingExits(true);
2591                 } finally {
2592                     inits.assign(initsPrev);
2593                     uninits.assign(uninitsPrev);
2594                     nextadr = nextadrPrev;
2595                     firstadr = firstadrPrev;
2596                     returnadr = returnadrPrev;
2597                     isConstructor = isConstructorPrev;
2598                 }
2599             } finally {
2600                 lint = lintPrev;
2601             }
2602         }
2603 
2604         Set<VarSymbol> findUninitStrictFields() {
2605             Set<VarSymbol> unsetFields = new LinkedHashSet<>();
2606             for (int i = uninits.nextBit(0); i >= 0; i = uninits.nextBit(i + 1)) {
2607                 JCVariableDecl variableDecl = vardecls[i];
2608                 if (variableDecl.sym.isStrict()) {
2609                     unsetFields.add(variableDecl.sym);
2610                 }
2611             }
2612             return unsetFields;
2613         }
2614 
2615         private void clearPendingExits(boolean inMethod) {
2616             List<PendingExit> exits = pendingExits.toList();
2617             pendingExits = new ListBuffer<>();
2618             while (exits.nonEmpty()) {
2619                 PendingExit exit = exits.head;
2620                 exits = exits.tail;
2621                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2622                                  log.hasErrorOn(exit.tree.pos()),
2623                              exit.tree);
2624                 if (inMethod && isConstructor) {
2625                     Assert.check(exit instanceof AssignPendingExit);
2626                     inits.assign(((AssignPendingExit) exit).exit_inits);
2627                     for (int i = firstadr; i < nextadr; i++) {
2628                         checkInit(exit.tree.pos(), vardecls[i].sym);
2629                     }
2630                 }
2631             }
2632         }
2633         protected void initParam(JCVariableDecl def) {
2634             inits.incl(def.sym.adr);

3058             }
3059         }
3060 
3061         @Override
3062         public void visitContinue(JCContinue tree) {
3063             recordExit(new AssignPendingExit(tree, inits, uninits));
3064         }
3065 
3066         @Override
3067         public void visitReturn(JCReturn tree) {
3068             scanExpr(tree.expr);
3069             recordExit(new AssignPendingExit(tree, inits, uninits));
3070         }
3071 
3072         public void visitThrow(JCThrow tree) {
3073             scanExpr(tree.expr);
3074             markDead();
3075         }
3076 
3077         public void visitApply(JCMethodInvocation tree) {
3078             Name name = TreeInfo.name(tree.meth);
3079             // let's process early initializers
3080             if (name == names._super) {
3081                 forEachInitializer(classDef, false, true, def -> {
3082                     scan(def);
3083                     clearPendingExits(false);
3084                 });
3085             }
3086             scanExpr(tree.meth);
3087             scanExprs(tree.args);
3088 
3089             // Handle superclass constructor invocations
3090             if (isConstructor) {
3091 
3092                 // If super(): at this point all initialization blocks will execute
3093 
3094                 if (name == names._super) {
3095                     // strict fields should have been initialized at this point
3096                     for (int i = firstadr; i < nextadr; i++) {
3097                         JCVariableDecl vardecl = vardecls[i];
3098                         VarSymbol var = vardecl.sym;
3099                         boolean isInstanceRecordField = var.enclClass().isRecord() &&
3100                                 (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
3101                                 var.owner.kind == TYP;
3102                         if (var.owner == classDef.sym && !var.isStatic() && var.isStrict() && !isInstanceRecordField) {
3103                             checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
3104                         }
3105                     }
3106                     forEachInitializer(classDef, false, def -> {
3107                         scan(def);
3108                         clearPendingExits(false);
3109                     });
3110                 }
3111 
3112                 // If this(): at this point all final uninitialized fields will get initialized
3113                 else if (name == names._this) {
3114                     for (int address = firstadr; address < nextadr; address++) {
3115                         VarSymbol sym = vardecls[address].sym;
3116                         if (isFinalOrStrictUninitializedField(sym) && !sym.isStatic())
3117                             letInit(tree.pos(), sym);
3118                     }
3119                 }
3120             }
3121         }
3122 
3123         public void visitNewClass(JCNewClass tree) {
3124             scanExpr(tree.encl);
3125             scanExprs(tree.args);
3126             scan(tree.def);
3127         }
3128 
3129         @Override
3130         public void visitLambda(JCLambda tree) {
3131             final Bits prevUninits = new Bits(uninits);
3132             final Bits prevUninitsTry = new Bits(uninitsTry);
3133             final Bits prevInits = new Bits(inits);
3134             int returnadrPrev = returnadr;
3135             int nextadrPrev = nextadr;
3136             ListBuffer<PendingExit> prevPending = pendingExits;

3170         }
3171 
3172         public void visitAssert(JCAssert tree) {
3173             final Bits initsExit = new Bits(inits);
3174             final Bits uninitsExit = new Bits(uninits);
3175             scanCond(tree.cond);
3176             uninitsExit.andSet(uninitsWhenTrue);
3177             if (tree.detail != null) {
3178                 inits.assign(initsWhenFalse);
3179                 uninits.assign(uninitsWhenFalse);
3180                 scanExpr(tree.detail);
3181             }
3182             inits.assign(initsExit);
3183             uninits.assign(uninitsExit);
3184         }
3185 
3186         public void visitAssign(JCAssign tree) {
3187             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
3188                 scanExpr(tree.lhs);
3189             scanExpr(tree.rhs);
3190             letInit(tree.lhs, tree);
3191         }
3192 
3193         // check fields accessed through this.<field> are definitely
3194         // assigned before reading their value
3195         public void visitSelect(JCFieldAccess tree) {
3196             super.visitSelect(tree);
3197             if (TreeInfo.isThisQualifier(tree.selected) &&
3198                 tree.sym.kind == VAR) {
3199                 checkInit(tree.pos(), (VarSymbol)tree.sym);
3200             }
3201         }
3202 
3203         public void visitAssignop(JCAssignOp tree) {
3204             scanExpr(tree.lhs);
3205             scanExpr(tree.rhs);
3206             letInit(tree.lhs);
3207         }
3208 
3209         public void visitUnary(JCUnary tree) {
3210             switch (tree.getTag()) {
< prev index next >