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

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


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

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





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

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










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










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

1729             }
1730 
1731             @Override
1732             public void resolveJump() {
1733                 inits.andSet(exit_inits);
1734                 uninits.andSet(exit_uninits);
1735             }
1736         }
1737 
1738         public AssignAnalyzer() {
1739             this.inits = new Bits();
1740             uninits = new Bits();
1741             uninitsTry = new Bits();
1742             initsWhenTrue = new Bits(true);
1743             initsWhenFalse = new Bits(true);
1744             uninitsWhenTrue = new Bits(true);
1745             uninitsWhenFalse = new Bits(true);
1746         }
1747 
1748         private boolean isConstructor;

1749 
1750         @Override
1751         protected void markDead() {
1752             inits.inclRange(returnadr, nextadr);
1753             uninits.inclRange(returnadr, nextadr);
1754         }
1755 
1756         /*-------------- Processing variables ----------------------*/
1757 
1758         /** Do we need to track init/uninit state of this symbol?
1759          *  I.e. is symbol either a local or a blank final variable?
1760          */
1761         protected boolean trackable(VarSymbol sym) {
1762             return
1763                 sym.pos >= startPos &&
1764                 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
1765                 isFinalUninitializedField(sym)));
1766         }
1767 
1768         boolean isFinalUninitializedField(VarSymbol sym) {
1769             return sym.owner.kind == TYP &&
1770                    ((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL &&

1771                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
1772         }
1773 
1774         /** Initialize new trackable variable by setting its address field
1775          *  to the next available sequence number and entering it under that
1776          *  index into the vars array.
1777          */
1778         void newVar(JCVariableDecl varDecl) {
1779             VarSymbol sym = varDecl.sym;
1780             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1781             if ((sym.flags() & FINAL) == 0) {
1782                 sym.flags_field |= EFFECTIVELY_FINAL;
1783             }
1784             sym.adr = nextadr;
1785             vardecls[nextadr] = varDecl;
1786             inits.excl(nextadr);
1787             uninits.incl(nextadr);
1788             nextadr++;
1789         }
1790 

1822                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1823             }
1824         }
1825         //where
1826             void uninit(VarSymbol sym) {
1827                 if (!inits.isMember(sym.adr)) {
1828                     // reachable assignment
1829                     uninits.excl(sym.adr);
1830                     uninitsTry.excl(sym.adr);
1831                 } else {
1832                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
1833                     uninits.excl(sym.adr);
1834                 }
1835             }
1836 
1837         /** If tree is either a simple name or of the form this.name or
1838          *  C.this.name, and tree represents a trackable variable,
1839          *  record an initialization of the variable.
1840          */
1841         void letInit(JCTree tree) {




1842             tree = TreeInfo.skipParens(tree);
1843             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1844                 Symbol sym = TreeInfo.symbol(tree);
1845                 if (sym.kind == VAR) {
1846                     letInit(tree.pos(), (VarSymbol)sym);






1847                 }
1848             }
1849         }
1850 
1851         /** Check that trackable variable is initialized.
1852          */
1853         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1854             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1855         }
1856 
1857         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1858             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1859                 trackable(sym) &&
1860                 !inits.isMember(sym.adr) &&
1861                 (sym.flags_field & CLASH) == 0) {
1862                     log.error(pos, errkey);
1863                 inits.incl(sym.adr);
1864             }
1865         }
1866 
1867         /** Utility method to reset several Bits instances.
1868          */
1869         private void resetBits(Bits... bits) {
1870             for (Bits b : bits) {
1871                 b.reset();
1872             }
1873         }
1874 
1875         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1876          */
1877         void split(boolean setToNull) {
1878             initsWhenFalse.assign(inits);
1879             uninitsWhenFalse.assign(uninits);
1880             initsWhenTrue.assign(inits);
1881             uninitsWhenTrue.assign(uninits);
1882             if (setToNull) {

2031 
2032         public void visitMethodDef(JCMethodDecl tree) {
2033             if (tree.body == null) {
2034                 return;
2035             }
2036 
2037             /*  MemberEnter can generate synthetic methods ignore them
2038              */
2039             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2040                 return;
2041             }
2042 
2043             final Bits initsPrev = new Bits(inits);
2044             final Bits uninitsPrev = new Bits(uninits);
2045             int nextadrPrev = nextadr;
2046             int firstadrPrev = firstadr;
2047             int returnadrPrev = returnadr;
2048 
2049             Assert.check(pendingExits.isEmpty());
2050             boolean isConstructorPrev = isConstructor;

2051             try {
2052                 isConstructor = TreeInfo.isConstructor(tree);


2053 
2054                 // We only track field initialization inside constructors
2055                 if (!isConstructor) {
2056                     firstadr = nextadr;
2057                 }
2058 
2059                 // Mark all method parameters as DA
2060                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2061                     JCVariableDecl def = l.head;
2062                     scan(def);
2063                     Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2064                     /*  If we are executing the code from Gen, then there can be
2065                      *  synthetic or mandated variables, ignore them.
2066                      */
2067                     initParam(def);
2068                 }







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

2098                                     } else {
2099                                         checkInit(TreeInfo.diagEndPos(tree.body), var);
2100                                     }
2101                                 } else {
2102                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2103                                 }
2104                             } else {
2105                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
2106                             }
2107                         }
2108                     }
2109                 }
2110                 clearPendingExits(true);
2111             } finally {
2112                 inits.assign(initsPrev);
2113                 uninits.assign(uninitsPrev);
2114                 nextadr = nextadrPrev;
2115                 firstadr = firstadrPrev;
2116                 returnadr = returnadrPrev;
2117                 isConstructor = isConstructorPrev;










2118             }

