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)81bool Analysis::SwitchCaseContainsUnconditionalExit(Statement& stmt) { 82 return SwitchCaseContainsExit{/*conditionalExits=*/false}.visitStatement(stmt); 83 } 84 SwitchCaseContainsConditionalExit(Statement & stmt)85bool Analysis::SwitchCaseContainsConditionalExit(Statement& stmt) { 86 return SwitchCaseContainsExit{/*conditionalExits=*/true}.visitStatement(stmt); 87 } 88 89 } // namespace SkSL 90