< 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 >