2119         }
2120 
2121         private void clearPendingExits(boolean inMethod) {
2122             List<PendingExit> exits = pendingExits.toList();
2123             pendingExits = new ListBuffer<>();
2124             while (exits.nonEmpty()) {
2125                 PendingExit exit = exits.head;
2126                 exits = exits.tail;
2127                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2128                                  log.hasErrorOn(exit.tree.pos()),
2129                              exit.tree);
2130                 if (inMethod && isConstructor) {
2131                     Assert.check(exit instanceof AssignPendingExit);
2132                     inits.assign(((AssignPendingExit) exit).exit_inits);
2133                     for (int i = firstadr; i < nextadr; i++) {
2134                         checkInit(exit.tree.pos(), vardecls[i].sym);
2135                     }
2136                 }
2137             }
2138         }

2557             }
2558         }
2559 
2560         @Override
2561         public void visitContinue(JCContinue tree) {
2562             recordExit(new AssignPendingExit(tree, inits, uninits));
2563         }
2564 
2565         @Override
2566         public void visitReturn(JCReturn tree) {
2567             scanExpr(tree.expr);
2568             recordExit(new AssignPendingExit(tree, inits, uninits));
2569         }
2570 
2571         public void visitThrow(JCThrow tree) {
2572             scanExpr(tree.expr);
2573             markDead();
2574         }
2575 
2576         public void visitApply(JCMethodInvocation tree) {








2577             scanExpr(tree.meth);
2578             scanExprs(tree.args);
2579 
2580             // Handle superclass constructor invocations
2581             if (isConstructor) {
2582 
2583                 // If super(): at this point all initialization blocks will execute
2584                 Name name = TreeInfo.name(tree.meth);
2585                 if (name == names._super) {








2586                     forEachInitializer(classDef, false, def -> {
2587                         scan(def);
2588                         clearPendingExits(false);
2589                     });
2590                 }
2591 
2592                 // If this(): at this point all final uninitialized fields will get initialized
2593                 else if (name == names._this) {
2594                     for (int address = firstadr; address < nextadr; address++) {
2595                         VarSymbol sym = vardecls[address].sym;
2596                         if (isFinalUninitializedField(sym) && !sym.isStatic())
2597                             letInit(tree.pos(), sym);
2598                     }
2599                 }
2600             }
2601         }
2602 
2603         public void visitNewClass(JCNewClass tree) {
2604             scanExpr(tree.encl);
2605             scanExprs(tree.args);
2606             scan(tree.def);
2607         }
2608 
2609         @Override
2610         public void visitLambda(JCLambda tree) {
2611             final Bits prevUninits = new Bits(uninits);
2612             final Bits prevUninitsTry = new Bits(uninitsTry);
2613             final Bits prevInits = new Bits(inits);
2614             int returnadrPrev = returnadr;
2615             int nextadrPrev = nextadr;
2616             ListBuffer<PendingExit> prevPending = pendingExits;

2650         }
2651 
2652         public void visitAssert(JCAssert tree) {
2653             final Bits initsExit = new Bits(inits);
2654             final Bits uninitsExit = new Bits(uninits);
2655             scanCond(tree.cond);
2656             uninitsExit.andSet(uninitsWhenTrue);
2657             if (tree.detail != null) {
2658                 inits.assign(initsWhenFalse);
2659                 uninits.assign(uninitsWhenFalse);
2660                 scanExpr(tree.detail);
2661             }
2662             inits.assign(initsExit);
2663             uninits.assign(uninitsExit);
2664         }
2665 
2666         public void visitAssign(JCAssign tree) {
2667             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2668                 scanExpr(tree.lhs);
2669             scanExpr(tree.rhs);
2670             letInit(tree.lhs);
2671         }
2672 
2673         // check fields accessed through this.<field> are definitely
2674         // assigned before reading their value
2675         public void visitSelect(JCFieldAccess tree) {
2676             super.visitSelect(tree);
2677             if (TreeInfo.isThisQualifier(tree.selected) &&
2678                 tree.sym.kind == VAR) {
2679                 checkInit(tree.pos(), (VarSymbol)tree.sym);
2680             }
2681         }
2682 
2683         public void visitAssignop(JCAssignOp tree) {
2684             scanExpr(tree.lhs);
2685             scanExpr(tree.rhs);
2686             letInit(tree.lhs);
2687         }
2688 
2689         public void visitUnary(JCUnary tree) {
2690             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.*;

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

 319         FlowKind(String errKey, boolean isFinal) {
 320             this.errKey = errKey;
 321             this.isFinal = isFinal;
 322         }
 323 
 324         boolean isFinal() {
 325             return isFinal;
 326         }
 327     }
 328 
 329     @SuppressWarnings("this-escape")
 330     protected Flow(Context context) {
 331         context.put(flowKey, this);
 332         names = Names.instance(context);
 333         log = Log.instance(context);
 334         syms = Symtab.instance(context);
 335         types = Types.instance(context);
 336         chk = Check.instance(context);
 337         rs = Resolve.instance(context);
 338         diags = JCDiagnostic.Factory.instance(context);
 339         unsetFieldsInfo = UnsetFieldsInfo.instance(context);
 340         Preview preview = Preview.instance(context);
 341         Source source = Source.instance(context);
 342         allowValueClasses = (!preview.isPreview(Source.Feature.VALUE_CLASSES) || preview.isEnabled()) &&
 343                 Source.Feature.VALUE_CLASSES.allowedInSource(source);
 344         exhaustiveness = ExhaustivenessComputer.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;

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

1758             }
1759 
1760             @Override
1761             public void resolveJump() {
1762                 inits.andSet(exit_inits);
1763                 uninits.andSet(exit_uninits);
1764             }
1765         }
1766 
1767         public AssignAnalyzer() {
1768             this.inits = new Bits();
1769             uninits = new Bits();
1770             uninitsTry = new Bits();
1771             initsWhenTrue = new Bits(true);
1772             initsWhenFalse = new Bits(true);
1773             uninitsWhenTrue = new Bits(true);
1774             uninitsWhenFalse = new Bits(true);
1775         }
1776 
1777         private boolean isConstructor;
1778         private boolean isCompactOrGeneratedRecordConstructor;
1779 
1780         @Override
1781         protected void markDead() {
1782             inits.inclRange(returnadr, nextadr);
1783             uninits.inclRange(returnadr, nextadr);
1784         }
1785 
1786         /*-------------- Processing variables ----------------------*/
1787 
1788         /** Do we need to track init/uninit state of this symbol?
1789          *  I.e. is symbol either a local or a blank final variable?
1790          */
1791         protected boolean trackable(VarSymbol sym) {
1792             return
1793                 sym.pos >= startPos &&
1794                 ((sym.owner.kind == MTH || sym.owner.kind == VAR ||
1795                 isFinalOrStrictUninitializedField(sym)));
1796         }
1797 
1798         boolean isFinalOrStrictUninitializedField(VarSymbol sym) {
1799             return sym.owner.kind == TYP &&
1800                    (((sym.flags() & (FINAL | HASINIT | PARAMETER)) == FINAL ||
1801                      (sym.flags() & (STRICT | HASINIT | PARAMETER)) == STRICT) &&
1802                    classDef.sym.isEnclosedBy((ClassSymbol)sym.owner));
1803         }
1804 
1805         /** Initialize new trackable variable by setting its address field
1806          *  to the next available sequence number and entering it under that
1807          *  index into the vars array.
1808          */
1809         void newVar(JCVariableDecl varDecl) {
1810             VarSymbol sym = varDecl.sym;
1811             vardecls = ArrayUtils.ensureCapacity(vardecls, nextadr);
1812             if ((sym.flags() & FINAL) == 0) {
1813                 sym.flags_field |= EFFECTIVELY_FINAL;
1814             }
1815             sym.adr = nextadr;
1816             vardecls[nextadr] = varDecl;
1817             inits.excl(nextadr);
1818             uninits.incl(nextadr);
1819             nextadr++;
1820         }
1821 

