< 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 

2160             }
2161 
2162             @Override
2163             public void resolveJump() {
2164                 inits.andSet(exit_inits);
2165                 uninits.andSet(exit_uninits);
2166             }
2167         }
2168 
2169         public AssignAnalyzer() {
2170             this.inits = new Bits();
2171             uninits = new Bits();
2172             uninitsTry = new Bits();
2173             initsWhenTrue = new Bits(true);
2174             initsWhenFalse = new Bits(true);
2175             uninitsWhenTrue = new Bits(true);
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) {

2471                 return;
2472             }
2473 
2474             /*  MemberEnter can generate synthetic methods ignore them
2475              */
2476             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2477                 return;
2478             }
2479 
2480             Lint lintPrev = lint;
2481             lint = lint.augment(tree.sym);
2482             try {
2483                 final Bits initsPrev = new Bits(inits);
2484                 final Bits uninitsPrev = new Bits(uninits);
2485                 int nextadrPrev = nextadr;
2486                 int firstadrPrev = firstadr;
2487                 int returnadrPrev = returnadr;
2488 
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() &&
2529                                             (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2530                                             var.owner.kind == TYP;
2531                                     if (isInstanceRecordField) {
2532                                         boolean notInitialized = !inits.isMember(var.adr);
2533                                         if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2534                                         /*  this way we indicate Lower that it should generate an initialization for this field

2538                                         } else {
2539                                             checkInit(TreeInfo.diagEndPos(tree.body), var);
2540                                         }
2541                                     } else {
2542                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2543                                     }
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     private final boolean allowValueClasses;
 222 
 223     public static Flow instance(Context context) {
 224         Flow instance = context.get(flowKey);
 225         if (instance == null)
 226             instance = new Flow(context);
 227         return instance;
 228     }
 229 
 230     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
 231         new AliveAnalyzer().analyzeTree(env, make);
 232         new AssignAnalyzer().analyzeTree(env, make);
 233         new FlowAnalyzer().analyzeTree(env, make);
 234         new CaptureAnalyzer().analyzeTree(env, make);
 235     }
 236 
 237     public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
 238         Log.DiagnosticHandler diagHandler = null;
 239         //we need to disable diagnostics temporarily; the problem is that if
 240         //a lambda expression contains e.g. an unreachable statement, an error
 241         //message will be reported and will cause compilation to skip the flow analysis

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

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

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

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

2510                 return;
2511             }
2512 
2513             /*  MemberEnter can generate synthetic methods ignore them
2514              */
2515             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2516                 return;
2517             }
2518 
2519             Lint lintPrev = lint;
2520             lint = lint.augment(tree.sym);
2521             try {
2522                 final Bits initsPrev = new Bits(inits);
2523                 final Bits uninitsPrev = new Bits(uninits);
2524                 int nextadrPrev = nextadr;
2525                 int firstadrPrev = firstadr;
2526                 int returnadrPrev = returnadr;
2527 
2528                 Assert.check(pendingExits.isEmpty());
2529                 boolean isConstructorPrev = isConstructor;
2530                 boolean isCompactOrGeneratedRecordConstructorPrev = isCompactOrGeneratedRecordConstructor;
2531                 try {
2532                     isConstructor = TreeInfo.isConstructor(tree);
2533                     isCompactOrGeneratedRecordConstructor = isConstructor && ((tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2534                             (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD));
2535 
2536                     // We only track field initialization inside constructors
2537                     if (!isConstructor) {
2538                         firstadr = nextadr;
2539                     }
2540 
2541                     // Mark all method parameters as DA
2542                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2543                         JCVariableDecl def = l.head;
2544                         scan(def);
2545                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2546                         /*  If we are executing the code from Gen, then there can be
2547                          *  synthetic or mandated variables, ignore them.
2548                          */
2549                         initParam(def);
2550                     }
2551                     if (isConstructor) {
2552                         Set<VarSymbol> unsetFields = findUninitStrictFields();
2553                         if (unsetFields != null && !unsetFields.isEmpty()) {
2554                             unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
2555                         }
2556                     }
2557 
2558                     // else we are in an instance initializer block;
2559                     // leave caught unchanged.
2560                     scan(tree.body);
2561 


2562                     if (isConstructor) {
2563                         boolean isSynthesized = (tree.sym.flags() &
2564                                                  GENERATEDCONSTR) != 0;
2565                         for (int i = firstadr; i < nextadr; i++) {
2566                             JCVariableDecl vardecl = vardecls[i];
2567                             VarSymbol var = vardecl.sym;
2568                             if (var.owner == classDef.sym && !var.isStatic()) {
2569                                 // choose the diagnostic position based on whether
2570                                 // the ctor is default(synthesized) or not
2571                                 if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2572                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2573                                             var, Errors.VarNotInitializedInDefaultConstructor(var));
2574                                 } else if (isCompactOrGeneratedRecordConstructor) {
2575                                     boolean isInstanceRecordField = var.enclClass().isRecord() &&
2576                                             (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2577                                             var.owner.kind == TYP;
2578                                     if (isInstanceRecordField) {
2579                                         boolean notInitialized = !inits.isMember(var.adr);
2580                                         if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2581                                         /*  this way we indicate Lower that it should generate an initialization for this field

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

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

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