< prev index next >

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

Print this page




  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 //todo: one might eliminate uninits.andSets when monotonic
  27 
  28 package com.sun.tools.javac.comp;
  29 
  30 import java.util.HashMap;
  31 import java.util.HashSet;
  32 import java.util.Set;

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


 238     }
 239 
 240     public List<Type> analyzeLambdaThrownTypes(final Env<AttrContext> env,
 241             JCLambda that, TreeMaker make) {
 242         //we need to disable diagnostics temporarily; the problem is that if
 243         //a lambda expression contains e.g. an unreachable statement, an error
 244         //message will be reported and will cause compilation to skip the flow analyis
 245         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
 246         //related errors, which will allow for more errors to be detected
 247         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
 248         try {
 249             new LambdaAssignAnalyzer(env).analyzeTree(env, that, make);
 250             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
 251             flowAnalyzer.analyzeTree(env, that, make);
 252             return flowAnalyzer.inferredThrownTypes;
 253         } finally {
 254             log.popDiagnosticHandler(diagHandler);
 255         }
 256     }
 257 








































 258     /**
 259      * Definite assignment scan mode
 260      */
 261     enum FlowKind {
 262         /**
 263          * This is the normal DA/DU analysis mode
 264          */
 265         NORMAL("var.might.already.be.assigned", false),
 266         /**
 267          * This is the speculative DA/DU analysis mode used to speculatively
 268          * derive assertions within loop bodies
 269          */
 270         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
 271 
 272         final String errKey;
 273         final boolean isFinal;
 274 
 275         FlowKind(String errKey, boolean isFinal) {
 276             this.errKey = errKey;
 277             this.isFinal = isFinal;


1450         @Override
1451         public void visitLambda(JCLambda tree) {
1452             if (inLambda || tree.getBodyKind() == BodyKind.EXPRESSION) {
1453                 return;
1454             }
1455             inLambda = true;
1456             try {
1457                 super.visitLambda(tree);
1458             } finally {
1459                 inLambda = false;
1460             }
1461         }
1462 
1463         @Override
1464         public void visitClassDef(JCClassDecl tree) {
1465             //skip
1466         }
1467     }
1468 
1469     /**













1470      * Specialized pass that performs DA/DU on a lambda
1471      */
1472     class LambdaAssignAnalyzer extends AssignAnalyzer {
1473         WriteableScope enclosedSymbols;
1474         boolean inLambda;
1475 
1476         LambdaAssignAnalyzer(Env<AttrContext> env) {
1477             enclosedSymbols = WriteableScope.create(env.enclClass.sym);
1478         }
1479 
1480         @Override
1481         public void visitLambda(JCLambda tree) {
1482             if (inLambda) {
1483                 return;
1484             }
1485             inLambda = true;
1486             try {
1487                 super.visitLambda(tree);
1488             } finally {
1489                 inLambda = false;


1971 
1972                     if (!isInitialConstructor) {
1973                         firstadr = nextadr;
1974                     }
1975                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
1976                         JCVariableDecl def = l.head;
1977                         scan(def);
1978                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
1979                         /*  If we are executing the code from Gen, then there can be
1980                          *  synthetic or mandated variables, ignore them.
1981                          */
1982                         initParam(def);
1983                     }
1984                     // else we are in an instance initializer block;
1985                     // leave caught unchanged.
1986                     scan(tree.body);
1987 
1988                     if (isInitialConstructor) {
1989                         boolean isSynthesized = (tree.sym.flags() &
1990                                                  GENERATEDCONSTR) != 0;
1991                         for (int i = firstadr; i < nextadr; i++) {
1992                             JCVariableDecl vardecl = vardecls[i];
1993                             VarSymbol var = vardecl.sym;
1994                             if (var.owner == classDef.sym) {
1995                                 // choose the diagnostic position based on whether
1996                                 // the ctor is default(synthesized) or not
1997                                 if (isSynthesized) {
1998                                     checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
1999                                         var, Errors.VarNotInitializedInDefaultConstructor(var));
2000                                 } else {
2001                                     checkInit(TreeInfo.diagEndPos(tree.body), var);




2002                                 }
2003                             }
2004                         }
2005                     }
2006                     List<PendingExit> exits = pendingExits.toList();
2007                     pendingExits = new ListBuffer<>();
2008                     while (exits.nonEmpty()) {
2009                         PendingExit exit = exits.head;
2010                         exits = exits.tail;
2011                         Assert.check(exit.tree.hasTag(RETURN) ||
2012                                          log.hasErrorOn(exit.tree.pos()),
2013                                      exit.tree);
2014                         if (isInitialConstructor) {
2015                             Assert.check(exit instanceof AssignPendingExit);
2016                             inits.assign(((AssignPendingExit) exit).exit_inits);
2017                             for (int i = firstadr; i < nextadr; i++) {
2018                                 checkInit(exit.tree.pos(), vardecls[i].sym);
2019                             }
2020                         }
2021                     }




  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 //todo: one might eliminate uninits.andSets when monotonic
  27 
  28 package com.sun.tools.javac.comp;
  29 
  30 import java.util.HashMap;
  31 import java.util.HashSet;
  32 import java.util.Set;
  33 import java.util.stream.Collectors;
  34 
  35 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
  36 import com.sun.tools.javac.code.*;
  37 import com.sun.tools.javac.code.Scope.WriteableScope;
  38 import com.sun.tools.javac.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.util.*;
  43 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  44 import com.sun.tools.javac.util.JCDiagnostic.Error;
  45 import com.sun.tools.javac.util.JCDiagnostic.Warning;
  46 
  47 import com.sun.tools.javac.code.Symbol.*;
  48 import com.sun.tools.javac.tree.JCTree.*;
  49 
  50 import static com.sun.tools.javac.code.Flags.*;
  51 import static com.sun.tools.javac.code.Flags.BLOCK;
  52 import static com.sun.tools.javac.code.Kinds.Kind.*;
  53 import static com.sun.tools.javac.code.TypeTag.BOOLEAN;


 239     }
 240 
 241     public List<Type> analyzeLambdaThrownTypes(final Env<AttrContext> env,
 242             JCLambda that, TreeMaker make) {
 243         //we need to disable diagnostics temporarily; the problem is that if
 244         //a lambda expression contains e.g. an unreachable statement, an error
 245         //message will be reported and will cause compilation to skip the flow analyis
 246         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
 247         //related errors, which will allow for more errors to be detected
 248         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
 249         try {
 250             new LambdaAssignAnalyzer(env).analyzeTree(env, that, make);
 251             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
 252             flowAnalyzer.analyzeTree(env, that, make);
 253             return flowAnalyzer.inferredThrownTypes;
 254         } finally {
 255             log.popDiagnosticHandler(diagHandler);
 256         }
 257     }
 258 
 259     public boolean aliveAfter(Env<AttrContext> env, JCTree that, TreeMaker make) {
 260         //we need to disable diagnostics temporarily; the problem is that if
 261         //"that" contains e.g. an unreachable statement, an error
 262         //message will be reported and will cause compilation to skip the flow analyis
 263         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
 264         //related errors, which will allow for more errors to be detected
 265         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
 266         try {
 267             SnippetAliveAnalyzer analyzer = new SnippetAliveAnalyzer();
 268 
 269             analyzer.analyzeTree(env, that, make);
 270             return analyzer.isAlive();
 271         } finally {
 272             log.popDiagnosticHandler(diagHandler);
 273         }
 274     }
 275 
 276     public boolean breaksOutOf(Env<AttrContext> env, JCTree loop, JCTree body, TreeMaker make) {
 277         //we need to disable diagnostics temporarily; the problem is that if
 278         //"that" contains e.g. an unreachable statement, an error
 279         //message will be reported and will cause compilation to skip the flow analyis
 280         //step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
 281         //related errors, which will allow for more errors to be detected
 282         Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
 283         try {
 284             boolean[] breaksOut = new boolean[1];
 285             new AliveAnalyzer() {
 286                 @Override
 287                 public void visitBreak(JCBreak tree) {
 288                     breaksOut[0] |= (super.alive == Liveness.ALIVE && tree.target == loop);
 289                     super.visitBreak(tree);
 290                 }
 291             }.analyzeTree(env, body, make);
 292 
 293             return breaksOut[0];
 294         } finally {
 295             log.popDiagnosticHandler(diagHandler);
 296         }
 297     }
 298 
 299     /**
 300      * Definite assignment scan mode
 301      */
 302     enum FlowKind {
 303         /**
 304          * This is the normal DA/DU analysis mode
 305          */
 306         NORMAL("var.might.already.be.assigned", false),
 307         /**
 308          * This is the speculative DA/DU analysis mode used to speculatively
 309          * derive assertions within loop bodies
 310          */
 311         SPECULATIVE_LOOP("var.might.be.assigned.in.loop", true);
 312 
 313         final String errKey;
 314         final boolean isFinal;
 315 
 316         FlowKind(String errKey, boolean isFinal) {
 317             this.errKey = errKey;
 318             this.isFinal = isFinal;


1491         @Override
1492         public void visitLambda(JCLambda tree) {
1493             if (inLambda || tree.getBodyKind() == BodyKind.EXPRESSION) {
1494                 return;
1495             }
1496             inLambda = true;
1497             try {
1498                 super.visitLambda(tree);
1499             } finally {
1500                 inLambda = false;
1501             }
1502         }
1503 
1504         @Override
1505         public void visitClassDef(JCClassDecl tree) {
1506             //skip
1507         }
1508     }
1509 
1510     /**
1511      * Determine if alive after the given tree.
1512      */
1513     class SnippetAliveAnalyzer extends AliveAnalyzer {
1514         @Override
1515         public void visitClassDef(JCClassDecl tree) {
1516             //skip
1517         }
1518         public boolean isAlive() {
1519             return super.alive != Liveness.DEAD;
1520         }
1521     }
1522 
1523     /**
1524      * Specialized pass that performs DA/DU on a lambda
1525      */
1526     class LambdaAssignAnalyzer extends AssignAnalyzer {
1527         WriteableScope enclosedSymbols;
1528         boolean inLambda;
1529 
1530         LambdaAssignAnalyzer(Env<AttrContext> env) {
1531             enclosedSymbols = WriteableScope.create(env.enclClass.sym);
1532         }
1533 
1534         @Override
1535         public void visitLambda(JCLambda tree) {
1536             if (inLambda) {
1537                 return;
1538             }
1539             inLambda = true;
1540             try {
1541                 super.visitLambda(tree);
1542             } finally {
1543                 inLambda = false;


2025 
2026                     if (!isInitialConstructor) {
2027                         firstadr = nextadr;
2028                     }
2029                     for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
2030                         JCVariableDecl def = l.head;
2031                         scan(def);
2032                         Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
2033                         /*  If we are executing the code from Gen, then there can be
2034                          *  synthetic or mandated variables, ignore them.
2035                          */
2036                         initParam(def);
2037                     }
2038                     // else we are in an instance initializer block;
2039                     // leave caught unchanged.
2040                     scan(tree.body);
2041 
2042                     if (isInitialConstructor) {
2043                         boolean isSynthesized = (tree.sym.flags() &
2044                                                  GENERATEDCONSTR) != 0;
2045                         boolean isRecord = (tree.sym.owner.flags() & Flags.RECORD) != 0;
2046                         // skip record as they are generated by the compiler and guaranteed to be correct
2047                         if (!isRecord || !isSynthesized) {
2048                             for (int i = firstadr; i < nextadr; i++) {
2049                                 JCVariableDecl vardecl = vardecls[i];
2050                                 VarSymbol var = vardecl.sym;
2051                                 if (var.owner == classDef.sym) {
2052                                     // choose the diagnostic position based on whether
2053                                     // the ctor is default(synthesized) or not
2054                                     if (isSynthesized) {
2055                                         checkInit(TreeInfo.diagnosticPositionFor(var, vardecl),
2056                                             var, Errors.VarNotInitializedInDefaultConstructor(var));
2057                                     } else {
2058                                         checkInit(TreeInfo.diagEndPos(tree.body), var);
2059                                     }
2060                                 }
2061                             }
2062                         }
2063                     }
2064                     List<PendingExit> exits = pendingExits.toList();
2065                     pendingExits = new ListBuffer<>();
2066                     while (exits.nonEmpty()) {
2067                         PendingExit exit = exits.head;
2068                         exits = exits.tail;
2069                         Assert.check(exit.tree.hasTag(RETURN) ||
2070                                          log.hasErrorOn(exit.tree.pos()),
2071                                      exit.tree);
2072                         if (isInitialConstructor) {
2073                             Assert.check(exit instanceof AssignPendingExit);
2074                             inits.assign(((AssignPendingExit) exit).exit_inits);
2075                             for (int i = firstadr; i < nextadr; i++) {
2076                                 checkInit(exit.tree.pos(), vardecls[i].sym);
2077                             }
2078                         }
2079                     }


< prev index next >