< prev index next >

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

Print this page

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


  31 import java.util.function.Consumer;
  32 
  33 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
  34 import com.sun.tools.javac.code.*;
  35 import com.sun.tools.javac.code.Scope.WriteableScope;
  36 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  37 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
  38 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  39 import com.sun.tools.javac.tree.*;
  40 import com.sun.tools.javac.util.*;
  41 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  42 import com.sun.tools.javac.util.JCDiagnostic.Error;
  43 import com.sun.tools.javac.util.JCDiagnostic.Warning;
  44 
  45 import com.sun.tools.javac.code.Symbol.*;
  46 import com.sun.tools.javac.tree.JCTree.*;
  47 
  48 import static com.sun.tools.javac.code.Flags.*;
  49 import static com.sun.tools.javac.code.Flags.BLOCK;
  50 import static com.sun.tools.javac.code.Kinds.Kind.*;

 186  *  support for assigning to a final field via this.x.
 187  *
 188  *  <p><b>This is NOT part of any supported API.
 189  *  If you write code that depends on this, you do so at your own risk.
 190  *  This code and its internal interfaces are subject to change or
 191  *  deletion without notice.</b>
 192  */
 193 public class Flow {
 194     protected static final Context.Key<Flow> flowKey = new Context.Key<>();
 195 
 196     private final Names names;
 197     private final Log log;
 198     private final Symtab syms;
 199     private final Types types;
 200     private final Check chk;
 201     private       TreeMaker make;
 202     private final Resolve rs;
 203     private final JCDiagnostic.Factory diags;
 204     private final ExhaustivenessComputer exhaustiveness;
 205     private Env<AttrContext> attrEnv;


 206 
 207     public static Flow instance(Context context) {
 208         Flow instance = context.get(flowKey);
 209         if (instance == null)
 210             instance = new Flow(context);
 211         return instance;
 212     }
 213 
 214     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
 215         new AliveAnalyzer().analyzeTree(env, make);
 216         new AssignAnalyzer().analyzeTree(env, make);
 217         new FlowAnalyzer().analyzeTree(env, make);
 218         new CaptureAnalyzer().analyzeTree(env, make);
 219     }
 220 
 221     public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
 222         Log.DiagnosticHandler diagHandler = null;
 223         //we need to disable diagnostics temporarily; the problem is that if
 224         //a lambda expression contains e.g. an unreachable statement, an error
 225         //message will be reported and will cause compilation to skip the flow analysis

 309         FlowKind(String errKey, boolean isFinal) {
 310             this.errKey = errKey;
 311             this.isFinal = isFinal;
 312         }
 313 
 314         boolean isFinal() {
 315             return isFinal;
 316         }
 317     }
 318 
 319     @SuppressWarnings("this-escape")
 320     protected Flow(Context context) {
 321         context.put(flowKey, this);
 322         names = Names.instance(context);
 323         log = Log.instance(context);
 324         syms = Symtab.instance(context);
 325         types = Types.instance(context);
 326         chk = Check.instance(context);
 327         rs = Resolve.instance(context);
 328         diags = JCDiagnostic.Factory.instance(context);





 329         exhaustiveness = ExhaustivenessComputer.instance(context);
 330     }
 331 
 332     /**
 333      * Base visitor class for all visitors implementing dataflow analysis logic.
 334      * This class define the shared logic for handling jumps (break/continue statements).
 335      */
 336     abstract static class BaseAnalyzer extends TreeScanner {
 337 
 338         enum JumpKind {
 339             BREAK(JCTree.Tag.BREAK) {
 340                 @Override
 341                 JCTree getTarget(JCTree tree) {
 342                     return ((JCBreak)tree).target;
 343                 }
 344             },
 345             CONTINUE(JCTree.Tag.CONTINUE) {
 346                 @Override
 347                 JCTree getTarget(JCTree tree) {
 348                     return ((JCContinue)tree).target;

 446             }
 447         }
 448 
 449         public void visitPackageDef(JCPackageDecl tree) {
 450             // Do nothing for PackageDecl
 451         }
 452 
 453         protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
 454             if (swtch.hasTag(SWITCH_EXPRESSION)) {
 455                 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
 456                                                                 .setType(swtch.type));
 457                 brk.target = swtch;
 458                 scan(brk);
 459             } else {
 460                 JCBreak brk = make.at(Position.NOPOS).Break(null);
 461                 brk.target = swtch;
 462                 scan(brk);
 463             }
 464         }
 465 
 466         // Do something with all static or non-static field initializers and initialization blocks.
 467         protected void forEachInitializer(JCClassDecl classDef, boolean isStatic, Consumer<? super JCTree> handler) {










 468             if (classDef == initScanClass)          // avoid infinite loops
 469                 return;
 470             JCClassDecl initScanClassPrev = initScanClass;
 471             initScanClass = classDef;
 472             try {
 473                 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
 474                     JCTree def = defs.head;
 475 
 476                     // Don't recurse into nested classes
 477                     if (def.hasTag(CLASSDEF))
 478                         continue;
 479 
 480                     /* we need to check for flags in the symbol too as there could be cases for which implicit flags are
 481                      * represented in the symbol but not in the tree modifiers as they were not originally in the source
 482                      * code
 483                      */
 484                     boolean isDefStatic = ((TreeInfo.flags(def) | (TreeInfo.symbolFor(def) == null ? 0 : TreeInfo.symbolFor(def).flags_field)) & STATIC) != 0;
 485                     if (!def.hasTag(METHODDEF) && (isDefStatic == isStatic))
 486                         handler.accept(def);










 487                 }
 488             } finally {
 489                 initScanClass = initScanClassPrev;
 490             }
 491         }
 492     }
 493 
 494     /**
 495      * This pass implements the first step of the dataflow analysis, namely
 496      * the liveness analysis check. This checks that every statement is reachable.
 497      * The output of this analysis pass are used by other analyzers. This analyzer
 498      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
 499      */
 500     class AliveAnalyzer extends BaseAnalyzer {
 501 
 502         /** A flag that indicates whether the last statement could
 503          *  complete normally.
 504          */
 505         private Liveness alive;
 506 

1676             }
1677 
1678             @Override
1679             public void resolveJump() {
1680                 inits.andSet(exit_inits);
1681                 uninits.andSet(exit_uninits);
1682             }
1683         }
1684 
1685         public AssignAnalyzer() {
1686             this.inits = new Bits();
1687             uninits = new Bits();
1688             uninitsTry = new Bits();
1689             initsWhenTrue = new Bits(true);
1690             initsWhenFalse = new Bits(true);
1691             uninitsWhenTrue = new Bits(true);
1692             uninitsWhenFalse = new Bits(true);
1693         }
1694 
1695         private boolean isConstructor;

