• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "src/sksl/SkSLAnalysis.h"
9 
10 #include "include/private/SkSLStatement.h"
11 #include "src/sksl/analysis/SkSLProgramVisitor.h"
12 
13 namespace SkSL {
14 namespace {
15 
16 class SwitchCaseContainsExit : public ProgramVisitor {
17 public:
SwitchCaseContainsExit(bool conditionalExits)18     SwitchCaseContainsExit(bool conditionalExits) : fConditionalExits(conditionalExits) {}
19 
visitStatement(const Statement & stmt)20     bool visitStatement(const Statement& stmt) override {
21         switch (stmt.kind()) {
22             case Statement::Kind::kBlock:
23             case Statement::Kind::kSwitchCase:
24                 return INHERITED::visitStatement(stmt);
25 
26             case Statement::Kind::kReturn:
27                 // Returns are an early exit regardless of the surrounding control structures.
28                 return fConditionalExits ? fInConditional : !fInConditional;
29 
30             case Statement::Kind::kContinue:
31                 // Continues are an early exit from switches, but not loops.
32                 return !fInLoop &&
33                        (fConditionalExits ? fInConditional : !fInConditional);
34 
35             case Statement::Kind::kBreak:
36                 // Breaks cannot escape from switches or loops.
37                 return !fInLoop && !fInSwitch &&
38                        (fConditionalExits ? fInConditional : !fInConditional);
39 
40             case Statement::Kind::kIf: {
41                 ++fInConditional;
42                 bool result = INHERITED::visitStatement(stmt);
43                 --fInConditional;
44                 return result;
45             }
46 
47             case Statement::Kind::kFor:
48             case Statement::Kind::kDo: {
49                 // Loops are treated as conditionals because a loop could potentially execute zero
50                 // times. We don't have a straightforward way to determine that a loop definitely
51                 // executes at least once.
52                 ++fInConditional;
53                 ++fInLoop;
54                 bool result = INHERITED::visitStatement(stmt);
55                 --fInLoop;
56                 --fInConditional;
57                 return result;
58             }
59 
60             case Statement::Kind::kSwitch: {
61                 ++fInSwitch;
62                 bool result = INHERITED::visitStatement(stmt);
63                 --fInSwitch;
64                 return result;
65             }
66 
67             default:
68                 return false;
69         }
70     }
71 
72     bool fConditionalExits = false;
73     int fInConditional = 0;
74     int fInLoop = 0;
75     int fInSwitch = 0;
76     using INHERITED = ProgramVisitor;
77 };
78 
79 }  // namespace
80 
SwitchCaseContainsUnconditionalExit(Statement & stmt)81 bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) {
82     return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt);
83 }
84 
SwitchCaseContainsConditionalExit(Statement & stmt)85 bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) {
86     return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt);
87 }
88 
89 }  // namespace SkSL
90