< prev index next >

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

Print this page

  37 import com.sun.tools.javac.code.Scope.WriteableScope;
  38 import com.sun.tools.javac.code.Source.Feature;
  39 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  40 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  41 import com.sun.tools.javac.tree.*;
  42 import com.sun.tools.javac.tree.TreeInfo.PatternPrimaryType;
  43 import com.sun.tools.javac.util.*;
  44 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  45 import com.sun.tools.javac.util.JCDiagnostic.Error;
  46 import com.sun.tools.javac.util.JCDiagnostic.Warning;
  47 
  48 import com.sun.tools.javac.code.Symbol.*;
  49 import com.sun.tools.javac.tree.JCTree.*;
  50 
  51 import static com.sun.tools.javac.code.Flags.*;
  52 import static com.sun.tools.javac.code.Flags.BLOCK;
  53 import static com.sun.tools.javac.code.Kinds.Kind.*;
  54 import com.sun.tools.javac.code.Type.TypeVar;
  55 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
  56 import static com.sun.tools.javac.code.TypeTag.VOID;


  57 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  58 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  59 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
  60 
  61 /** This pass implements dataflow analysis for Java programs though
  62  *  different AST visitor steps. Liveness analysis (see AliveAnalyzer) checks that
  63  *  every statement is reachable. Exception analysis (see FlowAnalyzer) ensures that
  64  *  every checked exception that is thrown is declared or caught.  Definite assignment analysis
  65  *  (see AssignAnalyzer) ensures that each variable is assigned when used.  Definite
  66  *  unassignment analysis (see AssignAnalyzer) in ensures that no final variable
  67  *  is assigned more than once. Finally, local variable capture analysis (see CaptureAnalyzer)
  68  *  determines that local variables accessed within the scope of an inner class/lambda
  69  *  are either final or effectively-final.
  70  *
  71  *  <p>The JLS has a number of problems in the
  72  *  specification of these flow analysis problems. This implementation
  73  *  attempts to address those issues.
  74  *
  75  *  <p>First, there is no accommodation for a finally clause that cannot
  76  *  complete normally. For liveness analysis, an intervening finally

1292                     caught = chk.incl(ct.type, caught);
1293                 }
1294             }
1295 
1296             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1297             pendingExits = new ListBuffer<>();
1298             for (JCTree resource : tree.resources) {
1299                 if (resource instanceof JCVariableDecl variableDecl) {
1300                     visitVarDef(variableDecl);
1301                 } else if (resource instanceof JCExpression expression) {
1302                     scan(expression);
1303                 } else {
1304                     throw new AssertionError(tree);  // parser error
1305                 }
1306             }
1307             for (JCTree resource : tree.resources) {
1308                 List<Type> closeableSupertypes = resource.type.isCompound() ?
1309                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1310                     List.of(resource.type);
1311                 for (Type sup : closeableSupertypes) {
1312                     if (types.asSuper(sup, syms.autoCloseableType.tsym) != null) {
1313                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1314                                 attrEnv,
1315                                 types.skipTypeVars(sup, false),
1316                                 names.close,
1317                                 List.nil(),
1318                                 List.nil());
1319                         Type mt = types.memberType(resource.type, closeMethod);
1320                         if (closeMethod.kind == MTH) {
1321                             for (Type t : mt.getThrownTypes()) {
1322                                 markThrown(resource, t);
1323                             }
1324                         }
1325                     }
1326                 }
1327             }
1328             scan(tree.body);
1329             List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1330             thrown = thrownPrev;
1331             caught = caughtPrev;
1332 

1715             inLambda = true;
1716             try {
1717                 pendingExits = new ListBuffer<>();
1718                 caught = List.of(syms.throwableType);
1719                 thrown = List.nil();
1720                 scan(tree.body);
1721                 inferredThrownTypes = thrown;
1722             } finally {
1723                 pendingExits = prevPending;
1724                 caught = prevCaught;
1725                 thrown = prevThrown;
1726                 inLambda = false;
1727             }
1728         }
1729         @Override
1730         public void visitClassDef(JCClassDecl tree) {
1731             //skip
1732         }
1733     }
1734 








1735     /**
1736      * This pass implements (i) definite assignment analysis, which ensures that
1737      * each variable is assigned when used and (ii) definite unassignment analysis,
1738      * which ensures that no final variable is assigned more than once. This visitor
1739      * depends on the results of the liveliness analyzer. This pass is also used to mark
1740      * effectively-final local variables/parameters.
1741      */
1742 
1743     public class AssignAnalyzer extends BaseAnalyzer {
1744 
1745         /** The set of definitely assigned variables.
1746          */
1747         final Bits inits;
1748 
1749         /** The set of definitely unassigned variables.
1750          */
1751         final Bits uninits;
1752 
1753         /** The set of variables that are definitely unassigned everywhere
1754          *  in current try block. This variable is maintained lazily; it is

1803             final Bits inits;
1804             final Bits uninits;
1805             final Bits exit_inits = new Bits(true);
1806             final Bits exit_uninits = new Bits(true);
1807 
1808             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
1809                 super(tree);
1810                 this.inits = inits;
1811                 this.uninits = uninits;
1812                 this.exit_inits.assign(inits);
1813                 this.exit_uninits.assign(uninits);
1814             }
1815 
1816             @Override
1817             public void resolveJump() {
1818                 inits.andSet(exit_inits);
1819                 uninits.andSet(exit_uninits);
1820             }
1821         }
1822 



1823         public AssignAnalyzer() {
1824             this.inits = new Bits();
1825             uninits = new Bits();
1826             uninitsTry = new Bits();
1827             initsWhenTrue = new Bits(true);
1828             initsWhenFalse = new Bits(true);
1829             uninitsWhenTrue = new Bits(true);
1830             uninitsWhenFalse = new Bits(true);
1831         }
1832 
1833         private boolean isInitialConstructor = false;
1834 
1835         @Override
1836         protected void markDead() {
1837             if (!isInitialConstructor) {
1838                 inits.inclRange(returnadr, nextadr);
1839             } else {
1840                 for (int address = returnadr; address < nextadr; address++) {
1841                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
1842                         inits.incl(address);

1928                 } else {
1929                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
1930                     uninits.excl(sym.adr);
1931                 }
1932             }
1933 
1934         /** If tree is either a simple name or of the form this.name or
1935          *  C.this.name, and tree represents a trackable variable,
1936          *  record an initialization of the variable.
1937          */
1938         void letInit(JCTree tree) {
1939             tree = TreeInfo.skipParens(tree);
1940             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1941                 Symbol sym = TreeInfo.symbol(tree);
1942                 if (sym.kind == VAR) {
1943                     letInit(tree.pos(), (VarSymbol)sym);
1944                 }
1945             }
1946         }
1947 






















