--- a/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Sat Sep 14 15:23:21 2013 +0100
+++ b/langtools/src/share/classes/com/sun/tools/javac/comp/Flow.java Sat Sep 14 19:04:47 2013 +0100
@@ -207,7 +207,7 @@
public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
new AliveAnalyzer().analyzeTree(env, make);
- new AssignAnalyzer().analyzeTree(env, make);
+ new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
new FlowAnalyzer().analyzeTree(env, make);
new CaptureAnalyzer().analyzeTree(env, make);
}
@@ -239,7 +239,7 @@
//related errors, which will allow for more errors to be detected
Log.DiagnosticHandler diagHandler = new Log.DiscardDiagnosticHandler(log);
try {
- new AssignAnalyzer().analyzeTree(env, that, make);
+ new AssignAnalyzer(log, syms, lint, names).analyzeTree(env);
LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
flowAnalyzer.analyzeTree(env, that, make);
return flowAnalyzer.inferredThrownTypes;
@@ -292,15 +292,6 @@
}
/**
- * Utility method to reset several Bits instances.
- */
- private void resetBits(Bits... bits) {
- for (Bits b : bits) {
- b.reset();
- }
- }
-
- /**
* Base visitor class for all visitors implementing dataflow analysis logic.
* This class define the shared logic for handling jumps (break/continue statements).
*/
@@ -347,17 +338,17 @@
this.tree = tree;
}
- void resolveJump() {
+ void resolveJump(JCTree tree) {
//do nothing
}
}
- abstract void markDead();
+ abstract void markDead(JCTree tree);
/** Record an outward transfer of control. */
void recordExit(JCTree tree, P pe) {
pendingExits.append(pe);
- markDead();
+ markDead(tree);
}
/** Resolve all jumps of this statement. */
@@ -371,7 +362,7 @@
P exit = exits.head;
if (exit.tree.hasTag(jk.treeTag) &&
jk.getTarget(exit.tree) == tree) {
- exit.resolveJump();
+ exit.resolveJump(tree);
resolved = true;
} else {
pendingExits.append(exit);
@@ -380,12 +371,12 @@
return resolved;
}
- /** Resolve all breaks of this statement. */
+ /** Resolve all continues of this statement. */
boolean resolveContinues(JCTree tree) {
return resolveJump(tree, new ListBuffer<P>(), JumpKind.CONTINUE);
}
- /** Resolve all continues of this statement. */
+ /** Resolve all breaks of this statement. */
boolean resolveBreaks(JCTree tree, ListBuffer<P> oldPendingExits) {
return resolveJump(tree, oldPendingExits, JumpKind.BREAK);
}
@@ -414,7 +405,7 @@
private boolean alive;
@Override
- void markDead() {
+ void markDead(JCTree tree) {
alive = false;
}
@@ -696,7 +687,7 @@
public void visitThrow(JCThrow tree) {
scan(tree.expr);
- markDead();
+ markDead(tree);
}
public void visitApply(JCMethodInvocation tree) {
@@ -797,7 +788,7 @@
}
@Override
- void markDead() {
+ void markDead(JCTree tree) {
//do nothing
}
@@ -1222,7 +1213,7 @@
else {
markThrown(tree, tree.expr.type);
}
- markDead();
+ markDead(tree);
}
public void visitApply(JCMethodInvocation tree) {
@@ -1372,11 +1363,13 @@
* depends on the results of the liveliness analyzer. This pass is also used to mark
* effectively-final local variables/parameters.
*/
- class AssignAnalyzer extends BaseAnalyzer<AssignAnalyzer.AssignPendingExit> {
+
+ public abstract static class AbstractAssignAnalyzer<P extends AbstractAssignAnalyzer.AbstractAssignPendingExit>
+ extends BaseAnalyzer<P> {
/** The set of definitely assigned variables.
*/
- final Bits inits;
+ protected final Bits inits;
/** The set of definitely unassigned variables.
*/
@@ -1402,7 +1395,7 @@
/** A mapping from addresses to variable symbols.
*/
- JCVariableDecl[] vardecls;
+ protected JCVariableDecl[] vardecls;
/** The current class being defined.
*/
@@ -1414,11 +1407,11 @@
/** The next available variable sequence number.
*/
- int nextadr;
+ protected int nextadr;
/** The first variable sequence number in a block that can return.
*/
- int returnadr;
+ protected int returnadr;
/** The list of unreferenced automatic resources.
*/
@@ -1430,35 +1423,46 @@
/** The starting position of the analysed tree */
int startPos;
- AssignAnalyzer() {
- inits = new Bits();
+ final Symtab syms;
+
+ protected Names names;
+
+ public static class AbstractAssignPendingExit extends BaseAnalyzer.PendingExit {
+
+ final Bits inits;
+ final Bits uninits;
+ final Bits exit_inits = new Bits(true);
+ final Bits exit_uninits = new Bits(true);
+
+ public AbstractAssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+ super(tree);
+ this.inits = inits;
+ this.uninits = uninits;
+ this.exit_inits.assign(inits);
+ this.exit_uninits.assign(uninits);
+ }
+
+ @Override
+ public void resolveJump(JCTree tree) {
+ inits.andSet(exit_inits);
+ uninits.andSet(exit_uninits);
+ }
+ }
+
+ public AbstractAssignAnalyzer(Bits inits, Symtab syms, Names names) {
+ this.inits = inits;
uninits = new Bits();
uninitsTry = new Bits();
initsWhenTrue = new Bits(true);
initsWhenFalse = new Bits(true);
uninitsWhenTrue = new Bits(true);
uninitsWhenFalse = new Bits(true);
- }
-
- class AssignPendingExit extends BaseAnalyzer.PendingExit {
-
- final Bits exit_inits = new Bits(true);
- final Bits exit_uninits = new Bits(true);
-
- AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
- super(tree);
- this.exit_inits.assign(inits);
- this.exit_uninits.assign(uninits);
- }
-
- void resolveJump() {
- inits.andSet(exit_inits);
- uninits.andSet(exit_uninits);
- }
+ this.syms = syms;
+ this.names = names;
}
@Override
- void markDead() {
+ protected void markDead(JCTree tree) {
inits.inclRange(returnadr, nextadr);
uninits.inclRange(returnadr, nextadr);
}
@@ -1468,7 +1472,7 @@
/** Do we need to track init/uninit state of this symbol?
* I.e. is symbol either a local or a blank final variable?
*/
- boolean trackable(VarSymbol sym) {
+ protected boolean trackable(VarSymbol sym) {
return
sym.pos >= startPos &&
((sym.owner.kind == MTH ||
@@ -1488,44 +1492,35 @@
}
sym.adr = nextadr;
vardecls[nextadr] = varDecl;
- inits.excl(nextadr);
+ exclVarFromInits(varDecl, nextadr);
uninits.incl(nextadr);
nextadr++;
}
+ protected void exclVarFromInits(JCTree tree, int adr) {
+ inits.excl(adr);
+ }
+
+ protected void assignToInits(JCTree tree, Bits bits) {
+ inits.assign(bits);
+ }
+
+ protected void andSetInits(JCTree tree, Bits bits) {
+ inits.andSet(bits);
+ }
+
+ protected void orSetInits(JCTree tree, Bits bits) {
+ inits.orSet(bits);
+ }
+
/** Record an initialization of a trackable variable.
*/
void letInit(DiagnosticPosition pos, VarSymbol sym) {
if (sym.adr >= firstadr && trackable(sym)) {
- if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
- if (!uninits.isMember(sym.adr)) {
- //assignment targeting an effectively final variable
- //makes the variable lose its status of effectively final
- //if the variable is _not_ definitively unassigned
- sym.flags_field &= ~EFFECTIVELY_FINAL;
- } else {
- uninit(sym);
- }
- }
- else if ((sym.flags() & FINAL) != 0) {
- if ((sym.flags() & PARAMETER) != 0) {
- if ((sym.flags() & UNION) != 0) { //multi-catch parameter
- log.error(pos, "multicatch.parameter.may.not.be.assigned",
- sym);
- }
- else {
- log.error(pos, "final.parameter.may.not.be.assigned",
- sym);
- }
- } else if (!uninits.isMember(sym.adr)) {
- log.error(pos, flowKind.errKey, sym);
- } else {
- uninit(sym);
- }
+ if (uninits.isMember(sym.adr)) {
+ uninit(sym);
}
inits.incl(sym.adr);
- } else if ((sym.flags() & FINAL) != 0) {
- log.error(pos, "var.might.already.be.assigned", sym);
}
}
//where
@@ -1559,12 +1554,14 @@
void checkInit(DiagnosticPosition pos, VarSymbol sym) {
checkInit(pos, sym, "var.might.not.have.been.initialized");
}
- void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
- if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
- trackable(sym) &&
- !inits.isMember(sym.adr)) {
- log.error(pos, errkey, sym);
- inits.incl(sym.adr);
+
+ void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {}
+
+ /** Utility method to reset several Bits instances.
+ */
+ private void resetBits(Bits... bits) {
+ for (Bits b : bits) {
+ b.reset();
}
}
@@ -1582,7 +1579,7 @@
/** Merge (intersect) inits/uninits from WhenTrue/WhenFalse sets.
*/
- void merge() {
+ protected void merge(JCTree tree) {
inits.assign(initsWhenFalse.andSet(initsWhenTrue));
uninits.assign(uninitsWhenFalse.andSet(uninitsWhenTrue));
}
@@ -1597,7 +1594,9 @@
void scanExpr(JCTree tree) {
if (tree != null) {
scan(tree);
- if (inits.isReset()) merge();
+ if (inits.isReset()) {
+ merge(tree);
+ }
}
}
@@ -1614,7 +1613,7 @@
*/
void scanCond(JCTree tree) {
if (tree.type.isFalse()) {
- if (inits.isReset()) merge();
+ if (inits.isReset()) merge(tree);
initsWhenTrue.assign(inits);
initsWhenTrue.inclRange(firstadr, nextadr);
uninitsWhenTrue.assign(uninits);
@@ -1622,7 +1621,7 @@
initsWhenFalse.assign(inits);
uninitsWhenFalse.assign(uninits);
} else if (tree.type.isTrue()) {
- if (inits.isReset()) merge();
+ if (inits.isReset()) merge(tree);
initsWhenFalse.assign(inits);
initsWhenFalse.inclRange(firstadr, nextadr);
uninitsWhenFalse.assign(uninits);
@@ -1641,22 +1640,22 @@
/* ------------ Visitor methods for various sorts of trees -------------*/
+ @Override
public void visitClassDef(JCClassDecl tree) {
- if (tree.sym == null) return;
+ if (tree.sym == null) {
+ return;
+ }
JCClassDecl classDefPrev = classDef;
int firstadrPrev = firstadr;
int nextadrPrev = nextadr;
- ListBuffer<AssignPendingExit> pendingExitsPrev = pendingExits;
- Lint lintPrev = lint;
+ ListBuffer<P> pendingExitsPrev = pendingExits;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ pendingExits = new ListBuffer<P>();
if (tree.name != names.empty) {
firstadr = nextadr;
}
classDef = tree;
- lint = lint.augment(tree.sym);
-
try {
// define all the static fields
for (List<JCTree> l = tree.defs; l.nonEmpty(); l = l.tail) {
@@ -1664,8 +1663,9 @@
JCVariableDecl def = (JCVariableDecl)l.head;
if ((def.mods.flags & STATIC) != 0) {
VarSymbol sym = def.sym;
- if (trackable(sym))
+ if (trackable(sym)) {
newVar(def);
+ }
}
}
}
@@ -1684,8 +1684,9 @@
JCVariableDecl def = (JCVariableDecl)l.head;
if ((def.mods.flags & STATIC) == 0) {
VarSymbol sym = def.sym;
- if (trackable(sym))
+ if (trackable(sym)) {
newVar(def);
+ }
}
}
}
@@ -1709,21 +1710,25 @@
nextadr = nextadrPrev;
firstadr = firstadrPrev;
classDef = classDefPrev;
- lint = lintPrev;
}
}
+ @Override
public void visitMethodDef(JCMethodDecl tree) {
- if (tree.body == null) return;
+ if (tree.body == null) {
+ return;
+ }
+ /* MemberEnter can generate synthetic methods, ignore them
+ */
+ if ((tree.sym.flags() & SYNTHETIC) != 0) {
+ return;
+ }
final Bits initsPrev = new Bits(inits);
final Bits uninitsPrev = new Bits(uninits);
int nextadrPrev = nextadr;
int firstadrPrev = firstadr;
int returnadrPrev = returnadr;
- Lint lintPrev = lint;
-
- lint = lint.augment(tree.sym);
Assert.check(pendingExits.isEmpty());
@@ -1731,13 +1736,17 @@
boolean isInitialConstructor =
TreeInfo.isInitialConstructor(tree);
- if (!isInitialConstructor)
+ if (!isInitialConstructor) {
firstadr = nextadr;
+ }
for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
JCVariableDecl def = l.head;
scan(def);
- inits.incl(def.sym.adr);
- uninits.excl(def.sym.adr);
+ Assert.check((def.sym.flags() & PARAMETER) != 0, "Method parameter without PARAMETER flag");
+ /* If we are executing the code from Gen, then there can be
+ * synthetic or mandated variables, ignore them.
+ */
+ initParam(def);
}
// else we are in an instance initializer block;
// leave caught unchanged.
@@ -1761,39 +1770,42 @@
}
}
}
- List<AssignPendingExit> exits = pendingExits.toList();
- pendingExits = new ListBuffer<AssignPendingExit>();
+ List<P> exits = pendingExits.toList();
+ pendingExits = new ListBuffer<>();
while (exits.nonEmpty()) {
- AssignPendingExit exit = exits.head;
+ P exit = exits.head;
exits = exits.tail;
Assert.check(exit.tree.hasTag(RETURN), exit.tree);
if (isInitialConstructor) {
- inits.assign(exit.exit_inits);
- for (int i = firstadr; i < nextadr; i++)
+ assignToInits(exit.tree, exit.exit_inits);
+ for (int i = firstadr; i < nextadr; i++) {
checkInit(exit.tree.pos(), vardecls[i].sym);
+ }
}
}
} finally {
- inits.assign(initsPrev);
+ assignToInits(tree, initsPrev);
uninits.assign(uninitsPrev);
nextadr = nextadrPrev;
firstadr = firstadrPrev;
returnadr = returnadrPrev;
- lint = lintPrev;
}
}
+ protected void initParam(JCVariableDecl def) {
+ inits.incl(def.sym.adr);
+ uninits.excl(def.sym.adr);
+ }
+
public void visitVarDef(JCVariableDecl tree) {
boolean track = trackable(tree.sym);
- if (track && tree.sym.owner.kind == MTH) newVar(tree);
+ if (track && tree.sym.owner.kind == MTH) {
+ newVar(tree);
+ }
if (tree.init != null) {
- Lint lintPrev = lint;
- lint = lint.augment(tree.sym);
- try{
- scanExpr(tree.init);
- if (track) letInit(tree.pos(), tree.sym);
- } finally {
- lint = lintPrev;
+ scanExpr(tree.init);
+ if (track) {
+ letInit(tree.pos(), tree.sym);
}
}
}
@@ -1804,14 +1816,18 @@
nextadr = nextadrPrev;
}
+ int getLogNumberOfErrors() {
+ return 0;
+ }
+
public void visitDoLoop(JCDoWhileLoop tree) {
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ ListBuffer<P> prevPendingExits = pendingExits;
FlowKind prevFlowKind = flowKind;
flowKind = FlowKind.NORMAL;
final Bits initsSkip = new Bits(true);
final Bits uninitsSkip = new Bits(true);
- pendingExits = new ListBuffer<AssignPendingExit>();
- int prevErrors = log.nerrors;
+ pendingExits = new ListBuffer<P>();
+ int prevErrors = getLogNumberOfErrors();
do {
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
@@ -1822,28 +1838,28 @@
initsSkip.assign(initsWhenFalse);
uninitsSkip.assign(uninitsWhenFalse);
}
- if (log.nerrors != prevErrors ||
+ if (getLogNumberOfErrors() != prevErrors ||
flowKind.isFinal() ||
new Bits(uninitsEntry).diffSet(uninitsWhenTrue).nextBit(firstadr)==-1)
break;
- inits.assign(initsWhenTrue);
+ assignToInits(tree.cond, initsWhenTrue);
uninits.assign(uninitsEntry.andSet(uninitsWhenTrue));
flowKind = FlowKind.SPECULATIVE_LOOP;
} while (true);
flowKind = prevFlowKind;
- inits.assign(initsSkip);
+ assignToInits(tree, initsSkip);
uninits.assign(uninitsSkip);
resolveBreaks(tree, prevPendingExits);
}
public void visitWhileLoop(JCWhileLoop tree) {
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ ListBuffer<P> prevPendingExits = pendingExits;
FlowKind prevFlowKind = flowKind;
flowKind = FlowKind.NORMAL;
final Bits initsSkip = new Bits(true);
final Bits uninitsSkip = new Bits(true);
- pendingExits = new ListBuffer<AssignPendingExit>();
- int prevErrors = log.nerrors;
+ pendingExits = new ListBuffer<>();
+ int prevErrors = getLogNumberOfErrors();
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
do {
@@ -1852,35 +1868,36 @@
initsSkip.assign(initsWhenFalse) ;
uninitsSkip.assign(uninitsWhenFalse);
}
- inits.assign(initsWhenTrue);
+ assignToInits(tree, initsWhenTrue);
uninits.assign(uninitsWhenTrue);
scan(tree.body);
resolveContinues(tree);
- if (log.nerrors != prevErrors ||
+ if (getLogNumberOfErrors() != prevErrors ||
flowKind.isFinal() ||
- new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
+ new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1) {
break;
+ }
uninits.assign(uninitsEntry.andSet(uninits));
flowKind = FlowKind.SPECULATIVE_LOOP;
} while (true);
flowKind = prevFlowKind;
//a variable is DA/DU after the while statement, if it's DA/DU assuming the
//branch is not taken AND if it's DA/DU before any break statement
- inits.assign(initsSkip);
+ assignToInits(tree.body, initsSkip);
uninits.assign(uninitsSkip);
resolveBreaks(tree, prevPendingExits);
}
public void visitForLoop(JCForLoop tree) {
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ ListBuffer<P> prevPendingExits = pendingExits;
FlowKind prevFlowKind = flowKind;
flowKind = FlowKind.NORMAL;
int nextadrPrev = nextadr;
scan(tree.init);
final Bits initsSkip = new Bits(true);
final Bits uninitsSkip = new Bits(true);
- pendingExits = new ListBuffer<AssignPendingExit>();
- int prevErrors = log.nerrors;
+ pendingExits = new ListBuffer<P>();
+ int prevErrors = getLogNumberOfErrors();
do {
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
@@ -1890,7 +1907,7 @@
initsSkip.assign(initsWhenFalse);
uninitsSkip.assign(uninitsWhenFalse);
}
- inits.assign(initsWhenTrue);
+ assignToInits(tree.body, initsWhenTrue);
uninits.assign(uninitsWhenTrue);
} else if (!flowKind.isFinal()) {
initsSkip.assign(inits);
@@ -1901,7 +1918,7 @@
scan(tree.body);
resolveContinues(tree);
scan(tree.step);
- if (log.nerrors != prevErrors ||
+ if (getLogNumberOfErrors() != prevErrors ||
flowKind.isFinal() ||
new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
break;
@@ -1911,7 +1928,7 @@
flowKind = prevFlowKind;
//a variable is DA/DU after a for loop, if it's DA/DU assuming the
//branch is not taken AND if it's DA/DU before any break statement
- inits.assign(initsSkip);
+ assignToInits(tree.body, initsSkip);
uninits.assign(uninitsSkip);
resolveBreaks(tree, prevPendingExits);
nextadr = nextadrPrev;
@@ -1920,7 +1937,7 @@
public void visitForeachLoop(JCEnhancedForLoop tree) {
visitVarDef(tree.var);
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
+ ListBuffer<P> prevPendingExits = pendingExits;
FlowKind prevFlowKind = flowKind;
flowKind = FlowKind.NORMAL;
int nextadrPrev = nextadr;
@@ -1929,14 +1946,14 @@
final Bits uninitsStart = new Bits(uninits);
letInit(tree.pos(), tree.var.sym);
- pendingExits = new ListBuffer<AssignPendingExit>();
- int prevErrors = log.nerrors;
+ pendingExits = new ListBuffer<P>();
+ int prevErrors = getLogNumberOfErrors();
do {
final Bits uninitsEntry = new Bits(uninits);
uninitsEntry.excludeFrom(nextadr);
scan(tree.body);
resolveContinues(tree);
- if (log.nerrors != prevErrors ||
+ if (getLogNumberOfErrors() != prevErrors ||
flowKind.isFinal() ||
new Bits(uninitsEntry).diffSet(uninits).nextBit(firstadr) == -1)
break;
@@ -1944,41 +1961,50 @@
flowKind = FlowKind.SPECULATIVE_LOOP;
} while (true);
flowKind = prevFlowKind;
- inits.assign(initsStart);
+ assignToInits(tree.body, initsStart);
uninits.assign(uninitsStart.andSet(uninits));
resolveBreaks(tree, prevPendingExits);
nextadr = nextadrPrev;
}
public void visitLabelled(JCLabeledStatement tree) {
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ ListBuffer<P> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<P>();
scan(tree.body);
resolveBreaks(tree, prevPendingExits);
}
public void visitSwitch(JCSwitch tree) {
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ ListBuffer<P> 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);
+ assignToInits(l.head, initsSwitch);
uninits.assign(uninits.andSet(uninitsSwitch));
JCCase c = l.head;
- if (c.pat == null)
+ if (c.pat == null) {
hasDefault = true;
- else
+ } else {
scanExpr(c.pat);
+ }
+ if (hasDefault) {
+ assignToInits(null, initsSwitch);
+ uninits.assign(uninits.andSet(uninitsSwitch));
+ }
scan(c.stats);
addVars(c.stats, initsSwitch, uninitsSwitch);
+ if (!hasDefault) {
+ assignToInits(l.head.stats.last(), initsSwitch);
+ uninits.assign(uninits.andSet(uninitsSwitch));
+ }
// Warn about fall-through if lint switch fallthrough enabled.
}
if (!hasDefault) {
- inits.andSet(initsSwitch);
+ andSetInits(null, initsSwitch);
}
resolveBreaks(tree, prevPendingExits);
nextadr = nextadrPrev;
@@ -1997,11 +2023,17 @@
}
}
+ boolean isEnabled(Lint.LintCategory lc) {
+ return false;
+ }
+
+ void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos, String key, Object ... args) {}
+
public void visitTry(JCTry tree) {
ListBuffer<JCVariableDecl> resourceVarDecls = ListBuffer.lb();
final Bits uninitsTryPrev = new Bits(uninitsTry);
- ListBuffer<AssignPendingExit> prevPendingExits = pendingExits;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ ListBuffer<P> prevPendingExits = pendingExits;
+ pendingExits = new ListBuffer<>();
final Bits initsTry = new Bits(inits);
uninitsTry.assign(uninits);
for (JCTree resource : tree.resources) {
@@ -2023,10 +2055,10 @@
int nextadrCatch = nextadr;
if (!resourceVarDecls.isEmpty() &&
- lint.isEnabled(Lint.LintCategory.TRY)) {
+ isEnabled(Lint.LintCategory.TRY)) {
for (JCVariableDecl resVar : resourceVarDecls) {
if (unrefdResources.includes(resVar.sym)) {
- log.warning(Lint.LintCategory.TRY, resVar.pos(),
+ reportWarning(Lint.LintCategory.TRY, resVar.pos(),
"try.resource.not.referenced", resVar.sym);
unrefdResources.remove(resVar.sym);
}
@@ -2042,20 +2074,22 @@
for (List<JCCatch> l = tree.catchers; l.nonEmpty(); l = l.tail) {
JCVariableDecl param = l.head.param;
- inits.assign(initsCatchPrev);
+ assignToInits(tree.body, initsCatchPrev);
uninits.assign(uninitsCatchPrev);
scan(param);
- inits.incl(param.sym.adr);
- uninits.excl(param.sym.adr);
+ /* If this is a TWR and we are executing the code from Gen,
+ * then there can be synthetic variables, ignore them.
+ */
+ initParam(param);
scan(l.head.body);
initsEnd.andSet(inits);
uninitsEnd.andSet(uninits);
nextadr = nextadrCatch;
}
if (tree.finalizer != null) {
- inits.assign(initsTry);
+ assignToInits(tree.finalizer, initsTry);
uninits.assign(uninitsTry);
- ListBuffer<AssignPendingExit> exits = pendingExits;
+ ListBuffer<P> exits = pendingExits;
pendingExits = prevPendingExits;
scan(tree.finalizer);
if (!tree.finallyCanCompleteNormally) {
@@ -2065,19 +2099,19 @@
// FIX: this doesn't preserve source order of exits in catch
// versus finally!
while (exits.nonEmpty()) {
- AssignPendingExit exit = exits.next();
+ P exit = exits.next();
if (exit.exit_inits != null) {
exit.exit_inits.orSet(inits);
exit.exit_uninits.andSet(uninits);
}
pendingExits.append(exit);
}
- inits.orSet(initsEnd);
+ orSetInits(tree, initsEnd);
}
} else {
- inits.assign(initsEnd);
+ assignToInits(tree, initsEnd);
uninits.assign(uninitsEnd);
- ListBuffer<AssignPendingExit> exits = pendingExits;
+ ListBuffer<P> exits = pendingExits;
pendingExits = prevPendingExits;
while (exits.nonEmpty()) pendingExits.append(exits.next());
}
@@ -2088,7 +2122,7 @@
scanCond(tree.cond);
final Bits initsBeforeElse = new Bits(initsWhenFalse);
final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
- inits.assign(initsWhenTrue);
+ assignToInits(tree.cond, initsWhenTrue);
uninits.assign(uninitsWhenTrue);
if (tree.truepart.type.hasTag(BOOLEAN) &&
tree.falsepart.type.hasTag(BOOLEAN)) {
@@ -2101,7 +2135,7 @@
final Bits initsAfterThenWhenFalse = new Bits(initsWhenFalse);
final Bits uninitsAfterThenWhenTrue = new Bits(uninitsWhenTrue);
final Bits uninitsAfterThenWhenFalse = new Bits(uninitsWhenFalse);
- inits.assign(initsBeforeElse);
+ assignToInits(tree.truepart, initsBeforeElse);
uninits.assign(uninitsBeforeElse);
scanCond(tree.falsepart);
initsWhenTrue.andSet(initsAfterThenWhenTrue);
@@ -2112,10 +2146,10 @@
scanExpr(tree.truepart);
final Bits initsAfterThen = new Bits(inits);
final Bits uninitsAfterThen = new Bits(uninits);
- inits.assign(initsBeforeElse);
+ assignToInits(tree.truepart, initsBeforeElse);
uninits.assign(uninitsBeforeElse);
scanExpr(tree.falsepart);
- inits.andSet(initsAfterThen);
+ andSetInits(tree.falsepart, initsAfterThen);
uninits.andSet(uninitsAfterThen);
}
}
@@ -2124,39 +2158,46 @@
scanCond(tree.cond);
final Bits initsBeforeElse = new Bits(initsWhenFalse);
final Bits uninitsBeforeElse = new Bits(uninitsWhenFalse);
- inits.assign(initsWhenTrue);
+ assignToInits(tree.cond, initsWhenTrue);
uninits.assign(uninitsWhenTrue);
scan(tree.thenpart);
if (tree.elsepart != null) {
final Bits initsAfterThen = new Bits(inits);
final Bits uninitsAfterThen = new Bits(uninits);
- inits.assign(initsBeforeElse);
+ assignToInits(tree.thenpart, initsBeforeElse);
uninits.assign(uninitsBeforeElse);
scan(tree.elsepart);
- inits.andSet(initsAfterThen);
+ andSetInits(tree.elsepart, initsAfterThen);
uninits.andSet(uninitsAfterThen);
} else {
- inits.andSet(initsBeforeElse);
+ andSetInits(tree.thenpart, initsBeforeElse);
uninits.andSet(uninitsBeforeElse);
}
}
+ protected P createNewPendingExit(JCTree tree, Bits inits, Bits uninits) {
+ return null;
+ }
+
+ @Override
public void visitBreak(JCBreak tree) {
- recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+ recordExit(tree, createNewPendingExit(tree, inits, uninits));
}
+ @Override
public void visitContinue(JCContinue tree) {
- recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+ recordExit(tree, createNewPendingExit(tree, inits, uninits));
}
+ @Override
public void visitReturn(JCReturn tree) {
scanExpr(tree.expr);
- recordExit(tree, new AssignPendingExit(tree, inits, uninits));
+ recordExit(tree, createNewPendingExit(tree, inits, uninits));
}
public void visitThrow(JCThrow tree) {
scanExpr(tree.expr);
- markDead();
+ markDead(tree.expr);
}
public void visitApply(JCMethodInvocation tree) {
@@ -2175,10 +2216,10 @@
final Bits prevUninits = new Bits(uninits);
final Bits prevInits = new Bits(inits);
int returnadrPrev = returnadr;
- ListBuffer<AssignPendingExit> prevPending = pendingExits;
+ ListBuffer<P> prevPending = pendingExits;
try {
returnadr = nextadr;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ pendingExits = new ListBuffer<P>();
for (List<JCVariableDecl> l = tree.params; l.nonEmpty(); l = l.tail) {
JCVariableDecl def = l.head;
scan(def);
@@ -2194,7 +2235,7 @@
finally {
returnadr = returnadrPrev;
uninits.assign(prevUninits);
- inits.assign(prevInits);
+ assignToInits(tree, prevInits);
pendingExits = prevPending;
}
}
@@ -2210,11 +2251,11 @@
scanCond(tree.cond);
uninitsExit.andSet(uninitsWhenTrue);
if (tree.detail != null) {
- inits.assign(initsWhenFalse);
+ assignToInits(tree, initsWhenFalse);
uninits.assign(uninitsWhenFalse);
scanExpr(tree.detail);
}
- inits.assign(initsExit);
+ assignToInits(tree, initsExit);
uninits.assign(uninitsExit);
}
@@ -2260,7 +2301,7 @@
scanCond(tree.lhs);
final Bits initsWhenFalseLeft = new Bits(initsWhenFalse);
final Bits uninitsWhenFalseLeft = new Bits(uninitsWhenFalse);
- inits.assign(initsWhenTrue);
+ assignToInits(tree.lhs, initsWhenTrue);
uninits.assign(uninitsWhenTrue);
scanCond(tree.rhs);
initsWhenFalse.andSet(initsWhenFalseLeft);
@@ -2270,7 +2311,7 @@
scanCond(tree.lhs);
final Bits initsWhenTrueLeft = new Bits(initsWhenTrue);
final Bits uninitsWhenTrueLeft = new Bits(uninitsWhenTrue);
- inits.assign(initsWhenFalse);
+ assignToInits(tree.lhs, initsWhenFalse);
uninits.assign(uninitsWhenFalse);
scanCond(tree.rhs);
initsWhenTrue.andSet(initsWhenTrueLeft);
@@ -2308,14 +2349,12 @@
/** Perform definite assignment/unassignment analysis on a tree.
*/
- public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
- analyzeTree(env, env.tree, make);
- }
+ public void analyzeTree(Env<?> env) {
+ analyzeTree(env, env.tree);
+ }
- public void analyzeTree(Env<AttrContext> env, JCTree tree, TreeMaker make) {
+ public void analyzeTree(Env<?> env, JCTree tree) {
try {
- attrEnv = env;
- Flow.this.make = make;
startPos = tree.pos().getStartPosition();
if (vardecls == null)
@@ -2325,7 +2364,7 @@
vardecls[i] = null;
firstadr = 0;
nextadr = 0;
- pendingExits = new ListBuffer<AssignPendingExit>();
+ pendingExits = new ListBuffer<>();
this.classDef = null;
unrefdResources = new Scope(env.enclClass.sym);
scan(tree);
@@ -2334,18 +2373,160 @@
startPos = -1;
resetBits(inits, uninits, uninitsTry, initsWhenTrue,
initsWhenFalse, uninitsWhenTrue, uninitsWhenFalse);
- if (vardecls != null) for (int i=0; i<vardecls.length; i++)
- vardecls[i] = null;
+ if (vardecls != null) {
+ for (int i=0; i<vardecls.length; i++)
+ vardecls[i] = null;
+ }
firstadr = 0;
nextadr = 0;
pendingExits = null;
- Flow.this.make = null;
this.classDef = null;
unrefdResources = null;
}
}
}
+ public static class AssignAnalyzer
+ extends AbstractAssignAnalyzer<AssignAnalyzer.AssignPendingExit> {
+
+ Log log;
+ Lint lint;
+
+ public static class AssignPendingExit
+ extends AbstractAssignAnalyzer.AbstractAssignPendingExit {
+
+ public AssignPendingExit(JCTree tree, final Bits inits, final Bits uninits) {
+ super(tree, inits, uninits);
+ }
+ }
+
+ public AssignAnalyzer(Log log, Symtab syms, Lint lint, Names names) {
+ super(new Bits(), syms, names);
+ this.log = log;
+ this.lint = lint;
+ }
+
+ @Override
+ protected AssignPendingExit createNewPendingExit(JCTree tree,
+ Bits inits, Bits uninits) {
+ return new AssignPendingExit(tree, inits, uninits);
+ }
+
+ /** Record an initialization of a trackable variable.
+ */
+ @Override
+ void letInit(DiagnosticPosition pos, VarSymbol sym) {
+ if (sym.adr >= firstadr && trackable(sym)) {
+ if ((sym.flags() & EFFECTIVELY_FINAL) != 0) {
+ if (!uninits.isMember(sym.adr)) {
+ //assignment targeting an effectively final variable
+ //makes the variable lose its status of effectively final
+ //if the variable is _not_ definitively unassigned
+ sym.flags_field &= ~EFFECTIVELY_FINAL;
+ } else {
+ uninit(sym);
+ }
+ }
+ else if ((sym.flags() & FINAL) != 0) {
+ if ((sym.flags() & PARAMETER) != 0) {
+ if ((sym.flags() & UNION) != 0) { //multi-catch parameter
+ log.error(pos, "multicatch.parameter.may.not.be.assigned", sym);
+ }
+ else {
+ log.error(pos, "final.parameter.may.not.be.assigned",
+ sym);
+ }
+ } else if (!uninits.isMember(sym.adr)) {
+ log.error(pos, flowKind.errKey, sym);
+ } else {
+ uninit(sym);
+ }
+ }
+ inits.incl(sym.adr);
+ } else if ((sym.flags() & FINAL) != 0) {
+ log.error(pos, "var.might.already.be.assigned", sym);
+ }
+ }
+
+ @Override
+ void checkInit(DiagnosticPosition pos, VarSymbol sym, String errkey) {
+ if ((sym.adr >= firstadr || sym.owner.kind != TYP) &&
+ trackable(sym) &&
+ !inits.isMember(sym.adr)) {
+ log.error(pos, errkey, sym);
+ inits.incl(sym.adr);
+ }
+ }
+
+ @Override
+ void reportWarning(Lint.LintCategory lc, DiagnosticPosition pos,
+ String key, Object ... args) {
+ log.warning(lc, pos, key, args);
+ }
+
+ @Override
+ int getLogNumberOfErrors() {
+ return log.nerrors;
+ }
+
+ @Override
+ boolean isEnabled(Lint.LintCategory lc) {
+ return lint.isEnabled(lc);
+ }
+
+ @Override
+ public void visitClassDef(JCClassDecl tree) {
+ if (tree.sym == null) {
+ return;
+ }
+
+ Lint lintPrev = lint;
+ lint = lint.augment(tree.sym);
+ try {
+ super.visitClassDef(tree);
+ } finally {
+ lint = lintPrev;
+ }
+ }
+
+ @Override
+ public void visitMethodDef(JCMethodDecl tree) {
+ if (tree.body == null) {
+ return;
+ }
+
+ /* MemberEnter can generate synthetic methods ignore them
+ */
+ if ((tree.sym.flags() & SYNTHETIC) != 0) {
+ return;
+ }
+
+ Lint lintPrev = lint;
+ lint = lint.augment(tree.sym);
+ try {
+ super.visitMethodDef(tree);
+ } finally {
+ lint = lintPrev;
+ }
+ }
+
+ @Override
+ public void visitVarDef(JCVariableDecl tree) {
+ if (tree.init == null) {
+ super.visitVarDef(tree);
+ } else {
+ Lint lintPrev = lint;
+ lint = lint.augment(tree.sym);
+ try{
+ super.visitVarDef(tree);
+ } finally {
+ lint = lintPrev;
+ }
+ }
+ }
+
+ }
+
/**
* This pass implements the last step of the dataflow analysis, namely
* the effectively-final analysis check. This checks that every local variable
@@ -2358,7 +2539,7 @@
JCTree currentTree; //local class or lambda
@Override
- void markDead() {
+ void markDead(JCTree tree) {
//do nothing
}