Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
SkSLGetReturnComplexity.cpp
Go to the documentation of this file.
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
15
16#include <algorithm>
17#include <memory>
18
19namespace SkSL {
20
21class Expression;
22
24 class CountReturnsAtEndOfControlFlow : public ProgramVisitor {
25 public:
26 CountReturnsAtEndOfControlFlow(const FunctionDefinition& funcDef) {
27 this->visitProgramElement(funcDef);
28 }
29
30 bool visitExpression(const Expression& expr) override {
31 // Do not recurse into expressions.
32 return false;
33 }
34
35 bool visitStatement(const Statement& stmt) override {
36 switch (stmt.kind()) {
37 case Statement::Kind::kBlock: {
38 // Check only the last statement of a block.
39 const auto& block = stmt.as<Block>();
40 return block.children().size() &&
41 this->visitStatement(*block.children().back());
42 }
43 case Statement::Kind::kSwitch:
44 case Statement::Kind::kDo:
45 case Statement::Kind::kFor:
46 // Don't introspect switches or loop structures at all.
47 return false;
48
49 case Statement::Kind::kReturn:
50 ++fNumReturns;
51 [[fallthrough]];
52
53 default:
54 return INHERITED::visitStatement(stmt);
55 }
56 }
57
58 int fNumReturns = 0;
60 };
61
62 return CountReturnsAtEndOfControlFlow{funcDef}.fNumReturns;
63}
64
66public:
67 CountReturnsWithLimit(const FunctionDefinition& funcDef, int limit) : fLimit(limit) {
68 this->visitProgramElement(funcDef);
69 }
70
71 bool visitExpression(const Expression& expr) override {
72 // Do not recurse into expressions.
73 return false;
74 }
75
76 bool visitStatement(const Statement& stmt) override {
77 switch (stmt.kind()) {
78 case Statement::Kind::kReturn: {
81 return (fNumReturns >= fLimit) || INHERITED::visitStatement(stmt);
82 }
83 case Statement::Kind::kVarDeclaration: {
84 if (fScopedBlockDepth > 1) {
85 fVariablesInBlocks = true;
86 }
87 return INHERITED::visitStatement(stmt);
88 }
89 case Statement::Kind::kBlock: {
90 int depthIncrement = stmt.as<Block>().isScope() ? 1 : 0;
91 fScopedBlockDepth += depthIncrement;
93 fScopedBlockDepth -= depthIncrement;
94 if (fNumReturns == 0 && fScopedBlockDepth <= 1) {
95 // If closing this block puts us back at the top level, and we haven't
96 // encountered any return statements yet, any vardecls we may have encountered
97 // up until this point can be ignored. They are out of scope now, and they were
98 // never used in a return statement.
99 fVariablesInBlocks = false;
100 }
101 return result;
102 }
103 default:
104 return INHERITED::visitStatement(stmt);
105 }
106 }
107
108 int fNumReturns = 0;
110 int fLimit = 0;
112 bool fVariablesInBlocks = false;
114};
115
117 int returnsAtEndOfControlFlow = count_returns_at_end_of_control_flow(funcDef);
118 CountReturnsWithLimit counter{funcDef, returnsAtEndOfControlFlow + 1};
119 if (counter.fNumReturns > returnsAtEndOfControlFlow) {
120 return ReturnComplexity::kEarlyReturns;
121 }
122 if (counter.fNumReturns > 1) {
123 return ReturnComplexity::kScopedReturns;
124 }
125 if (counter.fVariablesInBlocks && counter.fDeepestReturn > 1) {
126 return ReturnComplexity::kScopedReturns;
127 }
128 return ReturnComplexity::kSingleSafeReturn;
129}
130
131} // namespace SkSL
#define INHERITED(method,...)
const StatementArray & children() const
Definition SkSLBlock.h:71
bool visitExpression(const Expression &expr) override
CountReturnsWithLimit(const FunctionDefinition &funcDef, int limit)
bool visitStatement(const Statement &stmt) override
const T & as() const
Definition SkSLIRNode.h:133
Kind kind() const
virtual bool visitStatement(typename T::Statement &statement)
virtual bool visitProgramElement(typename T::ProgramElement &programElement)
int size() const
Definition SkTArray.h:416
GAsyncResult * result
ReturnComplexity GetReturnComplexity(const FunctionDefinition &funcDef)
static int count_returns_at_end_of_control_flow(const FunctionDefinition &funcDef)