1948         /** Check that trackable variable is initialized.
1949          */
1950         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1951             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1952         }
1953 
1954         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1955             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1956                 trackable(sym) &&
1957                 !inits.isMember(sym.adr) &&
1958                 (sym.flags_field & CLASH) == 0) {
1959                     log.error(pos, errkey);
1960                 inits.incl(sym.adr);
1961             }
1962         }
1963 
1964         /** Utility method to reset several Bits instances.
1965          */
1966         private void resetBits(Bits... bits) {
1967             for (Bits b : bits) {

2124                     classDef = classDefPrev;
2125                 }
2126             } finally {
2127                 lint = lintPrev;
2128             }
2129         }
2130 
2131         public void visitMethodDef(JCMethodDecl tree) {
2132             if (tree.body == null) {
2133                 return;
2134             }
2135 
2136             /*  MemberEnter can generate synthetic methods ignore them
2137              */
2138             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2139                 return;
2140             }
2141 
2142             Lint lintPrev = lint;
2143             lint = lint.augment(tree.sym);

2144             try {
2145                 if (tree.body == null) {
2146                     return;
2147                 }
2148                 /*  Ignore synthetic methods, except for translated lambda methods.
2149                  */
2150                 if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
2151                     return;
2152                 }
2153 
2154                 final Bits initsPrev = new Bits(inits);
2155                 final Bits uninitsPrev = new Bits(uninits);
2156                 int nextadrPrev = nextadr;
2157                 int firstadrPrev = firstadr;
2158                 int returnadrPrev = returnadr;
2159 
2160                 Assert.check(pendingExits.isEmpty());
2161                 boolean lastInitialConstructor = isInitialConstructor;
2162                 try {
2163                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2164 
2165                     if (!isInitialConstructor) {
2166                         firstadr = nextadr;






2167                     }
2168                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2169                         JCVariableDecl def = l.head;
2170                         scan(def);
2171                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2172                         /*  If we are executing the code from Gen, then there can be
2173                          *  synthetic or mandated variables, ignore them.
2174                          */
2175                         initParam(def);
2176                     }
2177                     // else we are in an instance initializer block;
2178                     // leave caught unchanged.
2179                     scan(tree.body);
2180 
2181                     boolean isCompactConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0;
2182                     if (isInitialConstructor) {
2183                         boolean isSynthesized = (tree.sym.flags() &
2184                                                  GENERATEDCONSTR) != 0;
2185                         for (int i = firstadr; i < nextadr; i++) {
2186                             JCVariableDecl vardecl = vardecls[i];

2209                                     } else {
2210                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2211                                     }
2212                                 } else {
2213                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2214                                 }
2215                             }
2216                         }
2217                     }
2218                     clearPendingExits(true);
2219                 } finally {
2220                     inits.assign(initsPrev);
2221                     uninits.assign(uninitsPrev);
2222                     nextadr = nextadrPrev;
2223                     firstadr = firstadrPrev;
2224                     returnadr = returnadrPrev;
2225                     isInitialConstructor = lastInitialConstructor;
2226                 }
2227             } finally {
2228                 lint = lintPrev;

2229             }
2230         }
2231 
2232         private void clearPendingExits(boolean inMethod) {
2233             List<PendingExit> exits = pendingExits.toList();
2234             pendingExits = new ListBuffer<>();
2235             while (exits.nonEmpty()) {
2236                 PendingExit exit = exits.head;
2237                 exits = exits.tail;
2238                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2239                                  log.hasErrorOn(exit.tree.pos()),
2240                              exit.tree);
2241                 if (inMethod && isInitialConstructor) {
2242                     Assert.check(exit instanceof AssignPendingExit);
2243                     inits.assign(((AssignPendingExit) exit).exit_inits);
2244                     for (int i = firstadr; i < nextadr; i++) {
2245                         checkInit(exit.tree.pos(), vardecls[i].sym);
2246                     }
2247                 }
2248             }

