Migrate `SwitchCaseContainsExit` out of SkSLAnalysis.

This CL also removes `SwitchCaseFallsThrough` entirely; it was
not referenced anywhere.

Change-Id: I58298bf2a603615e37f4cced9db6d2f4c2c54d5a
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/456473
Commit-Queue: John Stiles <johnstiles@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
diff --git a/gn/sksl.gni b/gn/sksl.gni
index 213e364..d4419ea 100644
--- a/gn/sksl.gni
+++ b/gn/sksl.gni
@@ -77,6 +77,8 @@
   "$_src/sksl/SkSLStringStream.h",
   "$_src/sksl/SkSLUtil.cpp",
   "$_src/sksl/SkSLUtil.h",
+  "$_src/sksl/analysis/SkSLProgramVisitor.h",
+  "$_src/sksl/analysis/SwitchCaseContainsExit.cpp",
   "$_src/sksl/codegen/SkSLVMCodeGenerator.cpp",
   "$_src/sksl/codegen/SkSLVMCodeGenerator.h",
   "$_src/sksl/dsl/DSLBlock.cpp",
diff --git a/src/sksl/SkSLAnalysis.cpp b/src/sksl/SkSLAnalysis.cpp
index 1751315..13c6e51 100644
--- a/src/sksl/SkSLAnalysis.cpp
+++ b/src/sksl/SkSLAnalysis.cpp
@@ -371,69 +371,6 @@
     using INHERITED = ProgramVisitor;
 };
 
-class SwitchCaseContainsExit : public ProgramVisitor {
-public:
-    SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
-
-    bool visitStatement(const Statement& stmt) override {
-        switch (stmt.kind()) {
-            case Statement::Kind::kBlock:
-            case Statement::Kind::kSwitchCase:
-                return INHERITED::visitStatement(stmt);
-
-            case Statement::Kind::kReturn:
-                // Returns are an early exit regardless of the surrounding control structures.
-                return fConditionalExits ? fInConditional : !fInConditional;
-
-            case Statement::Kind::kContinue:
-                // Continues are an early exit from switches, but not loops.
-                return !fInLoop &&
-                       (fConditionalExits ? fInConditional : !fInConditional);
-
-            case Statement::Kind::kBreak:
-                // Breaks cannot escape from switches or loops.
-                return !fInLoop && !fInSwitch &&
-                       (fConditionalExits ? fInConditional : !fInConditional);
-
-            case Statement::Kind::kIf: {
-                ++fInConditional;
-                bool result = INHERITED::visitStatement(stmt);
-                --fInConditional;
-                return result;
-            }
-
-            case Statement::Kind::kFor:
-            case Statement::Kind::kDo: {
-                // Loops are treated as conditionals because a loop could potentially execute zero
-                // times. We don't have a straightforward way to determine that a loop definitely
-                // executes at least once.
-                ++fInConditional;
-                ++fInLoop;
-                bool result = INHERITED::visitStatement(stmt);
-                --fInLoop;
-                --fInConditional;
-                return result;
-            }
-
-            case Statement::Kind::kSwitch: {
-                ++fInSwitch;
-                bool result = INHERITED::visitStatement(stmt);
-                --fInSwitch;
-                return result;
-            }
-
-            default:
-                return false;
-        }
-    }
-
-    bool fConditionalExits = false;
-    int fInConditional = 0;
-    int fInLoop = 0;
-    int fInSwitch = 0;
-    using INHERITED = ProgramVisitor;
-};
-
 class ReturnsOnAllPathsVisitor : public ProgramVisitor {
 public:
     bool visitExpression(const Expression& expr) override {
@@ -826,14 +763,6 @@
     return NodeCountVisitor{limit}.visit(*function.body());
 }
 
-bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
-    return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
-}
-
-bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
-    return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
-}
-
 std::unique_ptr<ProgramUsage> Analysis::GetUsage(const Program& program) {
     auto usage = std::make_unique<ProgramUsage>();
     ProgramUsageVisitor addRefs(usage.get(), /*delta=*/+1);
diff --git a/src/sksl/SkSLAnalysis.h b/src/sksl/SkSLAnalysis.h
index 1af4721..34cbded 100644
--- a/src/sksl/SkSLAnalysis.h
+++ b/src/sksl/SkSLAnalysis.h
@@ -78,13 +78,6 @@
 bool SwitchCaseContainsUnconditionalExit(Statement& stmt);
 
 /**
- * A switch-case "falls through" when it doesn't have an unconditional exit.
- */
-inline bool SwitchCaseFallsThrough(Statement& stmt) {
-    return !SwitchCaseContainsUnconditionalExit(stmt);
-}
-
-/**
  * Finds conditional exits from a switch-case. Returns true if this statement contains a
  * conditional that wraps a potential exit from the switch (via continue, break or return).
  */
diff --git a/src/sksl/analysis/SwitchCaseContainsExit.cpp b/src/sksl/analysis/SwitchCaseContainsExit.cpp
new file mode 100644
index 0000000..ffab385
--- /dev/null
+++ b/src/sksl/analysis/SwitchCaseContainsExit.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2021 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "src/sksl/SkSLAnalysis.h"
+
+#include "include/private/SkSLStatement.h"
+#include "src/sksl/analysis/SkSLProgramVisitor.h"
+
+namespace SkSL {
+namespace {
+
+class SwitchCaseContainsExit : public ProgramVisitor {
+public:
+    SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
+
+    bool visitStatement(const Statement& stmt) override {
+        switch (stmt.kind()) {
+            case Statement::Kind::kBlock:
+            case Statement::Kind::kSwitchCase:
+                return INHERITED::visitStatement(stmt);
+
+            case Statement::Kind::kReturn:
+                // Returns are an early exit regardless of the surrounding control structures.
+                return fConditionalExits ? fInConditional : !fInConditional;
+
+            case Statement::Kind::kContinue:
+                // Continues are an early exit from switches, but not loops.
+                return !fInLoop &&
+                       (fConditionalExits ? fInConditional : !fInConditional);
+
+            case Statement::Kind::kBreak:
+                // Breaks cannot escape from switches or loops.
+                return !fInLoop && !fInSwitch &&
+                       (fConditionalExits ? fInConditional : !fInConditional);
+
+            case Statement::Kind::kIf: {
+                ++fInConditional;
+                bool result = INHERITED::visitStatement(stmt);
+                --fInConditional;
+                return result;
+            }
+
+            case Statement::Kind::kFor:
+            case Statement::Kind::kDo: {
+                // Loops are treated as conditionals because a loop could potentially execute zero
+                // times. We don't have a straightforward way to determine that a loop definitely
+                // executes at least once.
+                ++fInConditional;
+                ++fInLoop;
+                bool result = INHERITED::visitStatement(stmt);
+                --fInLoop;
+                --fInConditional;
+                return result;
+            }
+
+            case Statement::Kind::kSwitch: {
+                ++fInSwitch;
+                bool result = INHERITED::visitStatement(stmt);
+                --fInSwitch;
+                return result;
+            }
+
+            default:
+                return false;
+        }
+    }
+
+    bool fConditionalExits = false;
+    int fInConditional = 0;
+    int fInLoop = 0;
+    int fInSwitch = 0;
+    using INHERITED = ProgramVisitor;
+};
+
+}  // namespace
+
+bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
+    return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
+}
+
+bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
+    return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
+}
+
+}  // namespace SkSL