1853                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1854             }
1855         }
1856         //where
1857             void uninit(VarSymbol sym) {
1858                 if (!inits.isMember(sym.adr)) {
1859                     // reachable assignment
1860                     uninits.excl(sym.adr);
1861                     uninitsTry.excl(sym.adr);
1862                 } else {
1863                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
1864                     uninits.excl(sym.adr);
1865                 }
1866             }
1867 
1868         /** If tree is either a simple name or of the form this.name or
1869          *  C.this.name, and tree represents a trackable variable,
1870          *  record an initialization of the variable.
1871          */
1872         void letInit(JCTree tree) {
1873             letInit(tree, (JCAssign) null);
1874         }
1875 
1876         void letInit(JCTree tree, JCAssign assign) {
1877             tree = TreeInfo.skipParens(tree);
1878             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1879                 Symbol sym = TreeInfo.symbol(tree);
1880                 if (sym.kind == VAR) {
1881                     letInit(tree.pos(), (VarSymbol)sym);
1882                     if (isConstructor && sym.isStrict()) {
1883                         /* we are initializing a strict field inside of a constructor, we now need to find which fields
1884                          * haven't been initialized yet
1885                          */
1886                         unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, assign != null ? assign : tree, findUninitStrictFields());
1887                     }
1888                 }
1889             }
1890         }
1891 
1892         /** Check that trackable variable is initialized.
1893          */
1894         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1895             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1896         }
1897 
1898         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1899             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1900                 trackable(sym) &&
1901                 !inits.isMember(sym.adr) &&
1902                 (sym.flags_field & CLASH) == 0) {
1903                 log.error(pos, errkey);
1904                 inits.incl(sym.adr);
1905             }
1906         }
1907 
1908         /** Utility method to reset several Bits instances.
1909          */
1910         private void resetBits(Bits... bits) {
1911             for (Bits b : bits) {
1912                 b.reset();
1913             }
1914         }
1915 
1916         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1917          */
1918         void split(boolean setToNull) {
1919             initsWhenFalse.assign(inits);
1920             uninitsWhenFalse.assign(uninits);
1921             initsWhenTrue.assign(inits);
1922             uninitsWhenTrue.assign(uninits);
1923             if (setToNull) {

2072 
2073         public void visitMethodDef(JCMethodDecl tree) {
2074             if (tree.body == null) {
2075                 return;
2076             }
2077 
2078             /*  MemberEnter can generate synthetic methods ignore them
2079              */
2080             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2081                 return;
2082             }
2083 
2084             final Bits initsPrev = new Bits(inits);
2085             final Bits uninitsPrev = new Bits(uninits);
2086             int nextadrPrev = nextadr;
2087             int firstadrPrev = firstadr;
2088             int returnadrPrev = returnadr;
2089 
2090             Assert.check(pendingExits.isEmpty());
2091             boolean isConstructorPrev = isConstructor;
2092             boolean isCompactOrGeneratedRecordConstructorPrev = isCompactOrGeneratedRecordConstructor;
2093             try {
2094                 isConstructor = TreeInfo.isConstructor(tree);
2095                 isCompactOrGeneratedRecordConstructor = isConstructor && ((tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2096                          (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD));
2097 
2098                 // We only track field initialization inside constructors
2099                 if (!isConstructor) {
2100                     firstadr = nextadr;
2101                 }
2102 
2103                 // Mark all method parameters as DA
2104                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2105                     JCVariableDecl def = l.head;
2106                     scan(def);
2107                     Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2108                     /*  If we are executing the code from Gen, then there can be
2109                      *  synthetic or mandated variables, ignore them.
2110                      */
2111                     initParam(def);
2112                 }
2113                 if (isConstructor) {
2114                     Set<VarSymbol> unsetFields = findUninitStrictFields();
2115                     if (unsetFields != null && !unsetFields.isEmpty()) {
2116                         unsetFieldsInfo.addUnsetFieldsInfo(classDef.sym, tree.body, unsetFields);
2117                     }
2118                 }
2119 
2120                 // else we are in an instance initializer block;
2121                 // leave caught unchanged.
2122                 scan(tree.body);
2123 


2124                 if (isConstructor) {
2125                     boolean isSynthesized = (tree.sym.flags() &
2126                                              GENERATEDCONSTR) != 0;
2127                     for (int i = firstadr; i < nextadr; i++) {
2128                         JCVariableDecl vardecl = vardecls[i];
2129                         VarSymbol var = vardecl.sym;
2130                         if (var.owner == classDef.sym && !var.isStatic()) {
2131                             // choose the diagnostic position based on whether
2132                             // the ctor is default(synthesized) or not
2133                             if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2134                                 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2135                                         var, Errors.VarNotInitializedInDefaultConstructor(var));
2136                             } else if (isCompactOrGeneratedRecordConstructor) {
2137                                 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2138                                         (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2139                                         var.owner.kind == TYP;
2140                                 if (isInstanceRecordField) {
2141                                     boolean notInitialized = !inits.isMember(var.adr);
2142                                     if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2143                                     /*  this way we indicate Lower that it should generate an initialization for this field

2147                                     } else {
2148                                         checkInit(TreeInfo.diagEndPos(tree.body), var);
2149                                     }
2150                                 } else {
2151                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2152                                 }
2153                             } else {
2154                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
2155                             }
2156                         }
2157                     }
2158                 }
2159                 clearPendingExits(true);
2160             } finally {
2161                 inits.assign(initsPrev);
2162                 uninits.assign(uninitsPrev);
2163                 nextadr = nextadrPrev;
2164                 firstadr = firstadrPrev;
2165                 returnadr = returnadrPrev;
2166                 isConstructor = isConstructorPrev;
2167                 isCompactOrGeneratedRecordConstructor = isCompactOrGeneratedRecordConstructorPrev;
2168             }
2169         }
2170 
2171         Set<VarSymbol> findUninitStrictFields() {
2172             Set<VarSymbol> unsetFields = new LinkedHashSet<>();
2173             for (int i = firstadr; i < nextadr; i++) {
2174                 if (uninits.isMember(i) && vardecls[i].sym.isStrict()) {
2175                     unsetFields.add(vardecls[i].sym);
2176                 }
2177             }
2178             return unsetFields;
2179         }
2180 
2181         private void clearPendingExits(boolean inMethod) {
2182             List<PendingExit> exits = pendingExits.toList();
2183             pendingExits = new ListBuffer<>();
2184             while (exits.nonEmpty()) {
2185                 PendingExit exit = exits.head;
2186                 exits = exits.tail;
2187                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2188                                  log.hasErrorOn(exit.tree.pos()),
2189                              exit.tree);
2190                 if (inMethod && isConstructor) {
2191                     Assert.check(exit instanceof AssignPendingExit);
2192                     inits.assign(((AssignPendingExit) exit).exit_inits);
2193                     for (int i = firstadr; i < nextadr; i++) {
2194                         checkInit(exit.tree.pos(), vardecls[i].sym);
2195                     }
2196                 }
2197             }
2198         }

2617             }
2618         }
2619 
2620         @Override
2621         public void visitContinue(JCContinue tree) {
2622             recordExit(new AssignPendingExit(tree, inits, uninits));
2623         }
2624 
2625         @Override
2626         public void visitReturn(JCReturn tree) {
2627             scanExpr(tree.expr);
2628             recordExit(new AssignPendingExit(tree, inits, uninits));
2629         }
2630 
2631         public void visitThrow(JCThrow tree) {
2632             scanExpr(tree.expr);
2633             markDead();
2634         }
2635 
2636         public void visitApply(JCMethodInvocation tree) {
2637             Name name = TreeInfo.name(tree.meth);
2638             // let's process early initializers
2639             if (name == names._super) {
2640                 forEachInitializer(classDef, false, true, def -> {
2641                     scan(def);
2642                     clearPendingExits(false);
2643                 });
2644             }
2645             scanExpr(tree.meth);
2646             scanExprs(tree.args);
2647 
2648             // Handle superclass constructor invocations
2649             if (isConstructor) {
2650 
2651                 // If super(): at this point all initialization blocks will execute
2652 
2653                 if (name == names._super) {
2654                     // strict fields should have been initialized at this point
2655                     for (int i = firstadr; i < nextadr; i++) {
2656                         JCVariableDecl vardecl = vardecls[i];
2657                         VarSymbol var = vardecl.sym;
2658                         if (allowValueClasses && (var.owner == classDef.sym && !var.isStatic() && (var.isStrict() || ((var.flags_field & RECORD) != 0)) && !isCompactOrGeneratedRecordConstructor)) {
2659                             checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
2660                         }
2661                     }
2662                     forEachInitializer(classDef, false, def -> {
2663                         scan(def);
2664                         clearPendingExits(false);
2665                     });
2666                 }
2667 
2668                 // If this(): at this point all final uninitialized fields will get initialized
2669                 else if (name == names._this) {
2670                     for (int address = firstadr; address < nextadr; address++) {
2671                         VarSymbol sym = vardecls[address].sym;
2672                         if (isFinalOrStrictUninitializedField(sym) && !sym.isStatic())
2673                             letInit(tree.pos(), sym);
2674                     }
2675                 }
2676             }
2677         }
2678 
2679         public void visitNewClass(JCNewClass tree) {
2680             scanExpr(tree.encl);
2681             scanExprs(tree.args);
2682             scan(tree.def);
2683         }
2684 
2685         @Override
2686         public void visitLambda(JCLambda tree) {
2687             final Bits prevUninits = new Bits(uninits);
2688             final Bits prevUninitsTry = new Bits(uninitsTry);
2689             final Bits prevInits = new Bits(inits);
2690             int returnadrPrev = returnadr;
2691             int nextadrPrev = nextadr;
2692             ListBuffer<PendingExit> prevPending = pendingExits;

2726         }
2727 
2728         public void visitAssert(JCAssert tree) {
2729             final Bits initsExit = new Bits(inits);
2730             final Bits uninitsExit = new Bits(uninits);
2731             scanCond(tree.cond);
2732             uninitsExit.andSet(uninitsWhenTrue);
2733             if (tree.detail != null) {
2734                 inits.assign(initsWhenFalse);
2735                 uninits.assign(uninitsWhenFalse);
2736                 scanExpr(tree.detail);
2737             }
2738             inits.assign(initsExit);
2739             uninits.assign(uninitsExit);
2740         }
2741 
2742         public void visitAssign(JCAssign tree) {
2743             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2744                 scanExpr(tree.lhs);
2745             scanExpr(tree.rhs);
2746             letInit(tree.lhs, tree);
2747         }
2748 
2749         // check fields accessed through this.<field> are definitely
2750         // assigned before reading their value
2751         public void visitSelect(JCFieldAccess tree) {
2752             super.visitSelect(tree);
2753             if (TreeInfo.isThisQualifier(tree.selected) &&
2754                 tree.sym.kind == VAR) {
2755                 checkInit(tree.pos(), (VarSymbol)tree.sym);
2756             }
2757         }
2758 
2759         public void visitAssignop(JCAssignOp tree) {
2760             scanExpr(tree.lhs);
2761             scanExpr(tree.rhs);
2762             letInit(tree.lhs);
2763         }
2764 
2765         public void visitUnary(JCUnary tree) {
2766             switch (tree.getTag()) {
< prev index next >