2689 
2690         @Override
2691         public void visitContinue(JCContinue tree) {
2692             recordExit(new AssignPendingExit(tree, inits, uninits));
2693         }
2694 
2695         @Override
2696         public void visitReturn(JCReturn tree) {
2697             scanExpr(tree.expr);
2698             recordExit(new AssignPendingExit(tree, inits, uninits));
2699         }
2700 
2701         public void visitThrow(JCThrow tree) {
2702             scanExpr(tree.expr);
2703             markDead();
2704         }
2705 
2706         public void visitApply(JCMethodInvocation tree) {
2707             scanExpr(tree.meth);
2708             scanExprs(tree.args);





2709         }
2710 
2711         public void visitNewClass(JCNewClass tree) {
2712             scanExpr(tree.encl);
2713             scanExprs(tree.args);
2714             scan(tree.def);






2715         }
2716 
2717         @Override
2718         public void visitLambda(JCLambda tree) {
2719             final Bits prevUninits = new Bits(uninits);
2720             final Bits prevInits = new Bits(inits);
2721             int returnadrPrev = returnadr;
2722             int nextadrPrev = nextadr;
2723             ListBuffer<PendingExit> prevPending = pendingExits;
2724             try {
2725                 returnadr = nextadr;
2726                 pendingExits = new ListBuffer<>();
2727                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2728                     JCVariableDecl def = l.head;
2729                     scan(def);
2730                     inits.incl(def.sym.adr);
2731                     uninits.excl(def.sym.adr);
2732                 }
2733                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
2734                     scanExpr(tree.body);

2757             uninitsExit.andSet(uninitsWhenTrue);
2758             if (tree.detail != null) {
2759                 inits.assign(initsWhenFalse);
2760                 uninits.assign(uninitsWhenFalse);
2761                 scanExpr(tree.detail);
2762             }
2763             inits.assign(initsExit);
2764             uninits.assign(uninitsExit);
2765         }
2766 
2767         public void visitAssign(JCAssign tree) {
2768             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2769                 scanExpr(tree.lhs);
2770             scanExpr(tree.rhs);
2771             letInit(tree.lhs);
2772         }
2773 
2774         // check fields accessed through this.<field> are definitely
2775         // assigned before reading their value
2776         public void visitSelect(JCFieldAccess tree) {
2777             super.visitSelect(tree);







2778             if (TreeInfo.isThisQualifier(tree.selected) &&
2779                 tree.sym.kind == VAR) {
2780                 checkInit(tree.pos(), (VarSymbol)tree.sym);



2781             }
2782         }
2783 
2784         public void visitAssignop(JCAssignOp tree) {
2785             scanExpr(tree.lhs);
2786             scanExpr(tree.rhs);
2787             letInit(tree.lhs);
2788         }
2789 
2790         public void visitUnary(JCUnary tree) {
2791             switch (tree.getTag()) {
2792             case NOT:
2793                 scanCond(tree.arg);
2794                 final Bits t = new Bits(initsWhenFalse);
2795                 initsWhenFalse.assign(initsWhenTrue);
2796                 initsWhenTrue.assign(t);
2797                 t.assign(uninitsWhenFalse);
2798                 uninitsWhenFalse.assign(uninitsWhenTrue);
2799                 uninitsWhenTrue.assign(t);
2800                 break;

2824                 scanCond(tree.lhs);
2825                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
2826                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
2827                 inits.assign(initsWhenFalse);
2828                 uninits.assign(uninitsWhenFalse);
2829                 scanCond(tree.rhs);
2830                 initsWhenTrue.andSet(initsWhenTrueLeft);
2831                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
2832                 break;
2833             default:
2834                 scanExpr(tree.lhs);
2835                 scanExpr(tree.rhs);
2836             }
2837         }
2838 
2839         public void visitIdent(JCIdent tree) {
2840             if (tree.sym.kind == VAR) {
2841                 checkInit(tree.pos(), (VarSymbol)tree.sym);
2842                 referenced(tree.sym);
2843             }



2844         }
2845 
2846         @Override
2847         public void visitBindingPattern(JCBindingPattern tree) {
2848             super.visitBindingPattern(tree);
2849             initParam(tree.var);
2850         }
2851 
2852         void referenced(Symbol sym) {
2853             unrefdResources.remove(sym);
2854         }
2855 
2856         public void visitAnnotatedType(JCAnnotatedType tree) {
2857             // annotations don't get scanned
2858             tree.underlyingType.accept(this);
2859         }
2860 
2861         public void visitModuleDef(JCModuleDecl tree) {
2862             // Do nothing for modules
2863         }

  37 import com.sun.tools.javac.code.Scope.WriteableScope;
  38 import com.sun.tools.javac.code.Source.Feature;
  39 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  40 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  41 import com.sun.tools.javac.tree.*;
  42 import com.sun.tools.javac.tree.TreeInfo.PatternPrimaryType;
  43 import com.sun.tools.javac.util.*;
  44 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  45 import com.sun.tools.javac.util.JCDiagnostic.Error;
  46 import com.sun.tools.javac.util.JCDiagnostic.Warning;
  47 
  48 import com.sun.tools.javac.code.Symbol.*;
  49 import com.sun.tools.javac.tree.JCTree.*;
  50 
  51 import static com.sun.tools.javac.code.Flags.*;
  52 import static com.sun.tools.javac.code.Flags.BLOCK;
  53 import static com.sun.tools.javac.code.Kinds.Kind.*;
  54 import com.sun.tools.javac.code.Type.TypeVar;
  55 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;
  56 import static com.sun.tools.javac.code.TypeTag.VOID;
  57 import static com.sun.tools.javac.comp.Flow.ThisExposability.ALLOWED;
  58 import static com.sun.tools.javac.comp.Flow.ThisExposability.BANNED;
  59 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  60 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  61 import com.sun.tools.javac.util.JCDiagnostic.Fragment;
  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

