| // Copyright 2017 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_CCTEST_SCOPE_TEST_HELPER_H_ |
| #define V8_CCTEST_SCOPE_TEST_HELPER_H_ |
| |
| #include "src/ast/scopes.h" |
| #include "src/ast/variables.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| class ScopeTestHelper { |
| public: |
| static bool MustAllocateInContext(Variable* var) { |
| return var->scope()->MustAllocateInContext(var); |
| } |
| |
| static void AllocateWithoutVariableResolution(Scope* scope) { |
| scope->AllocateVariablesRecursively(); |
| } |
| |
| static void CompareScopes(Scope* baseline, Scope* scope, |
| bool precise_maybe_assigned) { |
| CHECK_EQ(baseline->scope_type(), scope->scope_type()); |
| CHECK_IMPLIES(baseline->is_declaration_scope(), |
| baseline->AsDeclarationScope()->function_kind() == |
| scope->AsDeclarationScope()->function_kind()); |
| |
| if (!ProducedPreParsedScopeData::ScopeNeedsData(baseline)) { |
| return; |
| } |
| |
| if (scope->is_declaration_scope() && |
| scope->AsDeclarationScope()->is_skipped_function()) { |
| return; |
| } |
| |
| if (baseline->scope_type() == ScopeType::FUNCTION_SCOPE) { |
| Variable* function = baseline->AsDeclarationScope()->function_var(); |
| if (function != nullptr) { |
| CompareVariables(function, scope->AsDeclarationScope()->function_var(), |
| precise_maybe_assigned); |
| } else { |
| CHECK_NULL(scope->AsDeclarationScope()->function_var()); |
| } |
| } |
| |
| for (auto baseline_local = baseline->locals()->begin(), |
| scope_local = scope->locals()->begin(); |
| baseline_local != baseline->locals()->end(); |
| ++baseline_local, ++scope_local) { |
| if (scope_local->mode() == VAR || scope_local->mode() == LET || |
| scope_local->mode() == CONST) { |
| CompareVariables(*baseline_local, *scope_local, precise_maybe_assigned); |
| } |
| } |
| |
| for (Scope *baseline_inner = baseline->inner_scope(), |
| *scope_inner = scope->inner_scope(); |
| scope_inner != nullptr; scope_inner = scope_inner->sibling(), |
| baseline_inner = baseline_inner->sibling()) { |
| CompareScopes(baseline_inner, scope_inner, precise_maybe_assigned); |
| } |
| } |
| |
| static void CompareVariables(Variable* baseline_local, Variable* scope_local, |
| bool precise_maybe_assigned) { |
| // Sanity check the variable name. If this fails, the variable order |
| // is not deterministic. |
| CHECK_EQ(scope_local->raw_name()->length(), |
| baseline_local->raw_name()->length()); |
| for (int i = 0; i < scope_local->raw_name()->length(); ++i) { |
| CHECK_EQ(scope_local->raw_name()->raw_data()[i], |
| baseline_local->raw_name()->raw_data()[i]); |
| } |
| |
| CHECK_EQ(scope_local->location(), baseline_local->location()); |
| if (precise_maybe_assigned) { |
| CHECK_EQ(scope_local->maybe_assigned(), baseline_local->maybe_assigned()); |
| } else { |
| STATIC_ASSERT(kMaybeAssigned > kNotAssigned); |
| CHECK_GE(scope_local->maybe_assigned(), baseline_local->maybe_assigned()); |
| } |
| } |
| |
| // Finds a scope given a start point and directions to it (which inner scope |
| // to pick). |
| static Scope* FindScope(Scope* scope, const std::vector<unsigned>& location) { |
| for (auto n : location) { |
| scope = scope->inner_scope(); |
| CHECK_NOT_NULL(scope); |
| while (n-- > 0) { |
| scope = scope->sibling(); |
| CHECK_NOT_NULL(scope); |
| } |
| } |
| return scope; |
| } |
| |
| static void MarkInnerFunctionsAsSkipped(Scope* scope) { |
| for (Scope* inner = scope->inner_scope(); inner != nullptr; |
| inner = inner->sibling()) { |
| if (inner->scope_type() == ScopeType::FUNCTION_SCOPE && |
| !inner->AsDeclarationScope()->is_arrow_scope()) { |
| inner->AsDeclarationScope()->set_is_skipped_function(true); |
| } |
| MarkInnerFunctionsAsSkipped(inner); |
| } |
| } |
| }; |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_CCTEST_SCOPE_TEST_HELPER_H_ |