< 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,10 +26,12 @@
 //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,11 +211,11 @@
         return instance;
     }
 
     public void analyzeTree(Env<AttrContext> env, TreeMaker make) {
         new AliveAnalyzer().analyzeTree(env, make);
-        new AssignAnalyzer().analyzeTree(env);
+        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,11 +244,11 @@
         //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);
+            new LambdaAssignAnalyzer(env).analyzeTree(env, that, make);
             LambdaFlowAnalyzer flowAnalyzer = new LambdaFlowAnalyzer();
             flowAnalyzer.analyzeTree(env, that, make);
             return flowAnalyzer.inferredThrownTypes;
         } finally {
             log.popDiagnosticHandler(diagHandler);

@@ -394,10 +396,16 @@
         }
 
         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,15 +602,23 @@
             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)
+                if (c.pats.isEmpty())
                     hasDefault = true;
-                else
-                    scan(c.pat);
+                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,10 +629,50 @@
                 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,10 +734,12 @@
                 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,18 +1096,25 @@
             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(tree.selector);
-            for (List<JCCase> l = tree.cases; l.nonEmpty(); l = l.tail) {
+            scan(selector);
+            for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
                 JCCase c = l.head;
-                if (c.pat != null) {
-                    scan(c.pat);
-                }
+                scan(c.pats);
                 scan(c.stats);
             }
             resolveBreaks(tree, prevPendingExits);
         }
 

@@ -1189,10 +1254,12 @@
                 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,31 +2170,44 @@
             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(tree.selector);
+            scanExpr(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) {
+            for (List<JCCase> l = cases; l.nonEmpty(); l = l.tail) {
                 inits.assign(initsSwitch);
                 uninits.assign(uninits.andSet(uninitsSwitch));
                 JCCase c = l.head;
-                if (c.pat == null) {
+                if (c.pats.isEmpty()) {
                     hasDefault = true;
                 } else {
-                    scanExpr(c.pat);
+                    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,10 +2379,12 @@
             }
         }
 
         @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,25 +2559,26 @@
      * main method
      *************************************************************************/
 
         /** Perform definite assignment/unassignment analysis on a tree.
          */
-        public void analyzeTree(Env<?> env) {
-            analyzeTree(env, env.tree);
+        public void analyzeTree(Env<?> env, TreeMaker make) {
+            analyzeTree(env, env.tree, make);
          }
 
-        public void analyzeTree(Env<?> env, JCTree tree) {
+        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,10 +2590,11 @@
                     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,10 +2743,16 @@
                 }
             }
             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 >