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