1696 
1697         @Override
1698         protected void markDead() {
1699             inits.inclRange(returnadr, nextadr);
1700             uninits.inclRange(returnadr, nextadr);
1701         }
1702 
1703         /*-------------- Processing variables ----------------------*/
1704 
1705         /** Do we need to track init/uninit state of this symbol?
1706          *  I.e. is symbol either a local or a blank final variable?
1707          */
1708         protected boolean trackable(VarSymbol sym) {
1709             return
1710                 sym.pos >= startPos &&
1711                 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
1712                 isFinalUninitializedField(sym)));
1713         }
1714 
1715         boolean isFinalUninitializedField(VarSymbol sym) {
1716             return sym.owner.kind == TYP &&
1717                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&

1718                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
1719         }
1720 
1721         /** Initialize new trackable variable by setting its address field
1722          *  to the next available sequence number and entering it under that
1723          *  index into the vars array.
1724          */
1725         void newVar(JCVariableDecl varDecl) {
1726             VarSymbol sym = varDecl.sym;
1727             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1728             if ((sym.flags() & FINAL) == 0) {
1729                 sym.flags_field |= EFFECTIVELY_FINAL;
1730             }
1731             sym.adr = nextadr;
1732             vardecls[nextadr] = varDecl;
1733             inits.excl(nextadr);
1734             uninits.incl(nextadr);
1735             nextadr++;
1736         }
1737 

