1 /* 2 * Copyright 2024 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 "include/core/SkTypes.h" 9 #include "src/core/SkTHash.h" 10 #include "src/sksl/SkSLAnalysis.h" 11 #include "src/sksl/SkSLContext.h" 12 #include "src/sksl/SkSLErrorReporter.h" 13 #include "src/sksl/analysis/SkSLProgramVisitor.h" 14 #include "src/sksl/ir/SkSLProgram.h" 15 #include "src/sksl/ir/SkSLStatement.h" 16 #include "src/sksl/ir/SkSLSymbolTable.h" 17 #include "src/sksl/ir/SkSLVarDeclarations.h" 18 #include "src/sksl/ir/SkSLVariable.h" 19 20 #include <memory> 21 #include <string> 22 #include <string_view> 23 #include <vector> 24 25 using namespace skia_private; 26 27 namespace SkSL { 28 29 class Expression; 30 class ProgramElement; 31 class Symbol; 32 CheckSymbolTableCorrectness(const Program & program)33void Analysis::CheckSymbolTableCorrectness(const Program& program) { 34 const Context& context = *program.fContext; 35 36 class SymbolTableCorrectnessVisitor : public ProgramVisitor { 37 public: 38 SymbolTableCorrectnessVisitor(const Context& c, SymbolTable* sym) 39 : fContext(c) 40 , fSymbolTableStack({sym}) {} 41 42 using ProgramVisitor::visitProgramElement; 43 44 bool visitStatement(const Statement& stmt) override { 45 Analysis::SymbolTableStackBuilder symbolTableStackBuilder(&stmt, &fSymbolTableStack); 46 if (stmt.is<VarDeclaration>()) { 47 // Check the top of the symbol table stack to see if it contains this exact symbol. 48 const VarDeclaration& vardecl = stmt.as<VarDeclaration>(); 49 bool containsSymbol = false; 50 51 // We want to do an exact Symbol* comparison in just one symbol table; we don't want 52 // to look up by name, and we don't want to walk the symbol table tree. This makes 53 // SymbolTable::find() an inappropriate tool for the job. Instead, we can iterate 54 // the symbol table's contents directly and check for a pointer match. 55 fSymbolTableStack.back()->foreach([&](std::string_view, const Symbol* symbol) { 56 if (symbol == vardecl.var()) { 57 containsSymbol = true; 58 } 59 }); 60 if (!containsSymbol) { 61 fContext.fErrors->error(vardecl.position(), "internal error (variable '" + 62 std::string(vardecl.var()->name()) + 63 "' is incorrectly scoped)"); 64 } 65 } 66 return INHERITED::visitStatement(stmt); 67 } 68 69 bool visitExpression(const Expression&) override { 70 return false; 71 } 72 73 private: 74 using INHERITED = ProgramVisitor; 75 76 const Context& fContext; 77 std::vector<SymbolTable*> fSymbolTableStack; 78 }; 79 80 SymbolTableCorrectnessVisitor visitor{context, program.fSymbols.get()}; 81 for (const std::unique_ptr<ProgramElement>& pe : program.fOwnedElements) { 82 visitor.visitProgramElement(*pe); 83 } 84 } 85 86 } // namespace SkSL 87