< prev index next >
src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java
Print this page
rev 51258 : imported patch switch.diff
*** 26,35 ****
--- 26,37 ----
//todo: one might eliminate uninits.andSets when monotonic
package com.sun.tools.javac.comp;
import java.util.HashMap;
+ import java.util.HashSet;
+ import java.util.Set;
import com.sun.source.tree.LambdaExpressionTree.BodyKind;
import com.sun.tools.javac.code.*;
import com.sun.tools.javac.code.Scope.WriteableScope;
import com.sun.tools.javac.code.Source.Feature;
*** 209,219 ****
return instance;
}
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
new AliveAnalyzer().analyzeTree(env, make);
! new AssignAnalyzer().analyzeTree(env);
new FlowAnalyzer().analyzeTree(env, make);
new CaptureAnalyzer().analyzeTree(env, make);
}
public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
--- 211,221 ----
return instance;
}
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
new AliveAnalyzer().analyzeTree(env, make);
! new AssignAnalyzer().analyzeTree(env, make);
new FlowAnalyzer().analyzeTree(env, make);
new CaptureAnalyzer().analyzeTree(env, make);
}
public void analyzeLambda(Env<AttrContext> env, JCLambda that, TreeMaker make, boolean speculative) {
*** 242,252 ****
//message will be reported and will cause compilation to skip the flow analyis
//step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
//related errors, which will allow for more errors to be detected
Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
try {
! new LambdaAssignAnalyzer(env).analyzeTree(env, that);
LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
flowAnalyzer.analyzeTree(env, that, make);
return flowAnalyzer.inferredThrownTypes;
} finally {
log.popDiagnosticHandler(diagHandler);
--- 244,254 ----
//message will be reported and will cause compilation to skip the flow analyis
//step - if we suppress diagnostics, we won't stop at Attr for flow-analysis
//related errors, which will allow for more errors to be detected
Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
try {
! new LambdaAssignAnalyzer(env).analyzeTree(env, that, make);
LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
flowAnalyzer.analyzeTree(env, that, make);
return flowAnalyzer.inferredThrownTypes;
} finally {
log.popDiagnosticHandler(diagHandler);
*** 394,403 ****
--- 396,411 ----
}
public void visitPackageDef(JCPackageDecl tree) {
// Do nothing for PackageDecl
}
+
+ protected void scanSyntheticBreak(TreeMaker make, JCTree swtch) {
+ JCBreak brk = make.at(Position.NOPOS).Break(null);
+ brk.target = swtch;
+ scan(brk);
+ }
}
/**
* This pass implements the first step of the dataflow analysis, namely
* the liveness analysis check. This checks that every statement is reachable.
*** 594,608 ****
scan(tree.selector);
boolean hasDefault = false;
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
alive = true;
JCCase c = l.head;
! if (c.pat == null)
hasDefault = true;
! else
! scan(c.pat);
scanStats(c.stats);
// Warn about fall-through if lint switch fallthrough enabled.
if (alive &&
lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
c.stats.nonEmpty() && l.tail.nonEmpty())
log.warning(Lint.LintCategory.FALLTHROUGH,
--- 602,624 ----
scan(tree.selector);
boolean hasDefault = false;
for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
alive = true;
JCCase c = l.head;
! if (c.pats.isEmpty())
hasDefault = true;
! else {
! for (JCExpression pat : c.pats) {
! scan(pat);
! }
! }
scanStats(c.stats);
+ c.completesNormally = alive;
+ if (alive && c.caseKind == JCCase.RULE) {
+ scanSyntheticBreak(make, tree);
+ alive = false;
+ }
// Warn about fall-through if lint switch fallthrough enabled.
if (alive &&
lint.isEnabled(Lint.LintCategory.FALLTHROUGH) &&
c.stats.nonEmpty() && l.tail.nonEmpty())
log.warning(Lint.LintCategory.FALLTHROUGH,
*** 613,622 ****
--- 629,678 ----
alive = true;
}
alive |= resolveBreaks(tree, prevPendingExits);
}
+ @Override
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ ListBuffer<PendingExit> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<>();
+ scan(tree.selector);
+ Set<Object> constants = null;
+ if ((tree.selector.type.tsym.flags() & ENUM) != 0) {
+ constants = new HashSet<>();
+ for (Symbol s : tree.selector.type.tsym.members().getSymbols(s -> (s.flags() & ENUM) != 0)) {
+ constants.add(s.name);
+ }
+ }
+ boolean hasDefault = false;
+ boolean prevAlive = alive;
+ for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+ alive = true;
+ JCCase c = l.head;
+ if (c.pats.isEmpty())
+ hasDefault = true;
+ else {
+ for (JCExpression pat : c.pats) {
+ scan(pat);
+ if (constants != null) {
+ if (pat.hasTag(IDENT))
+ constants.remove(((JCIdent) pat).name);
+ if (pat.type != null)
+ constants.remove(pat.type.constValue());
+ }
+ }
+ }
+ scanStats(c.stats);
+ c.completesNormally = alive;
+ }
+ if ((constants == null || !constants.isEmpty()) && !hasDefault) {
+ log.error(tree, Errors.NotExhaustive);
+ }
+ alive = prevAlive;
+ alive |= resolveBreaks(tree, prevPendingExits);
+ }
+
public void visitTry(JCTry tree) {
ListBuffer<PendingExit> prevPendingExits = pendingExits;
pendingExits = new ListBuffer<>();
for (JCTree resource : tree.resources) {
if (resource instanceof JCVariableDecl) {
*** 678,687 ****
--- 734,745 ----
alive = true;
}
}
public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ scan(tree.value);
recordExit(new PendingExit(tree));
}
public void visitContinue(JCContinue tree) {
recordExit(new PendingExit(tree));
*** 1038,1055 ****
scan(tree.body);
resolveBreaks(tree, prevPendingExits);
}
public void visitSwitch(JCSwitch tree) {
ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
pendingExits = new ListBuffer<>();
! scan(tree.selector);
! for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
JCCase c = l.head;
! if (c.pat != null) {
! scan(c.pat);
! }
scan(c.stats);
}
resolveBreaks(tree, prevPendingExits);
}
--- 1096,1120 ----
scan(tree.body);
resolveBreaks(tree, prevPendingExits);
}
public void visitSwitch(JCSwitch tree) {
+ handleSwitch(tree, tree.selector, tree.cases);
+ }
+
+ @Override
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ handleSwitch(tree, tree.selector, tree.cases);
+ }
+
+ private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
ListBuffer<FlowPendingExit> prevPendingExits = pendingExits;
pendingExits = new ListBuffer<>();
! scan(selector);
! for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
JCCase c = l.head;
! scan(c.pats);
scan(c.stats);
}
resolveBreaks(tree, prevPendingExits);
}
*** 1189,1198 ****
--- 1254,1265 ----
return exc.tsym == syms.throwableType.tsym ||
exc.tsym == syms.exceptionType.tsym;
}
public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ scan(tree.value);
recordExit(new FlowPendingExit(tree, null));
}
public void visitContinue(JCContinue tree) {
recordExit(new FlowPendingExit(tree, null));
*** 2103,2133 ****
scan(tree.body);
resolveBreaks(tree, prevPendingExits);
}
public void visitSwitch(JCSwitch tree) {
ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
pendingExits = new ListBuffer<>();
int nextadrPrev = nextadr;
! scanExpr(tree.selector);
final Bits initsSwitch = new Bits(inits);
final Bits uninitsSwitch = new Bits(uninits);
boolean hasDefault = false;
! for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
inits.assign(initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
JCCase c = l.head;
! if (c.pat == null) {
hasDefault = true;
} else {
! scanExpr(c.pat);
}
if (hasDefault) {
inits.assign(initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
}
scan(c.stats);
addVars(c.stats, initsSwitch, uninitsSwitch);
if (!hasDefault) {
inits.assign(initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
}
--- 2170,2213 ----
scan(tree.body);
resolveBreaks(tree, prevPendingExits);
}
public void visitSwitch(JCSwitch tree) {
+ handleSwitch(tree, tree.selector, tree.cases);
+ }
+
+ public void visitSwitchExpression(JCSwitchExpression tree) {
+ handleSwitch(tree, tree.selector, tree.cases);
+ }
+
+ private void handleSwitch(JCTree tree, JCExpression selector, List<JCCase> cases) {
ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
pendingExits = new ListBuffer<>();
int nextadrPrev = nextadr;
! scanExpr(selector);
final Bits initsSwitch = new Bits(inits);
final Bits uninitsSwitch = new Bits(uninits);
boolean hasDefault = false;
! for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
inits.assign(initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
JCCase c = l.head;
! if (c.pats.isEmpty()) {
hasDefault = true;
} else {
! for (JCExpression pat : c.pats) {
! scanExpr(pat);
! }
}
if (hasDefault) {
inits.assign(initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
}
scan(c.stats);
+ if (c.completesNormally && c.caseKind == JCCase.RULE) {
+ scanSyntheticBreak(make, tree);
+ }
addVars(c.stats, initsSwitch, uninitsSwitch);
if (!hasDefault) {
inits.assign(initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
}
*** 2299,2308 ****
--- 2379,2390 ----
}
}
@Override
public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ scan(tree.value);
recordExit(new AssignPendingExit(tree, inits, uninits));
}
@Override
public void visitContinue(JCContinue tree) {
*** 2477,2501 ****
* main method
*************************************************************************/
/** Perform definite assignment/unassignment analysis on a tree.
*/
! public void analyzeTree(Env<?> env) {
! analyzeTree(env, env.tree);
}
! public void analyzeTree(Env<?> env, JCTree tree) {
try {
startPos = tree.pos().getStartPosition();
if (vardecls == null)
vardecls = new JCVariableDecl[32];
else
for (int i=0; i<vardecls.length; i++)
vardecls[i] = null;
firstadr = 0;
nextadr = 0;
pendingExits = new ListBuffer<>();
this.classDef = null;
unrefdResources = WriteableScope.create(env.enclClass.sym);
scan(tree);
} finally {
--- 2559,2584 ----
* main method
*************************************************************************/
/** Perform definite assignment/unassignment analysis on a tree.
*/
! public void analyzeTree(Env<?> env, TreeMaker make) {
! analyzeTree(env, env.tree, make);
}
! public void analyzeTree(Env<?> env, JCTree tree, TreeMaker make) {
try {
startPos = tree.pos().getStartPosition();
if (vardecls == null)
vardecls = new JCVariableDecl[32];
else
for (int i=0; i<vardecls.length; i++)
vardecls[i] = null;
firstadr = 0;
nextadr = 0;
+ Flow.this.make = make;
pendingExits = new ListBuffer<>();
this.classDef = null;
unrefdResources = WriteableScope.create(env.enclClass.sym);
scan(tree);
} finally {
*** 2507,2516 ****
--- 2590,2600 ----
for (int i=0; i<vardecls.length; i++)
vardecls[i] = null;
}
firstadr = 0;
nextadr = 0;
+ Flow.this.make = null;
pendingExits = null;
this.classDef = null;
unrefdResources = null;
}
}
*** 2659,2668 ****
--- 2743,2758 ----
}
}
super.visitTry(tree);
}
+ @Override
+ public void visitBreak(JCBreak tree) {
+ if (tree.isValueBreak())
+ scan(tree.value);
+ }
+
public void visitModuleDef(JCModuleDecl tree) {
// Do nothing for modules
}
/**************************************************************************
< prev index next >