CFG: fixing case fallthrough.

Review at http://gwt-code-reviews.appspot.com/434801


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@8041 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java
index 8be2b1b..6cd1087 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilder.java
@@ -622,6 +622,7 @@
       int defaultPos = -1;
       
       List<Exit> breakExits = new ArrayList<Exit>();
+      List<Exit> fallThroughExits = new ArrayList<Exit>();
 
       List<JStatement> statements = x.getBody().getStatements();
       
@@ -629,6 +630,8 @@
         if (s instanceof JCaseStatement) {
           if (((JCaseStatement) s).getExpr() != null) {
             // case label
+
+            fallThroughExits.addAll(removeExits(Exit.Reason.NORMAL));
             if (gotoExit != null) {
               // This is first non-default case.
               addExit(gotoExit);
@@ -647,6 +650,12 @@
           for (Exit e : thenExits) {
             addNormalExit(e.getNode(), e.role);
           }
+          if (!fallThroughExits.isEmpty()) {
+            for (Exit e : fallThroughExits) {
+              addExit(e);
+            }
+            fallThroughExits.clear();
+          }
         }
         accept(s);
         breakExits.addAll(removeExits(Exit.Reason.BREAK));
diff --git a/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java b/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java
index 82c0b37..ffdc7ca 100644
--- a/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java
+++ b/dev/core/test/com/google/gwt/dev/jjs/impl/gflow/cfg/CfgBuilderTest.java
@@ -1109,7 +1109,7 @@
             "STMT -> [*]",
             "COND (EntryPoint.i == 1) -> [THEN=*, ELSE=1]",
             "STMT -> [*]",
-            "GOTO -> [6]",
+            "GOTO -> [7]",
             "1: STMT -> [*]",
             "COND (EntryPoint.i == 2) -> [ELSE=*, THEN=2]",
             "STMT -> [*]",
@@ -1117,24 +1117,54 @@
             "2: STMT -> [*]",
             "WRITE(j, 1) -> [*]",
             "STMT -> [*]",
-            "GOTO -> [6]",
+            "GOTO -> [7]",
             "3: STMT -> [*]",
             "COND (EntryPoint.i == 4) -> [THEN=*, ELSE=5]",
             "STMT -> [*]",
             "WRITE(j, 2) -> [*]",
             "4: STMT -> [*]",
             "STMT -> [*]",
-            "WRITE(j, 4) -> [*]",
+            "WRITE(j, 4) -> [6]",
             "5: STMT -> [*]",
             "COND (EntryPoint.i == 5) -> [THEN=*, ELSE=4]",
-            "STMT -> [*]",
+            "6: STMT -> [*]",
             "WRITE(j, 3) -> [*]",
             "STMT -> [*]",
             "GOTO -> [*]",
-            "6: END"
+            "7: END"
     );
   }
 
+  public void testSwitch_FallThrough() throws Exception {
+    assertCfg("void",
+        "switch(i) {",
+        "  case 1: ",
+        "    j = 1;",
+        "  case 2: ",
+        "    j = 2;",
+        "  case 3: ",
+        "    j = 3;",
+        "}"
+        ).is(
+            "BLOCK -> [*]",
+            "STMT -> [*]",
+            "READ(i) -> [*]",
+            "GOTO -> [*]",
+            "STMT -> [*]",
+            "COND (EntryPoint.i == 1) -> [THEN=*, ELSE=1]",
+            "STMT -> [*]",
+            "WRITE(j, 1) -> [2]",
+            "1: STMT -> [*]",
+            "COND (EntryPoint.i == 2) -> [THEN=*, ELSE=3]",
+            "2: STMT -> [*]",
+            "WRITE(j, 2) -> [4]",
+            "3: STMT -> [*]",
+            "COND (EntryPoint.i == 3) -> [THEN=*, ELSE=5]",
+            "4: STMT -> [*]",
+            "WRITE(j, 3) -> [*]",
+            "5: END");
+  }
+  
   public void testSwitch_FirstDefault() throws Exception {
     assertCfg("void",
         "switch(i) {",