1294                     caught = chk.incl(ct.type, caught);
1295                 }
1296             }
1297 
1298             ListBuffer<PendingExit> prevPendingExits = pendingExits;
1299             pendingExits = new ListBuffer<>();
1300             for (JCTree resource : tree.resources) {
1301                 if (resource instanceof JCVariableDecl variableDecl) {
1302                     visitVarDef(variableDecl);
1303                 } else if (resource instanceof JCExpression expression) {
1304                     scan(expression);
1305                 } else {
1306                     throw new AssertionError(tree);  // parser error
1307                 }
1308             }
1309             for (JCTree resource : tree.resources) {
1310                 List<Type> closeableSupertypes = resource.type.isCompound() ?
1311                     types.interfaces(resource.type).prepend(types.supertype(resource.type)) :
1312                     List.of(resource.type);
1313                 for (Type sup : closeableSupertypes) {
1314                     if (types.asSuper(sup.referenceProjectionOrSelf(), syms.autoCloseableType.tsym) != null) {
1315                         Symbol closeMethod = rs.resolveQualifiedMethod(tree,
1316                                 attrEnv,
1317                                 types.skipTypeVars(sup, false),
1318                                 names.close,
1319                                 List.nil(),
1320                                 List.nil());
1321                         Type mt = types.memberType(resource.type, closeMethod);
1322                         if (closeMethod.kind == MTH) {
1323                             for (Type t : mt.getThrownTypes()) {
1324                                 markThrown(resource, t);
1325                             }
1326                         }
1327                     }
1328                 }
1329             }
1330             scan(tree.body);
1331             List<Type> thrownInTry = chk.union(thrown, List.of(syms.runtimeExceptionType, syms.errorType));
1332             thrown = thrownPrev;
1333             caught = caughtPrev;
1334 

