1 /* 2 * Copyright 2023 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 "src/sksl/analysis/SkSLProgramVisitor.h" 11 #include "src/sksl/ir/SkSLIRNode.h" 12 #include "src/sksl/ir/SkSLStatement.h" 13 14 namespace SkSL { 15 16 class Expression; 17 18 namespace Analysis { 19 namespace { 20 21 class LoopControlFlowVisitor : public ProgramVisitor { 22 public: LoopControlFlowVisitor()23 LoopControlFlowVisitor() {} 24 visitExpression(const Expression & expr)25 bool visitExpression(const Expression& expr) override { 26 // We can avoid processing expressions entirely. 27 return false; 28 } 29 visitStatement(const Statement & stmt)30 bool visitStatement(const Statement& stmt) override { 31 switch (stmt.kind()) { 32 case Statement::Kind::kContinue: 33 // A continue only affects the control flow of the loop if it's not nested inside 34 // another looping structure. (Inside a switch, SkSL disallows continue entirely.) 35 fResult.fHasContinue |= (fDepth == 0); 36 break; 37 38 case Statement::Kind::kBreak: 39 // A break only affects the control flow of the loop if it's not nested inside 40 // another loop/switch structure. 41 fResult.fHasBreak |= (fDepth == 0); 42 break; 43 44 case Statement::Kind::kReturn: 45 // A return will abort the loop's control flow no matter how deeply it is nested. 46 fResult.fHasReturn = true; 47 break; 48 49 case Statement::Kind::kFor: 50 case Statement::Kind::kDo: 51 case Statement::Kind::kSwitch: { 52 ++fDepth; 53 bool done = ProgramVisitor::visitStatement(stmt); 54 --fDepth; 55 return done; 56 } 57 58 default: 59 return ProgramVisitor::visitStatement(stmt); 60 } 61 62 // If we've already found everything we're hunting for, we can stop searching early. 63 return fResult.fHasContinue && fResult.fHasBreak && fResult.fHasReturn; 64 } 65 66 LoopControlFlowInfo fResult; 67 int fDepth = 0; 68 }; 69 70 } // namespace 71 GetLoopControlFlowInfo(const Statement & stmt)72LoopControlFlowInfo GetLoopControlFlowInfo(const Statement& stmt) { 73 LoopControlFlowVisitor visitor; 74 visitor.visitStatement(stmt); 75 return visitor.fResult; 76 } 77 78 } // namespace Analysis 79 } // namespace SkSL 80