xref: /aosp_15_r20/external/skia/src/sksl/SkSLAnalysis.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2020 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkSLAnalysis_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define SkSLAnalysis_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker 
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkSLSampleUsage.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
15*c8dee2aaSAndroid Build Coastguard Worker #include <memory>
16*c8dee2aaSAndroid Build Coastguard Worker #include <vector>
17*c8dee2aaSAndroid Build Coastguard Worker 
18*c8dee2aaSAndroid Build Coastguard Worker namespace SkSL {
19*c8dee2aaSAndroid Build Coastguard Worker 
20*c8dee2aaSAndroid Build Coastguard Worker class Context;
21*c8dee2aaSAndroid Build Coastguard Worker class ErrorReporter;
22*c8dee2aaSAndroid Build Coastguard Worker class Expression;
23*c8dee2aaSAndroid Build Coastguard Worker class FunctionDeclaration;
24*c8dee2aaSAndroid Build Coastguard Worker class FunctionDefinition;
25*c8dee2aaSAndroid Build Coastguard Worker class Position;
26*c8dee2aaSAndroid Build Coastguard Worker class ProgramElement;
27*c8dee2aaSAndroid Build Coastguard Worker class ProgramUsage;
28*c8dee2aaSAndroid Build Coastguard Worker class Statement;
29*c8dee2aaSAndroid Build Coastguard Worker class SymbolTable;
30*c8dee2aaSAndroid Build Coastguard Worker class Variable;
31*c8dee2aaSAndroid Build Coastguard Worker class VariableReference;
32*c8dee2aaSAndroid Build Coastguard Worker enum class VariableRefKind : int8_t;
33*c8dee2aaSAndroid Build Coastguard Worker struct ForLoopPositions;
34*c8dee2aaSAndroid Build Coastguard Worker struct LoopUnrollInfo;
35*c8dee2aaSAndroid Build Coastguard Worker struct Module;
36*c8dee2aaSAndroid Build Coastguard Worker struct Program;
37*c8dee2aaSAndroid Build Coastguard Worker 
38*c8dee2aaSAndroid Build Coastguard Worker /**
39*c8dee2aaSAndroid Build Coastguard Worker  * Provides utilities for analyzing SkSL statically before it's composed into a full program.
40*c8dee2aaSAndroid Build Coastguard Worker  */
41*c8dee2aaSAndroid Build Coastguard Worker namespace Analysis {
42*c8dee2aaSAndroid Build Coastguard Worker 
43*c8dee2aaSAndroid Build Coastguard Worker /**
44*c8dee2aaSAndroid Build Coastguard Worker  * Determines how `program` samples `child`. By default, assumes that the sample coords might be
45*c8dee2aaSAndroid Build Coastguard Worker  * modified, so `child.eval(sampleCoords)` is treated as Explicit. If writesToSampleCoords is false,
46*c8dee2aaSAndroid Build Coastguard Worker  * treats that as PassThrough, instead. If elidedSampleCoordCount is provided, the pointed to value
47*c8dee2aaSAndroid Build Coastguard Worker  * will be incremented by the number of sample calls where the above rewrite was performed.
48*c8dee2aaSAndroid Build Coastguard Worker  */
49*c8dee2aaSAndroid Build Coastguard Worker SampleUsage GetSampleUsage(const Program& program,
50*c8dee2aaSAndroid Build Coastguard Worker                            const Variable& child,
51*c8dee2aaSAndroid Build Coastguard Worker                            bool writesToSampleCoords = true,
52*c8dee2aaSAndroid Build Coastguard Worker                            int* elidedSampleCoordCount = nullptr);
53*c8dee2aaSAndroid Build Coastguard Worker 
54*c8dee2aaSAndroid Build Coastguard Worker bool ReferencesBuiltin(const Program& program, int builtin);
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker bool ReferencesSampleCoords(const Program& program);
57*c8dee2aaSAndroid Build Coastguard Worker bool ReferencesFragCoords(const Program& program);
58*c8dee2aaSAndroid Build Coastguard Worker 
59*c8dee2aaSAndroid Build Coastguard Worker bool CallsSampleOutsideMain(const Program& program);
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker bool CallsColorTransformIntrinsics(const Program& program);
62*c8dee2aaSAndroid Build Coastguard Worker 
63*c8dee2aaSAndroid Build Coastguard Worker /**
64*c8dee2aaSAndroid Build Coastguard Worker  * Determines if `function` always returns an opaque color (a vec4 where the last component is known
65*c8dee2aaSAndroid Build Coastguard Worker  * to be 1). This is conservative, and based on constant expression analysis.
66*c8dee2aaSAndroid Build Coastguard Worker  */
67*c8dee2aaSAndroid Build Coastguard Worker bool ReturnsOpaqueColor(const FunctionDefinition& function);
68*c8dee2aaSAndroid Build Coastguard Worker 
69*c8dee2aaSAndroid Build Coastguard Worker /**
70*c8dee2aaSAndroid Build Coastguard Worker  * Determines if `function` is a color filter which returns the alpha component of the input color
71*c8dee2aaSAndroid Build Coastguard Worker  * unchanged. This is a very conservative analysis, and only supports returning a swizzle of the
72*c8dee2aaSAndroid Build Coastguard Worker  * input color, or returning a constructor that ends with `input.a`.
73*c8dee2aaSAndroid Build Coastguard Worker  */
74*c8dee2aaSAndroid Build Coastguard Worker bool ReturnsInputAlpha(const FunctionDefinition& function, const ProgramUsage& usage);
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker /**
77*c8dee2aaSAndroid Build Coastguard Worker  * Checks for recursion or overly-deep function-call chains, and rejects programs which have them.
78*c8dee2aaSAndroid Build Coastguard Worker  */
79*c8dee2aaSAndroid Build Coastguard Worker bool CheckProgramStructure(const Program& program);
80*c8dee2aaSAndroid Build Coastguard Worker 
81*c8dee2aaSAndroid Build Coastguard Worker /** Determines if `expr` contains a reference to the variable sk_RTAdjust. */
82*c8dee2aaSAndroid Build Coastguard Worker bool ContainsRTAdjust(const Expression& expr);
83*c8dee2aaSAndroid Build Coastguard Worker 
84*c8dee2aaSAndroid Build Coastguard Worker /** Determines if `expr` contains a reference to variable `var`. */
85*c8dee2aaSAndroid Build Coastguard Worker bool ContainsVariable(const Expression& expr, const Variable& var);
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker /** Determines if `expr` has any side effects. (Is the expression state-altering or pure?) */
88*c8dee2aaSAndroid Build Coastguard Worker bool HasSideEffects(const Expression& expr);
89*c8dee2aaSAndroid Build Coastguard Worker 
90*c8dee2aaSAndroid Build Coastguard Worker /** Determines if `expr` is a compile-time constant (composed of just constructors and literals). */
91*c8dee2aaSAndroid Build Coastguard Worker bool IsCompileTimeConstant(const Expression& expr);
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker /**
94*c8dee2aaSAndroid Build Coastguard Worker  * Determines if `expr` is a dynamically-uniform expression; this returns true if the expression
95*c8dee2aaSAndroid Build Coastguard Worker  * could be evaluated at compile time if uniform values were known.
96*c8dee2aaSAndroid Build Coastguard Worker  */
97*c8dee2aaSAndroid Build Coastguard Worker bool IsDynamicallyUniformExpression(const Expression& expr);
98*c8dee2aaSAndroid Build Coastguard Worker 
99*c8dee2aaSAndroid Build Coastguard Worker /**
100*c8dee2aaSAndroid Build Coastguard Worker  * Detect an orphaned variable declaration outside of a scope, e.g. if (true) int a;. Returns
101*c8dee2aaSAndroid Build Coastguard Worker  * true if an error was reported.
102*c8dee2aaSAndroid Build Coastguard Worker  */
103*c8dee2aaSAndroid Build Coastguard Worker bool DetectVarDeclarationWithoutScope(const Statement& stmt, ErrorReporter* errors = nullptr);
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker int NodeCountUpToLimit(const FunctionDefinition& function, int limit);
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker /**
108*c8dee2aaSAndroid Build Coastguard Worker  * Finds unconditional exits from a switch-case. Returns true if this statement unconditionally
109*c8dee2aaSAndroid Build Coastguard Worker  * causes an exit from this switch (via continue, break or return).
110*c8dee2aaSAndroid Build Coastguard Worker  */
111*c8dee2aaSAndroid Build Coastguard Worker bool SwitchCaseContainsUnconditionalExit(const Statement& stmt);
112*c8dee2aaSAndroid Build Coastguard Worker 
113*c8dee2aaSAndroid Build Coastguard Worker /**
114*c8dee2aaSAndroid Build Coastguard Worker  * Finds conditional exits from a switch-case. Returns true if this statement contains a
115*c8dee2aaSAndroid Build Coastguard Worker  * conditional that wraps a potential exit from the switch (via continue, break or return).
116*c8dee2aaSAndroid Build Coastguard Worker  */
117*c8dee2aaSAndroid Build Coastguard Worker bool SwitchCaseContainsConditionalExit(const Statement& stmt);
118*c8dee2aaSAndroid Build Coastguard Worker 
119*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<ProgramUsage> GetUsage(const Program& program);
120*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<ProgramUsage> GetUsage(const Module& module);
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker /** Returns true if the passed-in statement might alter `var`. */
123*c8dee2aaSAndroid Build Coastguard Worker bool StatementWritesToVariable(const Statement& stmt, const Variable& var);
124*c8dee2aaSAndroid Build Coastguard Worker 
125*c8dee2aaSAndroid Build Coastguard Worker /**
126*c8dee2aaSAndroid Build Coastguard Worker  * Detects if the passed-in block contains a `continue`, `break` or `return` that could directly
127*c8dee2aaSAndroid Build Coastguard Worker  * affect its control flow. (A `continue` or `break` nested inside an inner loop/switch will not
128*c8dee2aaSAndroid Build Coastguard Worker  * affect the loop, but a `return` will.)
129*c8dee2aaSAndroid Build Coastguard Worker  */
130*c8dee2aaSAndroid Build Coastguard Worker struct LoopControlFlowInfo {
131*c8dee2aaSAndroid Build Coastguard Worker     bool fHasContinue = false;
132*c8dee2aaSAndroid Build Coastguard Worker     bool fHasBreak = false;
133*c8dee2aaSAndroid Build Coastguard Worker     bool fHasReturn = false;
134*c8dee2aaSAndroid Build Coastguard Worker };
135*c8dee2aaSAndroid Build Coastguard Worker LoopControlFlowInfo GetLoopControlFlowInfo(const Statement& stmt);
136*c8dee2aaSAndroid Build Coastguard Worker 
137*c8dee2aaSAndroid Build Coastguard Worker /**
138*c8dee2aaSAndroid Build Coastguard Worker  * Returns true if the expression can be assigned-into. Pass `info` if you want to know the
139*c8dee2aaSAndroid Build Coastguard Worker  * VariableReference that will be written to. Pass `errors` to report an error for expressions that
140*c8dee2aaSAndroid Build Coastguard Worker  * are not actually writable.
141*c8dee2aaSAndroid Build Coastguard Worker  */
142*c8dee2aaSAndroid Build Coastguard Worker struct AssignmentInfo {
143*c8dee2aaSAndroid Build Coastguard Worker     VariableReference* fAssignedVar = nullptr;
144*c8dee2aaSAndroid Build Coastguard Worker };
145*c8dee2aaSAndroid Build Coastguard Worker bool IsAssignable(Expression& expr, AssignmentInfo* info = nullptr,
146*c8dee2aaSAndroid Build Coastguard Worker                   ErrorReporter* errors = nullptr);
147*c8dee2aaSAndroid Build Coastguard Worker 
148*c8dee2aaSAndroid Build Coastguard Worker /**
149*c8dee2aaSAndroid Build Coastguard Worker  * Updates the `refKind` field of the VariableReference at the top level of `expr`.
150*c8dee2aaSAndroid Build Coastguard Worker  * If `expr` can be assigned to (`IsAssignable`), true is returned and no errors are reported.
151*c8dee2aaSAndroid Build Coastguard Worker  * If not, false is returned. and an error is reported if `errors` is non-null.
152*c8dee2aaSAndroid Build Coastguard Worker  */
153*c8dee2aaSAndroid Build Coastguard Worker bool UpdateVariableRefKind(Expression* expr, VariableRefKind kind, ErrorReporter* errors = nullptr);
154*c8dee2aaSAndroid Build Coastguard Worker 
155*c8dee2aaSAndroid Build Coastguard Worker /**
156*c8dee2aaSAndroid Build Coastguard Worker  * A "trivial" expression is one where we'd feel comfortable cloning it multiple times in
157*c8dee2aaSAndroid Build Coastguard Worker  * the code, without worrying about incurring a performance penalty. Examples:
158*c8dee2aaSAndroid Build Coastguard Worker  * - true
159*c8dee2aaSAndroid Build Coastguard Worker  * - 3.14159265
160*c8dee2aaSAndroid Build Coastguard Worker  * - myIntVariable
161*c8dee2aaSAndroid Build Coastguard Worker  * - myColor.rgb
162*c8dee2aaSAndroid Build Coastguard Worker  * - myArray[123]
163*c8dee2aaSAndroid Build Coastguard Worker  * - myStruct.myField
164*c8dee2aaSAndroid Build Coastguard Worker  * - half4(0)
165*c8dee2aaSAndroid Build Coastguard Worker  * - !myBoolean
166*c8dee2aaSAndroid Build Coastguard Worker  * - +myValue
167*c8dee2aaSAndroid Build Coastguard Worker  * - -myValue
168*c8dee2aaSAndroid Build Coastguard Worker  * - ~myInteger
169*c8dee2aaSAndroid Build Coastguard Worker  *
170*c8dee2aaSAndroid Build Coastguard Worker  * Trivial-ness is stackable. Somewhat large expressions can occasionally make the cut:
171*c8dee2aaSAndroid Build Coastguard Worker  * - half4(myColor.a)
172*c8dee2aaSAndroid Build Coastguard Worker  * - myStruct.myArrayField[7].xzy
173*c8dee2aaSAndroid Build Coastguard Worker  */
174*c8dee2aaSAndroid Build Coastguard Worker bool IsTrivialExpression(const Expression& expr);
175*c8dee2aaSAndroid Build Coastguard Worker 
176*c8dee2aaSAndroid Build Coastguard Worker /**
177*c8dee2aaSAndroid Build Coastguard Worker  * Returns true if both expression trees are the same. Used by the optimizer to look for self-
178*c8dee2aaSAndroid Build Coastguard Worker  * assignment or self-comparison; won't necessarily catch complex cases. Rejects expressions
179*c8dee2aaSAndroid Build Coastguard Worker  * that may cause side effects.
180*c8dee2aaSAndroid Build Coastguard Worker  */
181*c8dee2aaSAndroid Build Coastguard Worker bool IsSameExpressionTree(const Expression& left, const Expression& right);
182*c8dee2aaSAndroid Build Coastguard Worker 
183*c8dee2aaSAndroid Build Coastguard Worker /**
184*c8dee2aaSAndroid Build Coastguard Worker  * Returns true if expr is a constant-expression, as defined by GLSL 1.0, section 5.10.
185*c8dee2aaSAndroid Build Coastguard Worker  * A constant expression is one of:
186*c8dee2aaSAndroid Build Coastguard Worker  * - A literal value
187*c8dee2aaSAndroid Build Coastguard Worker  * - A global or local variable qualified as 'const', excluding function parameters
188*c8dee2aaSAndroid Build Coastguard Worker  * - An expression formed by an operator on operands that are constant expressions, including
189*c8dee2aaSAndroid Build Coastguard Worker  *   getting an element of a constant vector or a constant matrix, or a field of a constant
190*c8dee2aaSAndroid Build Coastguard Worker  *   structure
191*c8dee2aaSAndroid Build Coastguard Worker  * - A constructor whose arguments are all constant expressions
192*c8dee2aaSAndroid Build Coastguard Worker  * - A built-in function call whose arguments are all constant expressions, with the exception
193*c8dee2aaSAndroid Build Coastguard Worker  *   of the texture lookup functions
194*c8dee2aaSAndroid Build Coastguard Worker  */
195*c8dee2aaSAndroid Build Coastguard Worker bool IsConstantExpression(const Expression& expr);
196*c8dee2aaSAndroid Build Coastguard Worker 
197*c8dee2aaSAndroid Build Coastguard Worker /**
198*c8dee2aaSAndroid Build Coastguard Worker  * Ensures that any index-expressions inside of for-loops qualify as 'constant-index-expressions' as
199*c8dee2aaSAndroid Build Coastguard Worker  * defined by GLSL 1.0, Appendix A, Section 5. A constant-index-expression is:
200*c8dee2aaSAndroid Build Coastguard Worker  * - A constant-expression
201*c8dee2aaSAndroid Build Coastguard Worker  * - Loop indices (as defined in Appendix A, Section 4)
202*c8dee2aaSAndroid Build Coastguard Worker  * - Expressions composed of both of the above
203*c8dee2aaSAndroid Build Coastguard Worker  */
204*c8dee2aaSAndroid Build Coastguard Worker void ValidateIndexingForES2(const ProgramElement& pe, ErrorReporter& errors);
205*c8dee2aaSAndroid Build Coastguard Worker 
206*c8dee2aaSAndroid Build Coastguard Worker /**
207*c8dee2aaSAndroid Build Coastguard Worker  * Emits an internal error if a VarDeclaration exists without a matching entry in the nearest
208*c8dee2aaSAndroid Build Coastguard Worker  * SymbolTable.
209*c8dee2aaSAndroid Build Coastguard Worker  */
210*c8dee2aaSAndroid Build Coastguard Worker void CheckSymbolTableCorrectness(const Program& program);
211*c8dee2aaSAndroid Build Coastguard Worker 
212*c8dee2aaSAndroid Build Coastguard Worker /**
213*c8dee2aaSAndroid Build Coastguard Worker  * Ensures that a for-loop meets the strict requirements of The OpenGL ES Shading Language 1.00,
214*c8dee2aaSAndroid Build Coastguard Worker  * Appendix A, Section 4.
215*c8dee2aaSAndroid Build Coastguard Worker  * If the requirements are met, information about the loop's structure is returned.
216*c8dee2aaSAndroid Build Coastguard Worker  * If the requirements are not met, the problem is reported via `errors` (if not nullptr), and
217*c8dee2aaSAndroid Build Coastguard Worker  * null is returned.
218*c8dee2aaSAndroid Build Coastguard Worker  * The loop test-expression may be altered by this check. For example, a loop like this:
219*c8dee2aaSAndroid Build Coastguard Worker  *     for (float x = 1.0; x != 0.0; x -= 0.01) {...}
220*c8dee2aaSAndroid Build Coastguard Worker  * appears to be ES2-safe, but due to floating-point rounding error, it may not actually terminate.
221*c8dee2aaSAndroid Build Coastguard Worker  * We rewrite the test condition to `x > 0.0` in order to ensure loop termination.
222*c8dee2aaSAndroid Build Coastguard Worker  */
223*c8dee2aaSAndroid Build Coastguard Worker std::unique_ptr<LoopUnrollInfo> GetLoopUnrollInfo(const Context& context,
224*c8dee2aaSAndroid Build Coastguard Worker                                                   Position pos,
225*c8dee2aaSAndroid Build Coastguard Worker                                                   const ForLoopPositions& positions,
226*c8dee2aaSAndroid Build Coastguard Worker                                                   const Statement* loopInitializer,
227*c8dee2aaSAndroid Build Coastguard Worker                                                   std::unique_ptr<Expression>* loopTestPtr,
228*c8dee2aaSAndroid Build Coastguard Worker                                                   const Expression* loopNext,
229*c8dee2aaSAndroid Build Coastguard Worker                                                   const Statement* loopStatement,
230*c8dee2aaSAndroid Build Coastguard Worker                                                   ErrorReporter* errors);
231*c8dee2aaSAndroid Build Coastguard Worker 
232*c8dee2aaSAndroid Build Coastguard Worker /** Detects functions that fail to return a value on at least one path. */
233*c8dee2aaSAndroid Build Coastguard Worker bool CanExitWithoutReturningValue(const FunctionDeclaration& funcDecl, const Statement& body);
234*c8dee2aaSAndroid Build Coastguard Worker 
235*c8dee2aaSAndroid Build Coastguard Worker /** Determines if a given function has multiple and/or early returns. */
236*c8dee2aaSAndroid Build Coastguard Worker enum class ReturnComplexity {
237*c8dee2aaSAndroid Build Coastguard Worker     kSingleSafeReturn,
238*c8dee2aaSAndroid Build Coastguard Worker     kScopedReturns,
239*c8dee2aaSAndroid Build Coastguard Worker     kEarlyReturns,
240*c8dee2aaSAndroid Build Coastguard Worker };
241*c8dee2aaSAndroid Build Coastguard Worker ReturnComplexity GetReturnComplexity(const FunctionDefinition& funcDef);
242*c8dee2aaSAndroid Build Coastguard Worker 
243*c8dee2aaSAndroid Build Coastguard Worker /**
244*c8dee2aaSAndroid Build Coastguard Worker  * Runs at finalization time to perform any last-minute correctness checks:
245*c8dee2aaSAndroid Build Coastguard Worker  * - Reports dangling FunctionReference or TypeReference expressions
246*c8dee2aaSAndroid Build Coastguard Worker  * - Reports function `out` params which are never written to (structs are currently exempt)
247*c8dee2aaSAndroid Build Coastguard Worker  */
248*c8dee2aaSAndroid Build Coastguard Worker void DoFinalizationChecks(const Program& program);
249*c8dee2aaSAndroid Build Coastguard Worker 
250*c8dee2aaSAndroid Build Coastguard Worker /**
251*c8dee2aaSAndroid Build Coastguard Worker  * Error checks compute shader in/outs and returns a vector containing them ordered by location.
252*c8dee2aaSAndroid Build Coastguard Worker  */
253*c8dee2aaSAndroid Build Coastguard Worker skia_private::TArray<const SkSL::Variable*> GetComputeShaderMainParams(const Context& context,
254*c8dee2aaSAndroid Build Coastguard Worker                                                                        const Program& program);
255*c8dee2aaSAndroid Build Coastguard Worker 
256*c8dee2aaSAndroid Build Coastguard Worker /**
257*c8dee2aaSAndroid Build Coastguard Worker  * Tracks the symbol table stack, in conjunction with a ProgramVisitor. Inside `visitStatement`,
258*c8dee2aaSAndroid Build Coastguard Worker  * pass the current statement and a symbol-table vector to a SymbolTableStackBuilder and the symbol
259*c8dee2aaSAndroid Build Coastguard Worker  * table stack will be maintained automatically.
260*c8dee2aaSAndroid Build Coastguard Worker  */
261*c8dee2aaSAndroid Build Coastguard Worker class SymbolTableStackBuilder {
262*c8dee2aaSAndroid Build Coastguard Worker public:
263*c8dee2aaSAndroid Build Coastguard Worker     // If the passed-in statement holds a symbol table, adds it to the stack.
264*c8dee2aaSAndroid Build Coastguard Worker     SymbolTableStackBuilder(const Statement* stmt, std::vector<SymbolTable*>* stack);
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker     // If a symbol table was added to the stack earlier, removes it from the stack.
267*c8dee2aaSAndroid Build Coastguard Worker     ~SymbolTableStackBuilder();
268*c8dee2aaSAndroid Build Coastguard Worker 
269*c8dee2aaSAndroid Build Coastguard Worker     // Returns true if an entry was added to the symbol-table stack.
foundSymbolTable()270*c8dee2aaSAndroid Build Coastguard Worker     bool foundSymbolTable() {
271*c8dee2aaSAndroid Build Coastguard Worker         return fStackToPop != nullptr;
272*c8dee2aaSAndroid Build Coastguard Worker     }
273*c8dee2aaSAndroid Build Coastguard Worker 
274*c8dee2aaSAndroid Build Coastguard Worker private:
275*c8dee2aaSAndroid Build Coastguard Worker     std::vector<SymbolTable*>* fStackToPop = nullptr;
276*c8dee2aaSAndroid Build Coastguard Worker };
277*c8dee2aaSAndroid Build Coastguard Worker 
278*c8dee2aaSAndroid Build Coastguard Worker }  // namespace Analysis
279*c8dee2aaSAndroid Build Coastguard Worker }  // namespace SkSL
280*c8dee2aaSAndroid Build Coastguard Worker 
281*c8dee2aaSAndroid Build Coastguard Worker #endif
282