1717             inLambda = true;
1718             try {
1719                 pendingExits = new ListBuffer<>();
1720                 caught = List.of(syms.throwableType);
1721                 thrown = List.nil();
1722                 scan(tree.body);
1723                 inferredThrownTypes = thrown;
1724             } finally {
1725                 pendingExits = prevPending;
1726                 caught = prevCaught;
1727                 thrown = prevThrown;
1728                 inLambda = false;
1729             }
1730         }
1731         @Override
1732         public void visitClassDef(JCClassDecl tree) {
1733             //skip
1734         }
1735     }
1736 
1737     /** Enum to model whether constructors allowed to "leak" this reference before
1738         all instance fields are DA.
1739      */
1740     enum ThisExposability {
1741         ALLOWED,     // identity Object classes - NOP
1742         BANNED,      // primitive classes - Error
1743     }
1744 
1745     /**
1746      * This pass implements (i) definite assignment analysis, which ensures that
1747      * each variable is assigned when used and (ii) definite unassignment analysis,
1748      * which ensures that no final variable is assigned more than once. This visitor
1749      * depends on the results of the liveliness analyzer. This pass is also used to mark
1750      * effectively-final local variables/parameters.
1751      */
1752 
1753     public class AssignAnalyzer extends BaseAnalyzer {
1754 
1755         /** The set of definitely assigned variables.
1756          */
1757         final Bits inits;
1758 
1759         /** The set of definitely unassigned variables.
1760          */
1761         final Bits uninits;
1762 
1763         /** The set of variables that are definitely unassigned everywhere
1764          *  in current try block. This variable is maintained lazily; it is

1813             final Bits inits;
1814             final Bits uninits;
1815             final Bits exit_inits = new Bits(true);
1816             final Bits exit_uninits = new Bits(true);
1817 
1818             public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
1819                 super(tree);
1820                 this.inits = inits;
1821                 this.uninits = uninits;
1822                 this.exit_inits.assign(inits);
1823                 this.exit_uninits.assign(uninits);
1824             }
1825 
1826             @Override
1827             public void resolveJump() {
1828                 inits.andSet(exit_inits);
1829                 uninits.andSet(exit_uninits);
1830             }
1831         }
1832 
1833         // Are constructors allowed to leak this reference ?
1834         ThisExposability thisExposability = ALLOWED;
1835 
1836         public AssignAnalyzer() {
1837             this.inits = new Bits();
1838             uninits = new Bits();
1839             uninitsTry = new Bits();
1840             initsWhenTrue = new Bits(true);
1841             initsWhenFalse = new Bits(true);
1842             uninitsWhenTrue = new Bits(true);
1843             uninitsWhenFalse = new Bits(true);
1844         }
1845 
1846         private boolean isInitialConstructor = false;
1847 
1848         @Override
1849         protected void markDead() {
1850             if (!isInitialConstructor) {
1851                 inits.inclRange(returnadr, nextadr);
1852             } else {
1853                 for (int address = returnadr; address < nextadr; address++) {
1854                     if (!(isFinalUninitializedStaticField(vardecls[address].sym))) {
1855                         inits.incl(address);

1941                 } else {
1942                     //log.rawWarning(pos, "unreachable assignment");//DEBUG
1943                     uninits.excl(sym.adr);
1944                 }
1945             }
1946 
1947         /** If tree is either a simple name or of the form this.name or
1948          *  C.this.name, and tree represents a trackable variable,
1949          *  record an initialization of the variable.
1950          */
1951         void letInit(JCTree tree) {
1952             tree = TreeInfo.skipParens(tree);
1953             if (tree.hasTag(IDENT) || tree.hasTag(SELECT)) {
1954                 Symbol sym = TreeInfo.symbol(tree);
1955                 if (sym.kind == VAR) {
1956                     letInit(tree.pos(), (VarSymbol)sym);
1957                 }
1958             }
1959         }
1960 
1961         void checkEmbryonicThisExposure(JCTree node) {
1962             if (this.thisExposability == ALLOWED || classDef == null)
1963                 return;
1964 
1965             // Note: for non-initial constructors, firstadr is post all instance fields.
1966             for (int i = firstadr; i < nextadr; i++) {
1967                 VarSymbol sym = vardecls[i].sym;
1968                 if (sym.owner != classDef.sym)
1969                     continue;
1970                 if ((sym.flags() & (FINAL | HASINIT | STATIC | PARAMETER)) != FINAL)
1971                     continue;
1972                 if (sym.pos < startPos || sym.adr < firstadr)
1973                     continue;
1974                 if (!inits.isMember(sym.adr)) {
1975                     if (this.thisExposability == BANNED) {
1976                         log.error(node, Errors.ThisExposedPrematurely);
1977                     }
1978                     return; // don't flog a dead horse.
1979                 }
1980             }
1981         }
1982 
1983         /** Check that trackable variable is initialized.
1984          */
1985         void checkInit(DiagnosticPosition pos, VarSymbol sym) {
1986             checkInit(pos, sym, Errors.VarMightNotHaveBeenInitialized(sym));
1987         }
1988 
1989         void checkInit(DiagnosticPosition pos, VarSymbol sym, Error errkey) {
1990             if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
1991                 trackable(sym) &&
1992                 !inits.isMember(sym.adr) &&
1993                 (sym.flags_field & CLASH) == 0) {
1994                     log.error(pos, errkey);
1995                 inits.incl(sym.adr);
1996             }
1997         }
1998 
1999         /** Utility method to reset several Bits instances.
2000          */
2001         private void resetBits(Bits... bits) {
2002             for (Bits b : bits) {

2159                     classDef = classDefPrev;
2160                 }
2161             } finally {
2162                 lint = lintPrev;
2163             }
2164         }
2165 
2166         public void visitMethodDef(JCMethodDecl tree) {
2167             if (tree.body == null) {
2168                 return;
2169             }
2170 
2171             /*  MemberEnter can generate synthetic methods ignore them
2172              */
2173             if ((tree.sym.flags() & SYNTHETIC) != 0) {
2174                 return;
2175             }
2176 
2177             Lint lintPrev = lint;
2178             lint = lint.augment(tree.sym);
2179             ThisExposability priorThisExposability = this.thisExposability;
2180             try {
2181                 if (tree.body == null) {
2182                     return;
2183                 }
2184                 /*  Ignore synthetic methods, except for translated lambda methods.
2185                  */
2186                 if ((tree.sym.flags() & (SYNTHETIC | LAMBDA_METHOD)) == SYNTHETIC) {
2187                     return;
2188                 }
2189 
2190                 final Bits initsPrev = new Bits(inits);
2191                 final Bits uninitsPrev = new Bits(uninits);
2192                 int nextadrPrev = nextadr;
2193                 int firstadrPrev = firstadr;
2194                 int returnadrPrev = returnadr;
2195 
2196                 Assert.check(pendingExits.isEmpty());
2197                 boolean lastInitialConstructor = isInitialConstructor;
2198                 try {
2199                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
2200 
2201                     if (!isInitialConstructor) {
2202                         firstadr = nextadr;
2203                         this.thisExposability = ALLOWED;
2204                     } else {
2205                         if (tree.sym.owner.isPrimitiveClass())
2206                             this.thisExposability = BANNED;
2207                         else
2208                             this.thisExposability = ALLOWED;
2209                     }
2210                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2211                         JCVariableDecl def = l.head;
2212                         scan(def);
2213                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2214                         /*  If we are executing the code from Gen, then there can be
2215                          *  synthetic or mandated variables, ignore them.
2216                          */
2217                         initParam(def);
2218                     }
2219                     // else we are in an instance initializer block;
2220                     // leave caught unchanged.
2221                     scan(tree.body);
2222 
2223                     boolean isCompactConstructor = (tree.sym.flags() & Flags.COMPACT_RECORD_CONSTRUCTOR) != 0;
2224                     if (isInitialConstructor) {
2225                         boolean isSynthesized = (tree.sym.flags() &
2226                                                  GENERATEDCONSTR) != 0;
2227                         for (int i = firstadr; i < nextadr; i++) {
2228                             JCVariableDecl vardecl = vardecls[i];

2251                                     } else {
2252                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl), var);
2253                                     }
2254                                 } else {
2255                                     checkInit(TreeInfo.diagEndPos(tree.body), var);
2256                                 }
2257                             }
2258                         }
2259                     }
2260                     clearPendingExits(true);
2261                 } finally {
2262                     inits.assign(initsPrev);
2263                     uninits.assign(uninitsPrev);
2264                     nextadr = nextadrPrev;
2265                     firstadr = firstadrPrev;
2266                     returnadr = returnadrPrev;
2267                     isInitialConstructor = lastInitialConstructor;
2268                 }
2269             } finally {
2270                 lint = lintPrev;
2271                 this.thisExposability = priorThisExposability;
2272             }
2273         }
2274 
2275         private void clearPendingExits(boolean inMethod) {
2276             List<PendingExit> exits = pendingExits.toList();
2277             pendingExits = new ListBuffer<>();
2278             while (exits.nonEmpty()) {
2279                 PendingExit exit = exits.head;
2280                 exits = exits.tail;
2281                 Assert.check((inMethod && exit.tree.hasTag(RETURN)) ||
2282                                  log.hasErrorOn(exit.tree.pos()),
2283                              exit.tree);
2284                 if (inMethod && isInitialConstructor) {
2285                     Assert.check(exit instanceof AssignPendingExit);
2286                     inits.assign(((AssignPendingExit) exit).exit_inits);
2287                     for (int i = firstadr; i < nextadr; i++) {
2288                         checkInit(exit.tree.pos(), vardecls[i].sym);
2289                     }
2290                 }
2291             }

2732 
2733         @Override
2734         public void visitContinue(JCContinue tree) {
2735             recordExit(new AssignPendingExit(tree, inits, uninits));
2736         }
2737 
2738         @Override
2739         public void visitReturn(JCReturn tree) {
2740             scanExpr(tree.expr);
2741             recordExit(new AssignPendingExit(tree, inits, uninits));
2742         }
2743 
2744         public void visitThrow(JCThrow tree) {
2745             scanExpr(tree.expr);
2746             markDead();
2747         }
2748 
2749         public void visitApply(JCMethodInvocation tree) {
2750             scanExpr(tree.meth);
2751             scanExprs(tree.args);
2752             if (tree.meth.hasTag(IDENT)) {
2753                 JCIdent ident = (JCIdent) tree.meth;
2754                 if (ident.name != names._super && !ident.sym.isStatic())
2755                     checkEmbryonicThisExposure(tree);
2756             }
2757         }
2758 
2759         public void visitNewClass(JCNewClass tree) {
2760             scanExpr(tree.encl);
2761             scanExprs(tree.args);
2762             scan(tree.def);
2763             if (classDef != null && tree.encl == null && tree.clazz.hasTag(IDENT)) {
2764                 JCIdent clazz = (JCIdent) tree.clazz;
2765                 if (!clazz.sym.isStatic() && clazz.type.getEnclosingType().tsym == classDef.sym) {
2766                     checkEmbryonicThisExposure(tree);
2767                 }
2768             }
2769         }
2770 
2771         @Override
2772         public void visitLambda(JCLambda tree) {
2773             final Bits prevUninits = new Bits(uninits);
2774             final Bits prevInits = new Bits(inits);
2775             int returnadrPrev = returnadr;
2776             int nextadrPrev = nextadr;
2777             ListBuffer<PendingExit> prevPending = pendingExits;
2778             try {
2779                 returnadr = nextadr;
2780                 pendingExits = new ListBuffer<>();
2781                 for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2782                     JCVariableDecl def = l.head;
2783                     scan(def);
2784                     inits.incl(def.sym.adr);
2785                     uninits.excl(def.sym.adr);
2786                 }
2787                 if (tree.getBodyKind() == JCLambda.BodyKind.EXPRESSION) {
2788                     scanExpr(tree.body);

2811             uninitsExit.andSet(uninitsWhenTrue);
2812             if (tree.detail != null) {
2813                 inits.assign(initsWhenFalse);
2814                 uninits.assign(uninitsWhenFalse);
2815                 scanExpr(tree.detail);
2816             }
2817             inits.assign(initsExit);
2818             uninits.assign(uninitsExit);
2819         }
2820 
2821         public void visitAssign(JCAssign tree) {
2822             if (!TreeInfo.isIdentOrThisDotIdent(tree.lhs))
2823                 scanExpr(tree.lhs);
2824             scanExpr(tree.rhs);
2825             letInit(tree.lhs);
2826         }
2827 
2828         // check fields accessed through this.<field> are definitely
2829         // assigned before reading their value
2830         public void visitSelect(JCFieldAccess tree) {
2831             ThisExposability priorThisExposability = this.thisExposability;
2832             try {
2833                 if (tree.name == names._this && classDef != null && tree.sym.owner == classDef.sym) {
2834                     checkEmbryonicThisExposure(tree);
2835                 } else if (tree.sym.kind == VAR || tree.sym.isStatic()) {
2836                     this.thisExposability = ALLOWED;
2837                 }
2838                 super.visitSelect(tree);
2839             if (TreeInfo.isThisQualifier(tree.selected) &&
2840                 tree.sym.kind == VAR) {
2841                     checkInit(tree.pos(), (VarSymbol)tree.sym);
2842                 }
2843             } finally {
2844                  this.thisExposability = priorThisExposability;
2845             }
2846         }
2847 
2848         public void visitAssignop(JCAssignOp tree) {
2849             scanExpr(tree.lhs);
2850             scanExpr(tree.rhs);
2851             letInit(tree.lhs);
2852         }
2853 
2854         public void visitUnary(JCUnary tree) {
2855             switch (tree.getTag()) {
2856             case NOT:
2857                 scanCond(tree.arg);
2858                 final Bits t = new Bits(initsWhenFalse);
2859                 initsWhenFalse.assign(initsWhenTrue);
2860                 initsWhenTrue.assign(t);
2861                 t.assign(uninitsWhenFalse);
2862                 uninitsWhenFalse.assign(uninitsWhenTrue);
2863                 uninitsWhenTrue.assign(t);
2864                 break;

2888                 scanCond(tree.lhs);
2889                 final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
2890                 final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
2891                 inits.assign(initsWhenFalse);
2892                 uninits.assign(uninitsWhenFalse);
2893                 scanCond(tree.rhs);
2894                 initsWhenTrue.andSet(initsWhenTrueLeft);
2895                 uninitsWhenTrue.andSet(uninitsWhenTrueLeft);
2896                 break;
2897             default:
2898                 scanExpr(tree.lhs);
2899                 scanExpr(tree.rhs);
2900             }
2901         }
2902 
2903         public void visitIdent(JCIdent tree) {
2904             if (tree.sym.kind == VAR) {
2905                 checkInit(tree.pos(), (VarSymbol)tree.sym);
2906                 referenced(tree.sym);
2907             }
2908             if (tree.name == names._this) {
2909                 checkEmbryonicThisExposure(tree);
2910             }
2911         }
2912 
2913         @Override
2914         public void visitBindingPattern(JCBindingPattern tree) {
2915             super.visitBindingPattern(tree);
2916             initParam(tree.var);
2917         }
2918 
2919         void referenced(Symbol sym) {
2920             unrefdResources.remove(sym);
2921         }
2922 
2923         public void visitAnnotatedType(JCAnnotatedType tree) {
2924             // annotations don't get scanned
2925             tree.underlyingType.accept(this);
2926         }
2927 
2928         public void visitModuleDef(JCModuleDecl tree) {
2929             // Do nothing for modules
2930         }
< prev index next >