1769                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1770             }
1771         }
1772         //where
1773             void uninit(VarSymbol sym) {
1774                 if (!inits.isMember(sym.adr)) {
1775                     // reachable assignment
1776                     uninits.excl(sym.adr);
1777                     uninitsTry.excl(sym.adr);
1778                 } else {
1779                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
1780                     uninits.excl(sym.adr);
1781                 }
1782             }
1783 
1784         /** If tree is either a simple name or of the form this.name or
1785          *  C.this.name, and tree represents a trackable variable,
1786          *  record an initialization of the variable.
1787          */
1788         void letInit(JCTree tree) {




1789             tree = TreeInfo.skipParens(tree);
1790             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1791                 Symbol sym = TreeInfo.symbol(tree);
1792                 if (sym.kind == VAR) {
1793                     letInit(tree.pos(), (VarSymbol)sym);






1794                 }
1795             }
1796         }
1797 
1798         /** Check that trackable variable is initialized.
1799          */
1800         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1801             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1802         }
1803 
1804         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1805             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1806                 trackable(sym) &&
1807                 !inits.isMember(sym.adr) &&
1808                 (sym.flags_field & CLASH) == 0) {
1809                     log.error(pos, errkey);
1810                 inits.incl(sym.adr);
1811             }
1812         }
1813 
1814         /** Utility method to reset several Bits instances.
1815          */
1816         private void resetBits(Bits... bits) {
1817             for (Bits b : bits) {
1818                 b.reset();
1819             }
1820         }
1821 
1822         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1823          */
1824         void split(boolean setToNull) {
1825             initsWhenFalse.assign(inits);
1826             uninitsWhenFalse.assign(uninits);
1827             initsWhenTrue.assign(inits);
1828             uninitsWhenTrue.assign(uninits);
1829             if (setToNull) {

1978 
1979         public void visitMethodDef(JCMethodDecl tree) {
1980             if (tree.body == null) {
1981                 return;
1982             }
1983 
1984             /*  MemberEnter can generate synthetic methods ignore them
1985              */
1986             if ((tree.sym.flags() & SYNTHETIC) != 0) {
1987                 return;
1988             }
1989 
1990             final Bits initsPrev = new Bits(inits);
1991             final Bits uninitsPrev = new Bits(uninits);
1992             int nextadrPrev = nextadr;
1993             int firstadrPrev = firstadr;
1994             int returnadrPrev = returnadr;
1995 
1996             Assert.check(pendingExits.isEmpty());
1997             boolean isConstructorPrev = isConstructor;

1998             try {
1999                 isConstructor = TreeInfo.isConstructor(tree);


2000 
2001                 // We only track field initialization inside constructors
2002                 if (!isConstructor) {
2003                     firstadr = nextadr;
2004                 }
2005 
2006                 // Mark all method parameters as DA
2007                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2008                     JCVariableDecl def = l.head;
2009                     scan(def);
2010                     Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2011                     /*  If we are executing the code from Gen, then there can be
2012                      *  synthetic or mandated variables, ignore them.
2013                      */
2014                     initParam(def);
2015                 }







2016                 // else we are in an instance initializer block;
2017                 // leave caught unchanged.
2018                 scan(tree.body);
2019 
2020                 boolean isCompactOrGeneratedRecordConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2021                         (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD);
2022                 if (isConstructor) {
2023                     boolean isSynthesized = (tree.sym.flags() &
2024                                              GENERATEDCONSTR) != 0;
2025                     for (int i = firstadr; i < nextadr; i++) {
2026                         JCVariableDecl vardecl = vardecls[i];
2027                         VarSymbol var = vardecl.sym;
2028                         if (var.owner == classDef.sym && !var.isStatic()) {
2029                             // choose the diagnostic position based on whether
2030                             // the ctor is default(synthesized) or not
2031                             if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2032                                 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2033                                         var, Errors.VarNotInitializedInDefaultConstructor(var));
2034                             } else if (isCompactOrGeneratedRecordConstructor) {
2035                                 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2036                                         (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2037                                         var.owner.kind == TYP;
2038                                 if (isInstanceRecordField) {
2039                                     boolean notInitialized = !inits.isMember(var.adr);
2040                                     if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2041                                     /*  this way we indicate Lower that it should generate an initialization for this field

2045                                     } else {
2046                                         checkInit(TreeInfo.diagEndPos(tree.body), var);
2047                                     }
2048                                 } else {
2049                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2050                                 }
2051                             } else {
2052                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
2053                             }
2054                         }
2055                     }
2056                 }
2057                 clearPendingExits(true);
2058             } finally {
2059                 inits.assign(initsPrev);
2060                 uninits.assign(uninitsPrev);
2061                 nextadr = nextadrPrev;
2062                 firstadr = firstadrPrev;
2063                 returnadr = returnadrPrev;
2064                 isConstructor = isConstructorPrev;











2065             }

2066         }
2067 
2068         private void clearPendingExits(boolean inMethod) {
2069             List<PendingExit> exits = pendingExits.toList();
2070             pendingExits = new ListBuffer<>();
2071             while (exits.nonEmpty()) {
2072                 PendingExit exit = exits.head;
2073                 exits = exits.tail;
2074                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2075                                  log.hasErrorOn(exit.tree.pos()),
2076                              exit.tree);
2077                 if (inMethod && isConstructor) {
2078                     Assert.check(exit instanceof AssignPendingExit);
2079                     inits.assign(((AssignPendingExit) exit).exit_inits);
2080                     for (int i = firstadr; i < nextadr; i++) {
2081                         checkInit(exit.tree.pos(), vardecls[i].sym);
2082                     }
2083                 }
2084             }
2085         }

2504             }
2505         }
2506 
2507         @Override
2508         public void visitContinue(JCContinue tree) {
2509             recordExit(new AssignPendingExit(tree, inits, uninits));
2510         }
2511 
2512         @Override
2513         public void visitReturn(JCReturn tree) {
2514             scanExpr(tree.expr);
2515             recordExit(new AssignPendingExit(tree, inits, uninits));
2516         }
2517 
2518         public void visitThrow(JCThrow tree) {
2519             scanExpr(tree.expr);
2520             markDead();
2521         }
2522 
2523         public void visitApply(JCMethodInvocation tree) {








2524             scanExpr(tree.meth);
2525             scanExprs(tree.args);
2526 
2527             // Handle superclass constructor invocations
2528             if (isConstructor) {
2529 
2530                 // If super(): at this point all initialization blocks will execute
2531                 Name name = TreeInfo.name(tree.meth);
2532                 if (name == names._super) {








2533                     forEachInitializer(classDef, false, def -> {
2534                         scan(def);
2535                         clearPendingExits(false);
2536                     });
2537                 }
2538 
2539                 // If this(): at this point all final uninitialized fields will get initialized
2540                 else if (name == names._this) {
2541                     for (int address = firstadr; address < nextadr; address++) {
2542                         VarSymbol sym = vardecls[address].sym;
2543                         if (isFinalUninitializedField(sym) && !sym.isStatic())
2544                             letInit(tree.pos(), sym);
2545                     }
2546                 }
2547             }
2548         }
2549 
2550         public void visitNewClass(JCNewClass tree) {
2551             scanExpr(tree.encl);
2552             scanExprs(tree.args);
2553             scan(tree.def);
2554         }
2555 
2556         @Override
2557         public void visitLambda(JCLambda tree) {
2558             final Bits prevUninits = new Bits(uninits);
2559             final Bits prevUninitsTry = new Bits(uninitsTry);
2560             final Bits prevInits = new Bits(inits);
2561             int returnadrPrev = returnadr;
2562             int nextadrPrev = nextadr;
2563             ListBuffer<PendingExit> prevPending = pendingExits;

2597         }
2598 
2599         public void visitAssert(JCAssert tree) {
2600             final Bits initsExit = new Bits(inits);
2601             final Bits uninitsExit = new Bits(uninits);
2602             scanCond(tree.cond);
2603             uninitsExit.andSet(uninitsWhenTrue);
2604             if (tree.detail != null) {
2605                 inits.assign(initsWhenFalse);
2606                 uninits.assign(uninitsWhenFalse);
2607                 scanExpr(tree.detail);
2608             }
2609             inits.assign(initsExit);
2610             uninits.assign(uninitsExit);
2611         }
2612 
2613         public void visitAssign(JCAssign tree) {
2614             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2615                 scanExpr(tree.lhs);
2616             scanExpr(tree.rhs);
2617             letInit(tree.lhs);
2618         }
2619 
2620         // check fields accessed through this.<field> are definitely
2621         // assigned before reading their value
2622         public void visitSelect(JCFieldAccess tree) {
2623             super.visitSelect(tree);
2624             if (TreeInfo.isThisQualifier(tree.selected) &&
2625                 tree.sym.kind == VAR) {
2626                 checkInit(tree.pos(), (VarSymbol)tree.sym);
2627             }
2628         }
2629 
2630         public void visitAssignop(JCAssignOp tree) {
2631             scanExpr(tree.lhs);
2632             scanExpr(tree.rhs);
2633             letInit(tree.lhs);
2634         }
2635 
2636         public void visitUnary(JCUnary tree) {
2637             switch (tree.getTag()) {

  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.HashMap;
  31 import java.util.LinkedHashSet;
  32 import java.util.Set;
  33 import java.util.function.Consumer;
  34 
  35 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
  36 import com.sun.tools.javac.code.*;
  37 import com.sun.tools.javac.code.Scope.WriteableScope;
  38 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  39 import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
  40 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  41 import com.sun.tools.javac.tree.*;
  42 import com.sun.tools.javac.util.*;
  43 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  44 import com.sun.tools.javac.util.JCDiagnostic.Error;
  45 import com.sun.tools.javac.util.JCDiagnostic.Warning;
  46 
  47 import com.sun.tools.javac.code.Symbol.*;
  48 import com.sun.tools.javac.tree.JCTree.*;
  49 
  50 import static com.sun.tools.javac.code.Flags.*;
  51 import static com.sun.tools.javac.code.Flags.BLOCK;
  52 import static com.sun.tools.javac.code.Kinds.Kind.*;

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

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

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

1705             }
1706 
1707             @Override
1708             public void resolveJump() {
1709                 inits.andSet(exit_inits);
1710                 uninits.andSet(exit_uninits);
1711             }
1712         }
1713 
1714         public AssignAnalyzer() {
1715             this.inits = new Bits();
1716             uninits = new Bits();
1717             uninitsTry = new Bits();
1718             initsWhenTrue = new Bits(true);
1719             initsWhenFalse = new Bits(true);
1720             uninitsWhenTrue = new Bits(true);
1721             uninitsWhenFalse = new Bits(true);
1722         }
1723 
1724         private boolean isConstructor;
1725         private boolean isCompactOrGeneratedRecordConstructor;
1726 
1727         @Override
1728         protected void markDead() {
1729             inits.inclRange(returnadr, nextadr);
1730             uninits.inclRange(returnadr, nextadr);
1731         }
1732 
1733         /*-------------- Processing variables ----------------------*/
1734 
1735         /** Do we need to track init/uninit state of this symbol?
1736          *  I.e. is symbol either a local or a blank final variable?
1737          */
1738         protected boolean trackable(VarSymbol sym) {
1739             return
1740                 sym.pos >= startPos &&
1741                 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
1742                 isFinalOrStrictUninitializedField(sym)));
1743         }
1744 
1745         boolean isFinalOrStrictUninitializedField(VarSymbol sym) {
1746             return sym.owner.kind == TYP &&
1747                    (((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL ||
1748                      (sym.flags() & (STRICT | HASINIT | PARAMETER)) == STRICT) &&
1749                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
1750         }
1751 
1752         /** Initialize new trackable variable by setting its address field
1753          *  to the next available sequence number and entering it under that
1754          *  index into the vars array.
1755          */
1756         void newVar(JCVariableDecl varDecl) {
1757             VarSymbol sym = varDecl.sym;
1758             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1759             if ((sym.flags() & FINAL) == 0) {
1760                 sym.flags_field |= EFFECTIVELY_FINAL;
1761             }
1762             sym.adr = nextadr;
1763             vardecls[nextadr] = varDecl;
1764             inits.excl(nextadr);
1765             uninits.incl(nextadr);
1766             nextadr++;
1767         }
1768 

1800                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1801             }
1802         }
1803         //where
1804             void uninit(VarSymbol sym) {
1805                 if (!inits.isMember(sym.adr)) {
1806                     // reachable assignment
1807                     uninits.excl(sym.adr);
1808                     uninitsTry.excl(sym.adr);
1809                 } else {
1810                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
1811                     uninits.excl(sym.adr);
1812                 }
1813             }
1814 
1815         /** If tree is either a simple name or of the form this.name or
1816          *  C.this.name, and tree represents a trackable variable,
1817          *  record an initialization of the variable.
1818          */
1819         void letInit(JCTree tree) {
1820             letInit(tree, (JCAssign) null);
1821         }
1822 
1823         void letInit(JCTree tree, JCAssign assign) {
1824             tree = TreeInfo.skipParens(tree);
1825             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1826                 Symbol sym = TreeInfo.symbol(tree);
1827                 if (sym.kind == VAR) {
1828                     letInit(tree.pos(), (VarSymbol)sym);
1829                     if (isConstructor && sym.isStrict()) {
1830                         /* we are initializing a strict field inside of a constructor, we now need to find which fields
1831                          * haven't been initialized yet
1832                          */
1833                         unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, assign != null ? assign : tree, findUninitStrictFields());
1834                     }
1835                 }
1836             }
1837         }
1838 
1839         /** Check that trackable variable is initialized.
1840          */
1841         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1842             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1843         }
1844 
1845         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1846             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1847                 trackable(sym) &&
1848                 !inits.isMember(sym.adr) &&
1849                 (sym.flags_field & CLASH) == 0) {
1850                 log.error(pos, errkey);
1851                 inits.incl(sym.adr);
1852             }
1853         }
1854 
1855         /** Utility method to reset several Bits instances.
1856          */
1857         private void resetBits(Bits... bits) {
1858             for (Bits b : bits) {
1859                 b.reset();
1860             }
1861         }
1862 
1863         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1864          */
1865         void split(boolean setToNull) {
1866             initsWhenFalse.assign(inits);
1867             uninitsWhenFalse.assign(uninits);
1868             initsWhenTrue.assign(inits);
1869             uninitsWhenTrue.assign(uninits);
1870             if (setToNull) {

2019 
2020         public void visitMethodDef(JCMethodDecl tree) {
2021             if (tree.body == null) {
2022                 return;
2023             }
2024 
2025             /*  MemberEnter can generate synthetic methods ignore them
2026              */
2027             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2028                 return;
2029             }
2030 
2031             final Bits initsPrev = new Bits(inits);
2032             final Bits uninitsPrev = new Bits(uninits);
2033             int nextadrPrev = nextadr;
2034             int firstadrPrev = firstadr;
2035             int returnadrPrev = returnadr;
2036 
2037             Assert.check(pendingExits.isEmpty());
2038             boolean isConstructorPrev = isConstructor;
2039             boolean isCompactOrGeneratedRecordConstructorPrev = isCompactOrGeneratedRecordConstructor;
2040             try {
2041                 isConstructor = TreeInfo.isConstructor(tree);
2042                 isCompactOrGeneratedRecordConstructor = isConstructor && ((tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2043                          (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD));
2044 
2045                 // We only track field initialization inside constructors
2046                 if (!isConstructor) {
2047                     firstadr = nextadr;
2048                 }
2049 
2050                 // Mark all method parameters as DA
2051                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2052                     JCVariableDecl def = l.head;
2053                     scan(def);
2054                     Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2055                     /*  If we are executing the code from Gen, then there can be
2056                      *  synthetic or mandated variables, ignore them.
2057                      */
2058                     initParam(def);
2059                 }
2060                 if (isConstructor) {
2061                     Set<VarSymbol> unsetFields = findUninitStrictFields();
2062                     if (unsetFields != null && !unsetFields.isEmpty()) {
2063                         unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
2064                     }
2065                 }
2066 
2067                 // else we are in an instance initializer block;
2068                 // leave caught unchanged.
2069                 scan(tree.body);
2070 


2071                 if (isConstructor) {
2072                     boolean isSynthesized = (tree.sym.flags() &
2073                                              GENERATEDCONSTR) != 0;
2074                     for (int i = firstadr; i < nextadr; i++) {
2075                         JCVariableDecl vardecl = vardecls[i];
2076                         VarSymbol var = vardecl.sym;
2077                         if (var.owner == classDef.sym && !var.isStatic()) {
2078                             // choose the diagnostic position based on whether
2079                             // the ctor is default(synthesized) or not
2080                             if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2081                                 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2082                                         var, Errors.VarNotInitializedInDefaultConstructor(var));
2083                             } else if (isCompactOrGeneratedRecordConstructor) {
2084                                 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2085                                         (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2086                                         var.owner.kind == TYP;
2087                                 if (isInstanceRecordField) {
2088                                     boolean notInitialized = !inits.isMember(var.adr);
2089                                     if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2090                                     /*  this way we indicate Lower that it should generate an initialization for this field

2094                                     } else {
2095                                         checkInit(TreeInfo.diagEndPos(tree.body), var);
2096                                     }
2097                                 } else {
2098                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2099                                 }
2100                             } else {
2101                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
2102                             }
2103                         }
2104                     }
2105                 }
2106                 clearPendingExits(true);
2107             } finally {
2108                 inits.assign(initsPrev);
2109                 uninits.assign(uninitsPrev);
2110                 nextadr = nextadrPrev;
2111                 firstadr = firstadrPrev;
2112                 returnadr = returnadrPrev;
2113                 isConstructor = isConstructorPrev;
2114                 isCompactOrGeneratedRecordConstructor = isCompactOrGeneratedRecordConstructorPrev;
2115             }
2116         }
2117 
2118         Set<VarSymbol> findUninitStrictFields() {
2119             Set<VarSymbol> unsetFields = new LinkedHashSet<>();
2120             for (int i = uninits.nextBit(0); i >= 0; i = uninits.nextBit(i + 1)) {
2121                 JCVariableDecl variableDecl = vardecls[i];
2122                 if (variableDecl.sym.isStrict()) {
2123                     unsetFields.add(variableDecl.sym);
2124                 }
2125             }
2126             return unsetFields;
2127         }
2128 
2129         private void clearPendingExits(boolean inMethod) {
2130             List<PendingExit> exits = pendingExits.toList();
2131             pendingExits = new ListBuffer<>();
2132             while (exits.nonEmpty()) {
2133                 PendingExit exit = exits.head;
2134                 exits = exits.tail;
2135                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2136                                  log.hasErrorOn(exit.tree.pos()),
2137                              exit.tree);
2138                 if (inMethod && isConstructor) {
2139                     Assert.check(exit instanceof AssignPendingExit);
2140                     inits.assign(((AssignPendingExit) exit).exit_inits);
2141                     for (int i = firstadr; i < nextadr; i++) {
2142                         checkInit(exit.tree.pos(), vardecls[i].sym);
2143                     }
2144                 }
2145             }
2146         }

2565             }
2566         }
2567 
2568         @Override
2569         public void visitContinue(JCContinue tree) {
2570             recordExit(new AssignPendingExit(tree, inits, uninits));
2571         }
2572 
2573         @Override
2574         public void visitReturn(JCReturn tree) {
2575             scanExpr(tree.expr);
2576             recordExit(new AssignPendingExit(tree, inits, uninits));
2577         }
2578 
2579         public void visitThrow(JCThrow tree) {
2580             scanExpr(tree.expr);
2581             markDead();
2582         }
2583 
2584         public void visitApply(JCMethodInvocation tree) {
2585             Name name = TreeInfo.name(tree.meth);
2586             // let's process early initializers
2587             if (name == names._super) {
2588                 forEachInitializer(classDef, false, true, def -> {
2589                     scan(def);
2590                     clearPendingExits(false);
2591                 });
2592             }
2593             scanExpr(tree.meth);
2594             scanExprs(tree.args);
2595 
2596             // Handle superclass constructor invocations
2597             if (isConstructor) {
2598 
2599                 // If super(): at this point all initialization blocks will execute
2600 
2601                 if (name == names._super) {
2602                     // strict fields should have been initialized at this point
2603                     for (int i = firstadr; i < nextadr; i++) {
2604                         JCVariableDecl vardecl = vardecls[i];
2605                         VarSymbol var = vardecl.sym;
2606                         if (allowValueClasses && (var.owner == classDef.sym && !var.isStatic() && (var.isStrict() || ((var.flags_field & RECORD) != 0)) && !isCompactOrGeneratedRecordConstructor)) {
2607                             checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
2608                         }
2609                     }
2610                     forEachInitializer(classDef, false, def -> {
2611                         scan(def);
2612                         clearPendingExits(false);
2613                     });
2614                 }
2615 
2616                 // If this(): at this point all final uninitialized fields will get initialized
2617                 else if (name == names._this) {
2618                     for (int address = firstadr; address < nextadr; address++) {
2619                         VarSymbol sym = vardecls[address].sym;
2620                         if (isFinalOrStrictUninitializedField(sym) && !sym.isStatic())
2621                             letInit(tree.pos(), sym);
2622                     }
2623                 }
2624             }
2625         }
2626 
2627         public void visitNewClass(JCNewClass tree) {
2628             scanExpr(tree.encl);
2629             scanExprs(tree.args);
2630             scan(tree.def);
2631         }
2632 
2633         @Override
2634         public void visitLambda(JCLambda tree) {
2635             final Bits prevUninits = new Bits(uninits);
2636             final Bits prevUninitsTry = new Bits(uninitsTry);
2637             final Bits prevInits = new Bits(inits);
2638             int returnadrPrev = returnadr;
2639             int nextadrPrev = nextadr;
2640             ListBuffer<PendingExit> prevPending = pendingExits;

2674         }
2675 
2676         public void visitAssert(JCAssert tree) {
2677             final Bits initsExit = new Bits(inits);
2678             final Bits uninitsExit = new Bits(uninits);
2679             scanCond(tree.cond);
2680             uninitsExit.andSet(uninitsWhenTrue);
2681             if (tree.detail != null) {
2682                 inits.assign(initsWhenFalse);
2683                 uninits.assign(uninitsWhenFalse);
2684                 scanExpr(tree.detail);
2685             }
2686             inits.assign(initsExit);
2687             uninits.assign(uninitsExit);
2688         }
2689 
2690         public void visitAssign(JCAssign tree) {
2691             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2692                 scanExpr(tree.lhs);
2693             scanExpr(tree.rhs);
2694             letInit(tree.lhs, tree);
2695         }
2696 
2697         // check fields accessed through this.<field> are definitely
2698         // assigned before reading their value
2699         public void visitSelect(JCFieldAccess tree) {
2700             super.visitSelect(tree);
2701             if (TreeInfo.isThisQualifier(tree.selected) &&
2702                 tree.sym.kind == VAR) {
2703                 checkInit(tree.pos(), (VarSymbol)tree.sym);
2704             }
2705         }
2706 
2707         public void visitAssignop(JCAssignOp tree) {
2708             scanExpr(tree.lhs);
2709             scanExpr(tree.rhs);
2710             letInit(tree.lhs);
2711         }
2712 
2713         public void visitUnary(JCUnary tree) {
2714             switch (tree.getTag()) {
< prev index next >