< 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

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

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



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

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






















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

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

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






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

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

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

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





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






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

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







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



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

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



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

  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

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

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

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

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

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

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

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

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

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