< prev index next >

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

Print this page

  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.*;
  51 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
  52 import static com.sun.tools.javac.code.TypeTag.VOID;
  53 import com.sun.tools.javac.comp.ExhaustivenessComputer.BindingPattern;
  54 import com.sun.tools.javac.comp.ExhaustivenessComputer.EnumConstantPattern;
  55 import com.sun.tools.javac.comp.ExhaustivenessComputer.ExhaustivenessResult;
  56 import com.sun.tools.javac.comp.ExhaustivenessComputer.PatternDescription;
  57 import com.sun.tools.javac.comp.ExhaustivenessComputer.RecordPattern;
  58 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  59 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  60 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
  61 import java.util.Arrays;

  62 
  63 /** This pass implements dataflow analysis for Java programs though
  64  *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
  65  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
  66  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
  67  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
  68  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
  69  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
  70  *  determines that local variables accessed within the scope of an inner class/lambda
  71  *  are either final or effectively-final.
  72  *
  73  *  <p>The JLS has a number of problems in the
  74  *  specification of these flow analysis problems. This implementation
  75  *  attempts to address those issues.
  76  *
  77  *  <p>First, there is no accommodation for a finally clause that cannot
  78  *  complete normally. For liveness analysis, an intervening finally
  79  *  clause can cause a break, continue, or return not to reach its
  80  *  target.  For exception analysis, an intervening finally clause can
  81  *  cause any exception to be "caught".  For DA/DU analysis, the finally

 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 

 548         }
 549 
 550         /* ------------ Visitor methods for various sorts of trees -------------*/
 551 
 552         public void visitClassDef(JCClassDecl tree) {
 553             if (tree.sym == null) return;
 554             Liveness alivePrev = alive;
 555             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
 556 
 557             pendingExits = new ListBuffer<>();
 558 
 559             try {
 560                 // process all the nested classes
 561                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 562                     if (l.head.hasTag(CLASSDEF)) {
 563                         scan(l.head);
 564                     }
 565                 }
 566 
 567                 // process all the static initializers
 568                 forEachInitializer(tree, true, def -> {
 569                     scanDef(def);
 570                     clearPendingExits(false);
 571                 });
 572 
 573                 // process all the instance initializers
 574                 forEachInitializer(tree, false, def -> {
 575                     scanDef(def);
 576                     clearPendingExits(false);
 577                 });
 578 
 579                 // process all the methods
 580                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 581                     if (l.head.hasTag(METHODDEF)) {
 582                         scan(l.head);
 583                     }
 584                 }
 585             } finally {
 586                 pendingExits = pendingExitsPrev;
 587                 alive = alivePrev;
 588             }
 589         }
 590 
 591         public void visitMethodDef(JCMethodDecl tree) {
 592             if (tree.body == null) return;
 593 
 594             Assert.check(pendingExits.isEmpty());

1037             List<Type> thrownPrev = thrown;
1038             List<Type> caughtPrev = caught;
1039             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
1040             boolean anonymousClass = tree.name == names.empty;
1041             pendingExits = new ListBuffer<>();
1042             if (!anonymousClass) {
1043                 caught = List.nil();
1044             }
1045             classDef = tree;
1046             thrown = List.nil();
1047 
1048             try {
1049                 // process all the nested classes
1050                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1051                     if (l.head.hasTag(CLASSDEF)) {
1052                         scan(l.head);
1053                     }
1054                 }
1055 
1056                 // process all the static initializers
1057                 forEachInitializer(tree, true, def -> {
1058                     scan(def);
1059                     errorUncaught();
1060                 });
1061 
1062                 // in an anonymous class, add the set of thrown exceptions to
1063                 // the throws clause of the synthetic constructor and propagate
1064                 // outwards.
1065                 // Changing the throws clause on the fly is okay here because
1066                 // the anonymous constructor can't be invoked anywhere else,
1067                 // and its type hasn't been cached.
1068                 if (anonymousClass) {
1069                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1070                         if (TreeInfo.isConstructor(l.head)) {
1071                             JCMethodDecl mdef = (JCMethodDecl)l.head;
1072                             scan(mdef);
1073                             mdef.thrown = make.Types(thrown);
1074                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
1075                         }
1076                     }
1077                     thrownPrev = chk.union(thrown, thrownPrev);

1381                 for (Type t : preciseRethrowTypes.get(sym)) {
1382                     markThrown(tree, t);
1383                 }
1384             }
1385             else {
1386                 markThrown(tree, tree.expr.type);
1387             }
1388             markDead();
1389         }
1390 
1391         public void visitApply(JCMethodInvocation tree) {
1392             scan(tree.meth);
1393             scan(tree.args);
1394 
1395             // Mark as thrown the exceptions thrown by the method being invoked
1396             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
1397                 markThrown(tree, l.head);
1398 
1399             // After super(), scan initializers to uncover any exceptions they throw
1400             if (TreeInfo.name(tree.meth) == names._super) {
1401                 forEachInitializer(classDef, false, def -> {
1402                     scan(def);
1403                     errorUncaught();
1404                 });
1405             }
1406         }
1407 
1408         public void visitNewClass(JCNewClass tree) {
1409             scan(tree.encl);
1410             scan(tree.args);
1411            // scan(tree.def);
1412             for (List<Type> l = tree.constructorType.getThrownTypes();
1413                  l.nonEmpty();
1414                  l = l.tail) {
1415                 markThrown(tree, l.head);
1416             }
1417             List<Type> caughtPrev = caught;
1418             try {
1419                 // If the new class expression defines an anonymous class,
1420                 // analysis of the anonymous constructor may encounter thrown
1421                 // types which are unsubstituted type variables.

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 
1791         /** Record an initialization of a trackable variable.

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) {

1964             pendingExits = new ListBuffer<>();
1965             if (tree.name != names.empty) {
1966                 firstadr = nextadr;
1967             }
1968             classDef = tree;
1969             try {
1970                 // define all the static fields
1971                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1972                     if (l.head.hasTag(VARDEF)) {
1973                         JCVariableDecl def = (JCVariableDecl)l.head;
1974                         if ((def.mods.flags & STATIC) != 0) {
1975                             VarSymbol sym = def.sym;
1976                             if (trackable(sym)) {
1977                                 newVar(def);
1978                             }
1979                         }
1980                     }
1981                 }
1982 
1983                 // process all the static initializers
1984                 forEachInitializer(tree, true, def -> {
1985                     scan(def);
1986                     clearPendingExits(false);
1987                 });
1988 
1989                 // verify all static final fields got initialized
1990                 for (int i = firstadr; i < nextadr; i++) {
1991                     JCVariableDecl vardecl = vardecls[i];
1992                     VarSymbol var = vardecl.sym;
1993                     if (var.owner == classDef.sym && var.isStatic()) {
1994                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
1995                     }
1996                 }
1997 
1998                 // define all the instance fields
1999                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2000                     if (l.head.hasTag(VARDEF)) {
2001                         JCVariableDecl def = (JCVariableDecl)l.head;
2002                         if ((def.mods.flags & STATIC) == 0) {
2003                             VarSymbol sym = def.sym;
2004                             if (trackable(sym)) {

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             }

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;
2617             try {
2618                 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
2619                 // body. This is by design: a variable that was definitely unassigned before the
2620                 // lambda body may end up being assigned to later on, so we cannot conclude that
2621                 // the variable will be unassigned when the body is executed.
2622                 uninits.excludeFrom(firstadr);

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()) {

  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.*;
  51 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
  52 import static com.sun.tools.javac.code.TypeTag.VOID;
  53 import com.sun.tools.javac.comp.ExhaustivenessComputer.BindingPattern;
  54 import com.sun.tools.javac.comp.ExhaustivenessComputer.EnumConstantPattern;
  55 import com.sun.tools.javac.comp.ExhaustivenessComputer.ExhaustivenessResult;
  56 import com.sun.tools.javac.comp.ExhaustivenessComputer.PatternDescription;
  57 import com.sun.tools.javac.comp.ExhaustivenessComputer.RecordPattern;
  58 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  59 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  60 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
  61 import java.util.Arrays;
  62 import java.util.function.Predicate;
  63 
  64 /** This pass implements dataflow analysis for Java programs though
  65  *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
  66  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
  67  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
  68  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
  69  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
  70  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
  71  *  determines that local variables accessed within the scope of an inner class/lambda
  72  *  are either final or effectively-final.
  73  *
  74  *  <p>The JLS has a number of problems in the
  75  *  specification of these flow analysis problems. This implementation
  76  *  attempts to address those issues.
  77  *
  78  *  <p>First, there is no accommodation for a finally clause that cannot
  79  *  complete normally. For liveness analysis, an intervening finally
  80  *  clause can cause a break, continue, or return not to reach its
  81  *  target.  For exception analysis, an intervening finally clause can
  82  *  cause any exception to be "caught".  For DA/DU analysis, the finally

 453             }
 454         }
 455 
 456         public void visitPackageDef(JCPackageDecl tree) {
 457             // Do nothing for PackageDecl
 458         }
 459 
 460         protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
 461             if (swtch.hasTag(SWITCH_EXPRESSION)) {
 462                 JCYield brk = make.at(Position.NOPOS).Yield(make.Erroneous()
 463                                                                 .setType(swtch.type));
 464                 brk.target = swtch;
 465                 scan(brk);
 466             } else {
 467                 JCBreak brk = make.at(Position.NOPOS).Break(null);
 468                 brk.target = swtch;
 469                 scan(brk);
 470             }
 471         }
 472 
 473         /** a predicate that selects all static initializers */
 474         static final Predicate<JCTree> STATIC_INITS = tree ->
 475             switch (tree) {
 476                 case JCVariableDecl vdecl -> vdecl.sym.isStatic();
 477                 case JCBlock b -> b.isStatic();
 478                 default -> false;
 479             };
 480 
 481         /** a predicate that selects early instance initializers */
 482         static final Predicate<JCTree> EARLY_INSTANCE_INITS = tree ->
 483                 tree instanceof JCVariableDecl vdecl && vdecl.sym.isStrictInstance();
 484 
 485         /** a predicate that selects late instance initializers */
 486         static final Predicate<JCTree> LATE_INSTANCE_INITS = tree ->
 487                 switch (tree) {
 488                     case JCVariableDecl vdecl -> !vdecl.sym.isStatic() && !vdecl.sym.isStrict();
 489                     case JCBlock b -> !b.isStatic();
 490                     default -> false;
 491                 };
 492 
 493         /** a predicate that all instance initializers */
 494         static final Predicate<JCTree> INSTANCE_INITS = EARLY_INSTANCE_INITS.or(LATE_INSTANCE_INITS);
 495 
 496         protected void forEachInitializer(JCClassDecl classDef, Predicate<? super JCTree> initFilter,
 497                                           Consumer<? super JCTree> handler) {
 498             if (classDef == initScanClass)          // avoid infinite loops
 499                 return;
 500             JCClassDecl initScanClassPrev = initScanClass;
 501             initScanClass = classDef;
 502             try {
 503                 for (List<JCTree> defs = classDef.defs; defs.nonEmpty(); defs = defs.tail) {
 504                     JCTree def = defs.head;
 505 
 506                     if (!initFilter.test(def)) {

 507                         continue;
 508                     }
 509 
 510                     handler.accept(def);






 511                 }
 512             } finally {
 513                 initScanClass = initScanClassPrev;
 514             }
 515         }
 516     }
 517 
 518     /**
 519      * This pass implements the first step of the dataflow analysis, namely
 520      * the liveness analysis check. This checks that every statement is reachable.
 521      * The output of this analysis pass are used by other analyzers. This analyzer
 522      * sets the 'finallyCanCompleteNormally' field in the JCTry class.
 523      */
 524     class AliveAnalyzer extends BaseAnalyzer {
 525 
 526         /** A flag that indicates whether the last statement could
 527          *  complete normally.
 528          */
 529         private Liveness alive;
 530 

 566         }
 567 
 568         /* ------------ Visitor methods for various sorts of trees -------------*/
 569 
 570         public void visitClassDef(JCClassDecl tree) {
 571             if (tree.sym == null) return;
 572             Liveness alivePrev = alive;
 573             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
 574 
 575             pendingExits = new ListBuffer<>();
 576 
 577             try {
 578                 // process all the nested classes
 579                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 580                     if (l.head.hasTag(CLASSDEF)) {
 581                         scan(l.head);
 582                     }
 583                 }
 584 
 585                 // process all the static initializers
 586                 forEachInitializer(tree, STATIC_INITS, def -> {
 587                     scanDef(def);
 588                     clearPendingExits(false);
 589                 });
 590 
 591                 // process all the instance initializers
 592                 forEachInitializer(tree, INSTANCE_INITS, def -> {
 593                     scanDef(def);
 594                     clearPendingExits(false);
 595                 });
 596 
 597                 // process all the methods
 598                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
 599                     if (l.head.hasTag(METHODDEF)) {
 600                         scan(l.head);
 601                     }
 602                 }
 603             } finally {
 604                 pendingExits = pendingExitsPrev;
 605                 alive = alivePrev;
 606             }
 607         }
 608 
 609         public void visitMethodDef(JCMethodDecl tree) {
 610             if (tree.body == null) return;
 611 
 612             Assert.check(pendingExits.isEmpty());

1055             List<Type> thrownPrev = thrown;
1056             List<Type> caughtPrev = caught;
1057             ListBuffer<PendingExit> pendingExitsPrev = pendingExits;
1058             boolean anonymousClass = tree.name == names.empty;
1059             pendingExits = new ListBuffer<>();
1060             if (!anonymousClass) {
1061                 caught = List.nil();
1062             }
1063             classDef = tree;
1064             thrown = List.nil();
1065 
1066             try {
1067                 // process all the nested classes
1068                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1069                     if (l.head.hasTag(CLASSDEF)) {
1070                         scan(l.head);
1071                     }
1072                 }
1073 
1074                 // process all the static initializers
1075                 forEachInitializer(tree, STATIC_INITS, def -> {
1076                     scan(def);
1077                     errorUncaught();
1078                 });
1079 
1080                 // in an anonymous class, add the set of thrown exceptions to
1081                 // the throws clause of the synthetic constructor and propagate
1082                 // outwards.
1083                 // Changing the throws clause on the fly is okay here because
1084                 // the anonymous constructor can't be invoked anywhere else,
1085                 // and its type hasn't been cached.
1086                 if (anonymousClass) {
1087                     for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1088                         if (TreeInfo.isConstructor(l.head)) {
1089                             JCMethodDecl mdef = (JCMethodDecl)l.head;
1090                             scan(mdef);
1091                             mdef.thrown = make.Types(thrown);
1092                             mdef.sym.type = types.createMethodTypeWithThrown(mdef.sym.type, thrown);
1093                         }
1094                     }
1095                     thrownPrev = chk.union(thrown, thrownPrev);

1399                 for (Type t : preciseRethrowTypes.get(sym)) {
1400                     markThrown(tree, t);
1401                 }
1402             }
1403             else {
1404                 markThrown(tree, tree.expr.type);
1405             }
1406             markDead();
1407         }
1408 
1409         public void visitApply(JCMethodInvocation tree) {
1410             scan(tree.meth);
1411             scan(tree.args);
1412 
1413             // Mark as thrown the exceptions thrown by the method being invoked
1414             for (List<Type> l = tree.meth.type.getThrownTypes(); l.nonEmpty(); l = l.tail)
1415                 markThrown(tree, l.head);
1416 
1417             // After super(), scan initializers to uncover any exceptions they throw
1418             if (TreeInfo.name(tree.meth) == names._super) {
1419                 forEachInitializer(classDef, INSTANCE_INITS, def -> {
1420                     scan(def);
1421                     errorUncaught();
1422                 });
1423             }
1424         }
1425 
1426         public void visitNewClass(JCNewClass tree) {
1427             scan(tree.encl);
1428             scan(tree.args);
1429            // scan(tree.def);
1430             for (List<Type> l = tree.constructorType.getThrownTypes();
1431                  l.nonEmpty();
1432                  l = l.tail) {
1433                 markThrown(tree, l.head);
1434             }
1435             List<Type> caughtPrev = caught;
1436             try {
1437                 // If the new class expression defines an anonymous class,
1438                 // analysis of the anonymous constructor may encounter thrown
1439                 // types which are unsubstituted type variables.

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

1842                 log.error(pos, Errors.VarMightAlreadyBeAssigned(sym));
1843             }
1844         }
1845         //where
1846             void uninit(VarSymbol sym) {
1847                 if (!inits.isMember(sym.adr)) {
1848                     // reachable assignment
1849                     uninits.excl(sym.adr);
1850                     uninitsTry.excl(sym.adr);
1851                 } else {
1852                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
1853                     uninits.excl(sym.adr);
1854                 }
1855             }
1856 
1857         /** If tree is either a simple name or of the form this.name or
1858          *  C.this.name, and tree represents a trackable variable,
1859          *  record an initialization of the variable.
1860          */
1861         void letInit(JCTree tree) {
1862             letInit(tree, (JCAssign) null);
1863         }
1864 
1865         void letInit(JCTree tree, JCAssign assign) {
1866             tree = TreeInfo.skipParens(tree);
1867             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1868                 Symbol sym = TreeInfo.symbol(tree);
1869                 if (sym.kind == VAR) {
1870                     letInit(tree.pos(), (VarSymbol)sym);
1871                 }
1872             }
1873         }
1874 
1875         /** Check that trackable variable is initialized.
1876          */
1877         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1878             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1879         }
1880 
1881         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1882             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1883                 trackable(sym) &&
1884                 !inits.isMember(sym.adr) &&
1885                 (sym.flags_field & CLASH) == 0) {
1886                 log.error(pos, errkey);
1887                 inits.incl(sym.adr);
1888             }
1889         }
1890 
1891         /** Utility method to reset several Bits instances.
1892          */
1893         private void resetBits(Bits... bits) {
1894             for (Bits b : bits) {
1895                 b.reset();
1896             }
1897         }
1898 
1899         /** Split (duplicate) inits/uninits into WhenTrue/WhenFalse sets
1900          */
1901         void split(boolean setToNull) {
1902             initsWhenFalse.assign(inits);
1903             uninitsWhenFalse.assign(uninits);
1904             initsWhenTrue.assign(inits);
1905             uninitsWhenTrue.assign(uninits);
1906             if (setToNull) {

1988             pendingExits = new ListBuffer<>();
1989             if (tree.name != names.empty) {
1990                 firstadr = nextadr;
1991             }
1992             classDef = tree;
1993             try {
1994                 // define all the static fields
1995                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
1996                     if (l.head.hasTag(VARDEF)) {
1997                         JCVariableDecl def = (JCVariableDecl)l.head;
1998                         if ((def.mods.flags & STATIC) != 0) {
1999                             VarSymbol sym = def.sym;
2000                             if (trackable(sym)) {
2001                                 newVar(def);
2002                             }
2003                         }
2004                     }
2005                 }
2006 
2007                 // process all the static initializers
2008                 forEachInitializer(tree, STATIC_INITS, def -> {
2009                     scan(def);
2010                     clearPendingExits(false);
2011                 });
2012 
2013                 // verify all static final fields got initialized
2014                 for (int i = firstadr; i < nextadr; i++) {
2015                     JCVariableDecl vardecl = vardecls[i];
2016                     VarSymbol var = vardecl.sym;
2017                     if (var.owner == classDef.sym && var.isStatic()) {
2018                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2019                     }
2020                 }
2021 
2022                 // define all the instance fields
2023                 for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
2024                     if (l.head.hasTag(VARDEF)) {
2025                         JCVariableDecl def = (JCVariableDecl)l.head;
2026                         if ((def.mods.flags & STATIC) == 0) {
2027                             VarSymbol sym = def.sym;
2028                             if (trackable(sym)) {

2055 
2056         public void visitMethodDef(JCMethodDecl tree) {
2057             if (tree.body == null) {
2058                 return;
2059             }
2060 
2061             /*  MemberEnter can generate synthetic methods ignore them
2062              */
2063             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2064                 return;
2065             }
2066 
2067             final Bits initsPrev = new Bits(inits);
2068             final Bits uninitsPrev = new Bits(uninits);
2069             int nextadrPrev = nextadr;
2070             int firstadrPrev = firstadr;
2071             int returnadrPrev = returnadr;
2072 
2073             Assert.check(pendingExits.isEmpty());
2074             boolean isConstructorPrev = isConstructor;
2075             boolean isCompactOrGeneratedRecordConstructorPrev = isCompactOrGeneratedRecordConstructor;
2076             try {
2077                 isConstructor = TreeInfo.isConstructor(tree);
2078                 isCompactOrGeneratedRecordConstructor = isConstructor && ((tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0 ||
2079                          (tree.sym.flags() & (GENERATEDCONSTR | RECORD)) == (GENERATEDCONSTR | RECORD));
2080 
2081                 // We only track field initialization inside constructors
2082                 if (!isConstructor) {
2083                     firstadr = nextadr;
2084                 }
2085 
2086                 // Mark all method parameters as DA
2087                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2088                     JCVariableDecl def = l.head;
2089                     scan(def);
2090                     Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2091                     /*  If we are executing the code from Gen, then there can be
2092                      *  synthetic or mandated variables, ignore them.
2093                      */
2094                     initParam(def);
2095                 }
2096                 if (isConstructor &&
2097                         !TreeInfo.hasConstructorCall(tree, names._this)) {
2098                     // Strict fields initializers are executed before the first statement
2099                     // in the constructor body, unless the constructor is an alternate constructor
2100                     forEachInitializer(classDef, EARLY_INSTANCE_INITS, def -> {
2101                         scan(def);
2102                         clearPendingExits(false);
2103                     });
2104                 }
2105                 // else we are in an instance initializer block;
2106                 // leave caught unchanged.
2107                 scan(tree.body);
2108 


2109                 if (isConstructor) {
2110                     boolean isSynthesized = (tree.sym.flags() &
2111                                              GENERATEDCONSTR) != 0;
2112                     for (int i = firstadr; i < nextadr; i++) {
2113                         JCVariableDecl vardecl = vardecls[i];
2114                         VarSymbol var = vardecl.sym;
2115                         if (var.owner == classDef.sym && !var.isStatic()) {
2116                             // choose the diagnostic position based on whether
2117                             // the ctor is default(synthesized) or not
2118                             if (isSynthesized && !isCompactOrGeneratedRecordConstructor) {
2119                                 checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2120                                         var, Errors.VarNotInitializedInDefaultConstructor(var));
2121                             } else if (isCompactOrGeneratedRecordConstructor) {
2122                                 boolean isInstanceRecordField = var.enclClass().isRecord() &&
2123                                         (var.flags_field & (Flags.PRIVATE | Flags.FINAL | Flags.GENERATED_MEMBER | Flags.RECORD)) != 0 &&
2124                                         var.owner.kind == TYP;
2125                                 if (isInstanceRecordField) {
2126                                     boolean notInitialized = !inits.isMember(var.adr);
2127                                     if (notInitialized && uninits.isMember(var.adr) && tree.completesNormally) {
2128                                     /*  this way we indicate Lower that it should generate an initialization for this field

2132                                     } else {
2133                                         checkInit(TreeInfo.diagEndPos(tree.body), var);
2134                                     }
2135                                 } else {
2136                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2137                                 }
2138                             } else {
2139                                 checkInit(TreeInfo.diagEndPos(tree.body), var);
2140                             }
2141                         }
2142                     }
2143                 }
2144                 clearPendingExits(true);
2145             } finally {
2146                 inits.assign(initsPrev);
2147                 uninits.assign(uninitsPrev);
2148                 nextadr = nextadrPrev;
2149                 firstadr = firstadrPrev;
2150                 returnadr = returnadrPrev;
2151                 isConstructor = isConstructorPrev;
2152                 isCompactOrGeneratedRecordConstructor = isCompactOrGeneratedRecordConstructorPrev;
2153             }
2154         }
2155 
2156         private void clearPendingExits(boolean inMethod) {
2157             List<PendingExit> exits = pendingExits.toList();
2158             pendingExits = new ListBuffer<>();
2159             while (exits.nonEmpty()) {
2160                 PendingExit exit = exits.head;
2161                 exits = exits.tail;
2162                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2163                                  log.hasErrorOn(exit.tree.pos()),
2164                              exit.tree);
2165                 if (inMethod && isConstructor) {
2166                     Assert.check(exit instanceof AssignPendingExit);
2167                     inits.assign(((AssignPendingExit) exit).exit_inits);
2168                     for (int i = firstadr; i < nextadr; i++) {
2169                         checkInit(exit.tree.pos(), vardecls[i].sym);
2170                     }
2171                 }
2172             }

2601         public void visitReturn(JCReturn tree) {
2602             scanExpr(tree.expr);
2603             recordExit(new AssignPendingExit(tree, inits, uninits));
2604         }
2605 
2606         public void visitThrow(JCThrow tree) {
2607             scanExpr(tree.expr);
2608             markDead();
2609         }
2610 
2611         public void visitApply(JCMethodInvocation tree) {
2612             scanExpr(tree.meth);
2613             scanExprs(tree.args);
2614 
2615             // Handle superclass constructor invocations
2616             if (isConstructor) {
2617 
2618                 // If super(): at this point all initialization blocks will execute
2619                 Name name = TreeInfo.name(tree.meth);
2620                 if (name == names._super) {
2621                     if (!isCompactOrGeneratedRecordConstructor) {
2622                         // all strict fields must be initialized at this point
2623                         checkStrictFieldsInitializedBeforeSuper(tree);
2624                     }
2625                     forEachInitializer(classDef, LATE_INSTANCE_INITS,
2626                             def -> {
2627                                 scan(def);
2628                                 clearPendingExits(false);
2629                             });
2630                 }
2631 
2632                 // If this(): at this point all final uninitialized fields will get initialized
2633                 else if (name == names._this) {
2634                     for (int address = firstadr; address < nextadr; address++) {
2635                         VarSymbol sym = vardecls[address].sym;
2636                         if (isBlankFinalOrStrictField(sym) && !sym.isStatic())
2637                             letInit(tree.pos(), sym);
2638                     }
2639                 }
2640             }
2641         }
2642 
2643         void checkStrictFieldsInitializedBeforeSuper(JCMethodInvocation tree) {
2644             for (int i = firstadr; i < nextadr; i++) {
2645                 JCVariableDecl vardecl = vardecls[i];
2646                 VarSymbol var = vardecl.sym;
2647                 if (var.owner == classDef.sym && var.isStrictInstance()) {
2648                     checkInit(TreeInfo.diagEndPos(tree), var, Errors.StrictFieldNotHaveBeenInitializedBeforeSuper(var));
2649                 }
2650             }
2651         }
2652 
2653         public void visitNewClass(JCNewClass tree) {
2654             scanExpr(tree.encl);
2655             scanExprs(tree.args);
2656             scan(tree.def);
2657         }
2658 
2659         @Override
2660         public void visitLambda(JCLambda tree) {
2661             final Bits prevUninits = new Bits(uninits);
2662             final Bits prevUninitsTry = new Bits(uninitsTry);
2663             final Bits prevInits = new Bits(inits);
2664             int returnadrPrev = returnadr;
2665             int nextadrPrev = nextadr;
2666             ListBuffer<PendingExit> prevPending = pendingExits;
2667             try {
2668                 // JLS 16.1.10: No rule allows V to be definitely unassigned before a lambda
2669                 // body. This is by design: a variable that was definitely unassigned before the
2670                 // lambda body may end up being assigned to later on, so we cannot conclude that
2671                 // the variable will be unassigned when the body is executed.
2672                 uninits.excludeFrom(firstadr);

2700         }
2701 
2702         public void visitAssert(JCAssert tree) {
2703             final Bits initsExit = new Bits(inits);
2704             final Bits uninitsExit = new Bits(uninits);
2705             scanCond(tree.cond);
2706             uninitsExit.andSet(uninitsWhenTrue);
2707             if (tree.detail != null) {
2708                 inits.assign(initsWhenFalse);
2709                 uninits.assign(uninitsWhenFalse);
2710                 scanExpr(tree.detail);
2711             }
2712             inits.assign(initsExit);
2713             uninits.assign(uninitsExit);
2714         }
2715 
2716         public void visitAssign(JCAssign tree) {
2717             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2718                 scanExpr(tree.lhs);
2719             scanExpr(tree.rhs);
2720             letInit(tree.lhs, tree);
2721         }
2722 
2723         // check fields accessed through this.<field> are definitely
2724         // assigned before reading their value
2725         public void visitSelect(JCFieldAccess tree) {
2726             super.visitSelect(tree);
2727             if (TreeInfo.isThisQualifier(tree.selected) &&
2728                 tree.sym.kind == VAR) {
2729                 checkInit(tree.pos(), (VarSymbol)tree.sym);
2730             }
2731         }
2732 
2733         public void visitAssignop(JCAssignOp tree) {
2734             scanExpr(tree.lhs);
2735             scanExpr(tree.rhs);
2736             letInit(tree.lhs);
2737         }
2738 
2739         public void visitUnary(JCUnary tree) {
2740             switch (tree.getTag()) {
< prev index next >