/* * Copyright 2024 Google LLC * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "include/core/SkTypes.h" #include "src/core/SkTHash.h" #include "src/sksl/SkSLAnalysis.h" #include "src/sksl/SkSLContext.h" #include "src/sksl/SkSLErrorReporter.h" #include "src/sksl/analysis/SkSLProgramVisitor.h" #include "src/sksl/ir/SkSLProgram.h" #include "src/sksl/ir/SkSLStatement.h" #include "src/sksl/ir/SkSLSymbolTable.h" #include "src/sksl/ir/SkSLVarDeclarations.h" #include "src/sksl/ir/SkSLVariable.h" #include #include #include #include using namespace skia_private; namespace SkSL { class Expression; class ProgramElement; class Symbol; void Analysis::CheckSymbolTableCorrectness(const Program& program) { const Context& context = *program.fContext; class SymbolTableCorrectnessVisitor : public ProgramVisitor { public: SymbolTableCorrectnessVisitor(const Context& c, SymbolTable* sym) : fContext(c) , fSymbolTableStack({sym}) {} using ProgramVisitor::visitProgramElement; bool visitStatement(const Statement& stmt) override { Analysis::SymbolTableStackBuilder symbolTableStackBuilder(&stmt, &fSymbolTableStack); if (stmt.is()) { // Check the top of the symbol table stack to see if it contains this exact symbol. const VarDeclaration& vardecl = stmt.as(); bool containsSymbol = false; // We want to do an exact Symbol* comparison in just one symbol table; we don't want // to look up by name, and we don't want to walk the symbol table tree. This makes // SymbolTable::find() an inappropriate tool for the job. Instead, we can iterate // the symbol table's contents directly and check for a pointer match. fSymbolTableStack.back()->foreach([&](std::string_view, const Symbol* symbol) { if (symbol == vardecl.var()) { containsSymbol = true; } }); if (!containsSymbol) { fContext.fErrors->error(vardecl.position(), "internal error (variable '" + std::string(vardecl.var()->name()) + "' is incorrectly scoped)"); } } return INHERITED::visitStatement(stmt); } bool visitExpression(const Expression&) override { return false; } private: using INHERITED = ProgramVisitor; const Context& fContext; std::vector fSymbolTableStack; }; SymbolTableCorrectnessVisitor visitor{context, program.fSymbols.get()}; for (const std::unique_ptr& pe : program.fOwnedElements) { visitor.visitProgramElement(*pe); } } } // namespace SkSL