// Copyright 2021 The Tint Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef FUZZERS_TINT_AST_FUZZER_UTIL_H_ #define FUZZERS_TINT_AST_FUZZER_UTIL_H_ #include #include "src/ast/module.h" #include "src/ast/variable_decl_statement.h" #include "src/castable.h" #include "src/program.h" #include "src/sem/block_statement.h" #include "src/sem/function.h" #include "src/sem/statement.h" #include "src/sem/variable.h" namespace tint { namespace fuzzers { namespace ast_fuzzer { namespace util { /// @file /// @brief Returns all in-scope variables (including formal function parameters) /// related to statement `curr_stmt`. /// /// These variables are additionally filtered by applying a predicate `pred`. /// /// @tparam Pred - a predicate that accepts a `const sem::Variable*` and returns /// `bool`. /// @param program - the program to look for variables in. /// @param curr_stmt - the current statement. Everything below it is not in /// scope. /// @param pred - a predicate (e.g. a function pointer, functor, lambda etc) of /// type `Pred`. /// @return a vector of all variables that can be accessed from `curr_stmt`. template std::vector GetAllVarsInScope( const tint::Program& program, const sem::Statement* curr_stmt, Pred&& pred) { std::vector result; // Walk up the hierarchy of blocks in which `curr_stmt` is contained. for (const auto* block = curr_stmt->Block(); block; block = tint::As(block->Parent())) { for (const auto* stmt : block->Declaration()->statements) { if (stmt == curr_stmt->Declaration()) { // `curr_stmt` was found. This is only possible if `block is the // enclosing block of `curr_stmt` since the AST nodes are not shared. // Because of all this, skip the iteration of the inner loop since // the rest of the instructions in the `block` are not visible from the // `curr_stmt`. break; } if (const auto* var_node = tint::As(stmt)) { const auto* sem_var = program.Sem().Get(var_node->variable); if (pred(sem_var)) { result.push_back(sem_var); } } } } // Process function parameters. for (const auto* param : curr_stmt->Function()->Parameters()) { if (pred(param)) { result.push_back(param); } } // Global variables do not belong to any ast::BlockStatement. for (const auto* global_decl : program.AST().GlobalDeclarations()) { if (global_decl == curr_stmt->Function()->Declaration()) { // The same situation as in the previous loop. The current function has // been reached. If there are any variables declared below, they won't be // visible in this function. Thus, exit the loop. break; } if (const auto* global_var = tint::As(global_decl)) { const auto* sem_node = program.Sem().Get(global_var); if (pred(sem_node)) { result.push_back(sem_node); } } } return result; } } // namespace util } // namespace ast_fuzzer } // namespace fuzzers } // namespace tint #endif // FUZZERS_TINT_AST_FUZZER_UTIL_H_