From db558f34954d52a0453a5e3c7173feaaf8dde124 Mon Sep 17 00:00:00 2001 From: Marco Roth Date: Fri, 7 Aug 2026 12:42:53 +0200 Subject: [PATCH] Parser: Don't transform locals that shadow ActionView helpers --- .../test/rules/html-no-unknown-tag.test.ts | 25 ++++ src/analyze/action_view/tag_helpers.c | 141 +++++++++--------- src/analyze/analyze.c | 72 ++++++++- src/include/analyze/analyze.h | 10 +- .../action_view/tag_helper/tag_test.rb | 104 +++++++++++++ ...856d2-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 50 +++++++ ...f89c8-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 28 ++++ ...e882f-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 28 ++++ ...59b86-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 50 +++++++ ...da603-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 47 ++++++ ...7fac2-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 37 +++++ ...9f6b5-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 42 ++++++ ...f6282-4c63ec08b6ab0e9cb1d6ac3f296576f6.txt | 52 +++++++ ...aea5d-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 62 ++++++++ ...c8692-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 62 ++++++++ ...e5c8e-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 60 ++++++++ ...8cd59-ef4af315cb33925c38d24ea3c2e8a1cd.txt | 77 ++++++++++ 17 files changed, 871 insertions(+), 76 deletions(-) create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0090_tag_shadowed_by_local_variable_assignment_is_not_treated_as_tag_helper_3002414cbbbee566b64e16fa573856d2-ef4af315cb33925c38d24ea3c2e8a1cd.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0091_tag_shadowed_by_multiple_assignment_is_not_treated_as_tag_helper_8f98b0bc3c23693e5a742622bc5f89c8-ef4af315cb33925c38d24ea3c2e8a1cd.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0092_tag_shadowed_by_or-assignment_is_not_treated_as_tag_helper_3d1f98b12ea5f8f5b7ee2f0a716e882f-ef4af315cb33925c38d24ea3c2e8a1cd.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0093_tag_shadowed_by_local_variable_assignment_inside_an_if_statement_is_not_treated_as_tag_helper_6dda2a09159cfdd43944aa70a2559b86-ef4af315cb33925c38d24ea3c2e8a1cd.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0094_real_tag_helper_is_still_transformed_before_the_local_variable_assignment_e37a17bb86a915b47cf78ec20e6da603-ef4af315cb33925c38d24ea3c2e8a1cd.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0095_tag_shadowed_by_a_for_loop_variable_is_not_treated_as_tag_helper_279f26fe3a8ac4cc08f89e40f017fac2-ef4af315cb33925c38d24ea3c2e8a1cd.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0096_tag_shadowed_by_a_local_variable_assigned_in_a_block_opening_is_not_treated_as_tag_helper_2f6fbc8168699f810c5858be4739f6b5-ef4af315cb33925c38d24ea3c2e8a1cd.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0097_tag_shadowed_by_block_argument_is_not_treated_as_tag_helper_with_iteration_nodes_c7f0d997281ad7650587e6260b8f6282-4c63ec08b6ab0e9cb1d6ac3f296576f6.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0098_tag_shadowed_by_a_rescue_reference_is_not_treated_as_tag_helper_c29cf7876303aa20dc206b4a579aea5d-ef4af315cb33925c38d24ea3c2e8a1cd.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0099_tag_shadowed_by_a_rescue_reference_with_an_exception_class_is_not_treated_as_tag_helper_2dd895016b10bcff0c9264c5f8cc8692-ef4af315cb33925c38d24ea3c2e8a1cd.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0100_real_tag_helper_is_still_transformed_outside_the_rescue_branch_8c92964ce90030b9e384d89cfc1e5c8e-ef4af315cb33925c38d24ea3c2e8a1cd.txt create mode 100644 test/snapshots/analyze/action_view/tag_helper/tag_test/test_0101_local_variable_assigned_inside_a_block_doesn't_shadow_the_tag_helper_outside_of_it_b8b55ad908011b311a1dcbc684e8cd59-ef4af315cb33925c38d24ea3c2e8a1cd.txt diff --git a/javascript/packages/linter/test/rules/html-no-unknown-tag.test.ts b/javascript/packages/linter/test/rules/html-no-unknown-tag.test.ts index f0a73f29a..a610bc5b3 100644 --- a/javascript/packages/linter/test/rules/html-no-unknown-tag.test.ts +++ b/javascript/packages/linter/test/rules/html-no-unknown-tag.test.ts @@ -500,5 +500,30 @@ describe("html-no-unknown-tag", () => { test("tag.send for custom element passes", () => { expectNoOffenses(`<%= tag.send("turbo-frame", id: "frame") do %>content<% end %>`) }) + + test("tag shadowed by a block argument passes", () => { + expectNoOffenses(` + <% @tags.each do |tag| %> + <%= tag.name %> + <% end %> + `) + }) + + test("tag shadowed by a local variable assignment passes", () => { + expectNoOffenses(` + <% tag = Tag.new(name: "Name") %> + +
  • <%= tag.name %>
  • + `) + }) + + test("tag.hello is still flagged after an unrelated local variable assignment", () => { + expectWarning('Unknown HTML tag ``. This is not a standard HTML element.') + + assertOffenses(` + <% label = "Name" %> + <%= tag.hello do %><%= label %><% end %> + `) + }) }) }) diff --git a/src/analyze/action_view/tag_helpers.c b/src/analyze/action_view/tag_helpers.c index 507ab24fd..248661a2c 100644 --- a/src/analyze/action_view/tag_helpers.c +++ b/src/analyze/action_view/tag_helpers.c @@ -48,29 +48,86 @@ typedef struct { size_t erb_content_offset; } tag_helper_parse_context_T; -static bool build_scope_options_from_context(analyze_ruby_context_T* context, pm_options_t* options) { - size_t locals_count = context && context->tag_helper_locals ? hb_array_size(context->tag_helper_locals) : 0; +typedef struct { + tag_helper_scope_T* scope; + hb_array_T* constants; + size_t from; + size_t to; +} local_read_search_T; - if (locals_count == 0) { return false; } - if (!pm_options_scopes_init(options, 1)) { return false; } +static void append_local_read_constant(local_read_search_T* search, pm_constant_id_t constant_id) { + pm_constant_t* constant = pm_constant_pool_id_to_constant(&search->scope->parser.constant_pool, constant_id); - pm_options_scope_t* scope = &options->scopes[0]; + if (!constant || constant->length == 0) { return; } - if (!pm_options_scope_init(scope, locals_count)) { - pm_options_free(options); + for (size_t index = 0; index < hb_array_size(search->constants); index++) { + pm_constant_t* existing = hb_array_get(search->constants, index); - return false; + if (existing && existing->length == constant->length + && memcmp(existing->start, constant->start, constant->length) == 0) { + return; + } } - for (size_t index = 0; index < locals_count; index++) { - const char* local_name = hb_array_get(context->tag_helper_locals, index); + hb_array_append(search->constants, constant); +} + +static bool search_local_variable_reads(const pm_node_t* node, void* data) { + local_read_search_T* search = (local_read_search_T*) data; + const uint8_t* base = (const uint8_t*) search->scope->buffer.value; + + size_t start = (size_t) (node->location.start - base); + size_t end = (size_t) (node->location.end - base); + + if (end <= search->from || start >= search->to) { return false; } - pm_string_constant_init(&scope->locals[index], local_name, strlen(local_name)); + if (PM_NODE_TYPE(node) == PM_LOCAL_VARIABLE_READ_NODE && start >= search->from && end <= search->to) { + append_local_read_constant(search, ((pm_local_variable_read_node_t*) node)->name); } return true; } +static bool build_scope_options_from_context( + analyze_ruby_context_T* context, + pm_options_t* options, + size_t from, + size_t to +) { + if (!context || !context->tag_helper_scope || !context->tag_helper_scope->root) { return false; } + if (to <= from) { return false; } + + local_read_search_T search = { .scope = context->tag_helper_scope, + .constants = hb_array_init(4, context->allocator), + .from = from, + .to = to }; + + pm_visit_node(context->tag_helper_scope->root, search_local_variable_reads, &search); + + size_t locals_count = hb_array_size(search.constants); + bool built = false; + + if (locals_count > 0 && pm_options_scopes_init(options, 1)) { + pm_options_scope_t* scope = &options->scopes[0]; + + if (pm_options_scope_init(scope, locals_count)) { + for (size_t index = 0; index < locals_count; index++) { + pm_constant_t* constant = hb_array_get(search.constants, index); + + pm_string_constant_init(&scope->locals[index], (const char*) constant->start, constant->length); + } + + built = true; + } else { + pm_options_free(options); + } + } + + hb_array_free(&search.constants); + + return built; +} + static tag_helper_parse_context_T* parse_tag_helper_content( const char* content_string, const char* original_source, @@ -88,13 +145,16 @@ static tag_helper_parse_context_T* parse_tag_helper_content( parse_context->original_source = original_source; parse_context->erb_content_offset = erb_content_offset; + size_t content_length = strlen(parse_context->content_string); + pm_options_t options = { 0 }; - bool has_scope_options = build_scope_options_from_context(context, &options); + bool has_scope_options = + build_scope_options_from_context(context, &options, erb_content_offset, erb_content_offset + content_length); pm_parser_init( &parse_context->parser, parse_context->prism_source, - strlen(parse_context->content_string), + content_length, has_scope_options ? &options : NULL ); parse_context->root = pm_parse(&parse_context->parser); @@ -1774,67 +1834,12 @@ void transform_tag_helper_blocks(const AST_NODE_T* node, analyze_ruby_context_T* } } -static size_t push_tag_helper_local_scope(const AST_NODE_T* node, analyze_ruby_context_T* context) { - if (!node || !context || !context->tag_helper_locals) { return 0; } - - hb_array_T* block_arguments = NULL; - - if (node->type == AST_ERB_BLOCK_NODE) { - block_arguments = ((AST_ERB_BLOCK_NODE_T*) node)->block_arguments; - } else if (node->type == AST_ERB_RENDER_NODE) { - block_arguments = ((AST_ERB_RENDER_NODE_T*) node)->block_arguments; - } - - if (!block_arguments) { return 0; } - - size_t pushed = 0; - - for (size_t index = 0; index < hb_array_size(block_arguments); index++) { - AST_NODE_T* argument = hb_array_get(block_arguments, index); - - if (!argument || argument->type != AST_RUBY_PARAMETER_NODE) { continue; } - - AST_RUBY_PARAMETER_NODE_T* parameter = (AST_RUBY_PARAMETER_NODE_T*) argument; - - if (!parameter->name || hb_string_is_empty(parameter->name->value)) { continue; } - - char* name = hb_allocator_strndup(context->allocator, parameter->name->value.data, parameter->name->value.length); - - if (name && hb_array_append(context->tag_helper_locals, name)) { - pushed++; - } else if (name) { - hb_allocator_dealloc(context->allocator, name); - } - } - - return pushed; -} - -static void pop_tag_helper_local_scope(analyze_ruby_context_T* context, size_t count) { - if (!context || !context->tag_helper_locals) { return; } - - for (size_t index = 0; index < count; index++) { - size_t size = hb_array_size(context->tag_helper_locals); - - if (size == 0) { break; } - - char* name = hb_array_get(context->tag_helper_locals, size - 1); - hb_array_remove(context->tag_helper_locals, size - 1); - - if (name) { hb_allocator_dealloc(context->allocator, name); } - } -} - bool transform_tag_helper_nodes(const AST_NODE_T* node, void* data) { analyze_ruby_context_T* context = (analyze_ruby_context_T*) data; - size_t pushed_locals = push_tag_helper_local_scope(node, context); - transform_tag_helper_blocks(node, context); herb_visit_child_nodes(node, transform_tag_helper_nodes, data); - pop_tag_helper_local_scope(context, pushed_locals); - return false; } diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 043ec0375..8ffbced00 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -16,8 +16,10 @@ #include "../include/ast/ast_node.h" #include "../include/ast/ast_nodes.h" #include "../include/errors.h" +#include "../include/extract.h" #include "../include/lexer/token_struct.h" #include "../include/lib/hb_array.h" +#include "../include/lib/hb_buffer.h" #include "../include/lib/hb_string.h" #include "../include/lib/string.h" #include "../include/location/location.h" @@ -1016,6 +1018,63 @@ hb_array_T* rewrite_node_array(AST_NODE_T* node, hb_array_T* array, analyze_ruby return new_array; } +static tag_helper_scope_T* tag_helper_scope_init(const char* source, hb_allocator_T* allocator) { + if (!source) { return NULL; } + + tag_helper_scope_T* scope = hb_allocator_alloc(allocator, sizeof(tag_helper_scope_T)); + + if (!scope) { return NULL; } + + memset(scope, 0, sizeof(tag_helper_scope_T)); + + if (!hb_buffer_init(&scope->buffer, strlen(source), allocator)) { + hb_allocator_dealloc(allocator, scope); + + return NULL; + } + + herb_extract_ruby_options_T extract_options = { + .semicolons = true, + .comments = false, + .preserve_positions = true, + }; + + herb_extract_ruby_to_buffer_with_options(source, &scope->buffer, &extract_options, allocator); + + if (!scope->buffer.value || scope->buffer.length == 0) { + hb_buffer_free(&scope->buffer); + hb_allocator_dealloc(allocator, scope); + + return NULL; + } + + pm_options_partial_script_set(&scope->options, true); + pm_parser_init(&scope->parser, (const uint8_t*) scope->buffer.value, scope->buffer.length, &scope->options); + + scope->root = pm_parse(&scope->parser); + + if (!scope->root) { + pm_parser_free(&scope->parser); + pm_options_free(&scope->options); + hb_buffer_free(&scope->buffer); + hb_allocator_dealloc(allocator, scope); + + return NULL; + } + + return scope; +} + +static void tag_helper_scope_free(tag_helper_scope_T* scope, hb_allocator_T* allocator) { + if (!scope) { return; } + + pm_node_destroy(&scope->parser, scope->root); + pm_parser_free(&scope->parser); + pm_options_free(&scope->options); + hb_buffer_free(&scope->buffer); + hb_allocator_dealloc(allocator, scope); +} + void herb_analyze_parse_tree( AST_DOCUMENT_NODE_T* document, const char* source, @@ -1029,7 +1088,7 @@ void herb_analyze_parse_tree( .document = document, .parent = NULL, .ruby_context_stack = hb_array_init(8, allocator), - .tag_helper_locals = hb_array_init(8, allocator), + .tag_helper_scope = NULL, .allocator = allocator, .source = source, }; @@ -1051,7 +1110,12 @@ void herb_analyze_parse_tree( } if (options && options->action_view_helpers) { + context.tag_helper_scope = tag_helper_scope_init(source, allocator); + herb_visit_node((AST_NODE_T*) document, transform_tag_helper_nodes, &context); + + tag_helper_scope_free(context.tag_helper_scope, allocator); + context.tag_helper_scope = NULL; } herb_transform_conditional_elements(document, allocator); @@ -1069,11 +1133,5 @@ void herb_analyze_parse_tree( herb_parser_match_html_tags_post_analyze(document, options, allocator); - for (size_t index = hb_array_size(context.tag_helper_locals); index > 0; index--) { - char* local_name = hb_array_get(context.tag_helper_locals, index - 1); - if (local_name) { hb_allocator_dealloc(allocator, local_name); } - } - - hb_array_free(&context.tag_helper_locals); hb_array_free(&context.ruby_context_stack); } diff --git a/src/include/analyze/analyze.h b/src/include/analyze/analyze.h index b0a0b2dfa..d0c242f28 100644 --- a/src/include/analyze/analyze.h +++ b/src/include/analyze/analyze.h @@ -4,14 +4,22 @@ #include "../ast/ast_nodes.h" #include "../lib/hb_allocator.h" #include "../lib/hb_array.h" +#include "../lib/hb_buffer.h" #include "../parser/parser.h" #include "analyzed_ruby.h" +typedef struct TAG_HELPER_SCOPE_STRUCT { + hb_buffer_T buffer; + pm_options_t options; + pm_parser_t parser; + pm_node_t* root; +} tag_helper_scope_T; + typedef struct ANALYZE_RUBY_CONTEXT_STRUCT { AST_DOCUMENT_NODE_T* document; AST_NODE_T* parent; hb_array_T* ruby_context_stack; - hb_array_T* tag_helper_locals; + tag_helper_scope_T* tag_helper_scope; hb_allocator_T* allocator; const char* source; bool found_strict_locals; diff --git a/test/analyze/action_view/tag_helper/tag_test.rb b/test/analyze/action_view/tag_helper/tag_test.rb index e98c250bd..fd784bf34 100644 --- a/test/analyze/action_view/tag_helper/tag_test.rb +++ b/test/analyze/action_view/tag_helper/tag_test.rb @@ -644,5 +644,109 @@ class TagTest < Minitest::Spec <%= tag.hr %> HTML end + + test "tag shadowed by local variable assignment is not treated as tag helper" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <% tag = Tag.new(name: "Name") %> + +
  • <%= tag.name %>
  • + HTML + end + + test "tag shadowed by multiple assignment is not treated as tag helper" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <% label, tag = @pair %> + <%= tag.name %> + HTML + end + + test "tag shadowed by or-assignment is not treated as tag helper" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <% tag ||= Tag.new %> + <%= tag.name %> + HTML + end + + test "tag shadowed by local variable assignment inside an if statement is not treated as tag helper" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <% if @condition %> + <% tag = Tag.new %> + <%= tag.name %> + <% end %> + HTML + end + + test "real tag helper is still transformed before the local variable assignment" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <%= tag.hr %> + <% tag = Tag.new %> + <%= tag.name %> + HTML + end + + test "tag shadowed by a for loop variable is not treated as tag helper" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <% for tag in @tags %> + <%= tag.name %> + <% end %> + HTML + end + + test "tag shadowed by a local variable assigned in a block opening is not treated as tag helper" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <% tag = capture do %> + content + <% end %> + <%= tag.name %> + HTML + end + + test "tag shadowed by block argument is not treated as tag helper with iteration nodes" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true, iteration_nodes: true) + <% @tags.each do |tag| %> + <%= tag.name %> + <% end %> + HTML + end + + test "tag shadowed by a rescue reference is not treated as tag helper" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <% begin %> + <%= render "thing" %> + <% rescue => tag %> + <%= tag.name %> + <% end %> + HTML + end + + test "tag shadowed by a rescue reference with an exception class is not treated as tag helper" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <% begin %> + <%= render "thing" %> + <% rescue StandardError => tag %> + <%= tag.name %> + <% end %> + HTML + end + + test "real tag helper is still transformed outside the rescue branch" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <% begin %> + <%= tag.hr %> + <% rescue => tag %> + rescued + <% end %> + HTML + end + + test "local variable assigned inside a block doesn't shadow the tag helper outside of it" do + assert_parsed_snapshot(<<~HTML, action_view_helpers: true) + <% @groups.each do |group| %> + <% tag = group.tag %> + <%= tag.name %> + <% end %> + <%= tag.hr %> + HTML + end end end diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0090_tag_shadowed_by_local_variable_assignment_is_not_treated_as_tag_helper_3002414cbbbee566b64e16fa573856d2-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0090_tag_shadowed_by_local_variable_assignment_is_not_treated_as_tag_helper_3002414cbbbee566b64e16fa573856d2-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..7922e83f7 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0090_tag_shadowed_by_local_variable_assignment_is_not_treated_as_tag_helper_3002414cbbbee566b64e16fa573856d2-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,50 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0090_tag shadowed by local variable assignment is not treated as tag helper" +input: |2- +<% tag = Tag.new(name: "Name") %> + +
  • <%= tag.name %>
  • +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(4:0)) +└── children: (4 items) + ├── @ ERBContentNode (location: (1:0)-(1:33)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " tag = Tag.new(name: "Name") " (location: (1:2)-(1:31)) + │ ├── tag_closing: "%>" (location: (1:31)-(1:33)) + │ ├── parsed: true + │ └── valid: true + │ + ├── @ HTMLTextNode (location: (1:33)-(3:0)) + │ └── content: "\n\n" + │ + ├── @ HTMLElementNode (location: (3:0)-(3:24)) + │ ├── open_tag: + │ │ └── @ HTMLOpenTagNode (location: (3:0)-(3:4)) + │ │ ├── tag_opening: "<" (location: (3:0)-(3:1)) + │ │ ├── tag_name: "li" (location: (3:1)-(3:3)) + │ │ ├── tag_closing: ">" (location: (3:3)-(3:4)) + │ │ ├── children: [] + │ │ └── is_void: false + │ │ + │ ├── tag_name: "li" (location: (3:1)-(3:3)) + │ ├── body: (1 item) + │ │ └── @ ERBContentNode (location: (3:4)-(3:19)) + │ │ ├── tag_opening: "<%=" (location: (3:4)-(3:7)) + │ │ ├── content: " tag.name " (location: (3:7)-(3:17)) + │ │ ├── tag_closing: "%>" (location: (3:17)-(3:19)) + │ │ ├── parsed: true + │ │ └── valid: true + │ │ + │ ├── close_tag: + │ │ └── @ HTMLCloseTagNode (location: (3:19)-(3:24)) + │ │ ├── tag_opening: "" (location: (3:23)-(3:24)) + │ │ + │ ├── is_void: false + │ └── element_source: "HTML" + │ + └── @ HTMLTextNode (location: (3:24)-(4:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0091_tag_shadowed_by_multiple_assignment_is_not_treated_as_tag_helper_8f98b0bc3c23693e5a742622bc5f89c8-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0091_tag_shadowed_by_multiple_assignment_is_not_treated_as_tag_helper_8f98b0bc3c23693e5a742622bc5f89c8-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..f62badc39 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0091_tag_shadowed_by_multiple_assignment_is_not_treated_as_tag_helper_8f98b0bc3c23693e5a742622bc5f89c8-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,28 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0091_tag shadowed by multiple assignment is not treated as tag helper" +input: |2- +<% label, tag = @pair %> +<%= tag.name %> +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(3:0)) +└── children: (4 items) + ├── @ ERBContentNode (location: (1:0)-(1:24)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " label, tag = @pair " (location: (1:2)-(1:22)) + │ ├── tag_closing: "%>" (location: (1:22)-(1:24)) + │ ├── parsed: true + │ └── valid: true + │ + ├── @ HTMLTextNode (location: (1:24)-(2:0)) + │ └── content: "\n" + │ + ├── @ ERBContentNode (location: (2:0)-(2:15)) + │ ├── tag_opening: "<%=" (location: (2:0)-(2:3)) + │ ├── content: " tag.name " (location: (2:3)-(2:13)) + │ ├── tag_closing: "%>" (location: (2:13)-(2:15)) + │ ├── parsed: true + │ └── valid: true + │ + └── @ HTMLTextNode (location: (2:15)-(3:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0092_tag_shadowed_by_or-assignment_is_not_treated_as_tag_helper_3d1f98b12ea5f8f5b7ee2f0a716e882f-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0092_tag_shadowed_by_or-assignment_is_not_treated_as_tag_helper_3d1f98b12ea5f8f5b7ee2f0a716e882f-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..edca0e733 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0092_tag_shadowed_by_or-assignment_is_not_treated_as_tag_helper_3d1f98b12ea5f8f5b7ee2f0a716e882f-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,28 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0092_tag shadowed by or-assignment is not treated as tag helper" +input: |2- +<% tag ||= Tag.new %> +<%= tag.name %> +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(3:0)) +└── children: (4 items) + ├── @ ERBContentNode (location: (1:0)-(1:21)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " tag ||= Tag.new " (location: (1:2)-(1:19)) + │ ├── tag_closing: "%>" (location: (1:19)-(1:21)) + │ ├── parsed: true + │ └── valid: true + │ + ├── @ HTMLTextNode (location: (1:21)-(2:0)) + │ └── content: "\n" + │ + ├── @ ERBContentNode (location: (2:0)-(2:15)) + │ ├── tag_opening: "<%=" (location: (2:0)-(2:3)) + │ ├── content: " tag.name " (location: (2:3)-(2:13)) + │ ├── tag_closing: "%>" (location: (2:13)-(2:15)) + │ ├── parsed: true + │ └── valid: true + │ + └── @ HTMLTextNode (location: (2:15)-(3:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0093_tag_shadowed_by_local_variable_assignment_inside_an_if_statement_is_not_treated_as_tag_helper_6dda2a09159cfdd43944aa70a2559b86-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0093_tag_shadowed_by_local_variable_assignment_inside_an_if_statement_is_not_treated_as_tag_helper_6dda2a09159cfdd43944aa70a2559b86-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..2d11b957c --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0093_tag_shadowed_by_local_variable_assignment_inside_an_if_statement_is_not_treated_as_tag_helper_6dda2a09159cfdd43944aa70a2559b86-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,50 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0093_tag shadowed by local variable assignment inside an if statement is not treated as tag helper" +input: |2- +<% if @condition %> + <% tag = Tag.new %> + <%= tag.name %> +<% end %> +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(5:0)) +└── children: (2 items) + ├── @ ERBIfNode (location: (1:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " if @condition " (location: (1:2)-(1:17)) + │ ├── tag_closing: "%>" (location: (1:17)-(1:19)) + │ ├── then_keyword: ∅ + │ ├── statements: (5 items) + │ │ ├── @ HTMLTextNode (location: (1:19)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:21)) + │ │ │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ │ │ ├── content: " tag = Tag.new " (location: (2:4)-(2:19)) + │ │ │ ├── tag_closing: "%>" (location: (2:19)-(2:21)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ ├── @ HTMLTextNode (location: (2:21)-(3:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (3:2)-(3:17)) + │ │ │ ├── tag_opening: "<%=" (location: (3:2)-(3:5)) + │ │ │ ├── content: " tag.name " (location: (3:5)-(3:15)) + │ │ │ ├── tag_closing: "%>" (location: (3:15)-(3:17)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ └── @ HTMLTextNode (location: (3:17)-(4:0)) + │ │ └── content: "\n" + │ │ + │ ├── subsequent: ∅ + │ └── end_node: + │ └── @ ERBEndNode (location: (4:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (4:0)-(4:2)) + │ ├── content: " end " (location: (4:2)-(4:7)) + │ └── tag_closing: "%>" (location: (4:7)-(4:9)) + │ + │ + └── @ HTMLTextNode (location: (4:9)-(5:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0094_real_tag_helper_is_still_transformed_before_the_local_variable_assignment_e37a17bb86a915b47cf78ec20e6da603-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0094_real_tag_helper_is_still_transformed_before_the_local_variable_assignment_e37a17bb86a915b47cf78ec20e6da603-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..7fbd18825 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0094_real_tag_helper_is_still_transformed_before_the_local_variable_assignment_e37a17bb86a915b47cf78ec20e6da603-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,47 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0094_real tag helper is still transformed before the local variable assignment" +input: |2- +<%= tag.hr %> +<% tag = Tag.new %> +<%= tag.name %> +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(4:0)) +└── children: (6 items) + ├── @ HTMLElementNode (location: (1:0)-(1:13)) + │ ├── open_tag: + │ │ └── @ ERBOpenTagNode (location: (1:0)-(1:13)) + │ │ ├── tag_opening: "<%=" (location: (1:0)-(1:3)) + │ │ ├── content: " tag.hr " (location: (1:3)-(1:11)) + │ │ ├── tag_closing: "%>" (location: (1:11)-(1:13)) + │ │ ├── tag_name: "hr" (location: (1:8)-(1:10)) + │ │ └── children: [] + │ │ + │ ├── tag_name: "hr" (location: (1:8)-(1:10)) + │ ├── body: [] + │ ├── close_tag: ∅ + │ ├── is_void: true + │ └── element_source: "ActionView::Helpers::TagHelper#tag" + │ + ├── @ HTMLTextNode (location: (1:13)-(2:0)) + │ └── content: "\n" + │ + ├── @ ERBContentNode (location: (2:0)-(2:19)) + │ ├── tag_opening: "<%" (location: (2:0)-(2:2)) + │ ├── content: " tag = Tag.new " (location: (2:2)-(2:17)) + │ ├── tag_closing: "%>" (location: (2:17)-(2:19)) + │ ├── parsed: true + │ └── valid: true + │ + ├── @ HTMLTextNode (location: (2:19)-(3:0)) + │ └── content: "\n" + │ + ├── @ ERBContentNode (location: (3:0)-(3:15)) + │ ├── tag_opening: "<%=" (location: (3:0)-(3:3)) + │ ├── content: " tag.name " (location: (3:3)-(3:13)) + │ ├── tag_closing: "%>" (location: (3:13)-(3:15)) + │ ├── parsed: true + │ └── valid: true + │ + └── @ HTMLTextNode (location: (3:15)-(4:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0095_tag_shadowed_by_a_for_loop_variable_is_not_treated_as_tag_helper_279f26fe3a8ac4cc08f89e40f017fac2-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0095_tag_shadowed_by_a_for_loop_variable_is_not_treated_as_tag_helper_279f26fe3a8ac4cc08f89e40f017fac2-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..5652e9d92 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0095_tag_shadowed_by_a_for_loop_variable_is_not_treated_as_tag_helper_279f26fe3a8ac4cc08f89e40f017fac2-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,37 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0095_tag shadowed by a for loop variable is not treated as tag helper" +input: |2- +<% for tag in @tags %> + <%= tag.name %> +<% end %> +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(4:0)) +└── children: (2 items) + ├── @ ERBForNode (location: (1:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " for tag in @tags " (location: (1:2)-(1:20)) + │ ├── tag_closing: "%>" (location: (1:20)-(1:22)) + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:22)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:17)) + │ │ │ ├── tag_opening: "<%=" (location: (2:2)-(2:5)) + │ │ │ ├── content: " tag.name " (location: (2:5)-(2:15)) + │ │ │ ├── tag_closing: "%>" (location: (2:15)-(2:17)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:17)-(3:0)) + │ │ └── content: "\n" + │ │ + │ └── end_node: + │ └── @ ERBEndNode (location: (3:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ ├── content: " end " (location: (3:2)-(3:7)) + │ └── tag_closing: "%>" (location: (3:7)-(3:9)) + │ + │ + └── @ HTMLTextNode (location: (3:9)-(4:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0096_tag_shadowed_by_a_local_variable_assigned_in_a_block_opening_is_not_treated_as_tag_helper_2f6fbc8168699f810c5858be4739f6b5-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0096_tag_shadowed_by_a_local_variable_assigned_in_a_block_opening_is_not_treated_as_tag_helper_2f6fbc8168699f810c5858be4739f6b5-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..2a91ca541 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0096_tag_shadowed_by_a_local_variable_assigned_in_a_block_opening_is_not_treated_as_tag_helper_2f6fbc8168699f810c5858be4739f6b5-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,42 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0096_tag shadowed by a local variable assigned in a block opening is not treated as tag helper" +input: |2- +<% tag = capture do %> + content +<% end %> +<%= tag.name %> +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(5:0)) +└── children: (4 items) + ├── @ ERBBlockNode (location: (1:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " tag = capture do " (location: (1:2)-(1:20)) + │ ├── tag_closing: "%>" (location: (1:20)-(1:22)) + │ ├── body: (1 item) + │ │ └── @ HTMLTextNode (location: (1:22)-(3:0)) + │ │ └── content: "\n content\n" + │ │ + │ ├── block_arguments: [] + │ ├── rescue_clause: ∅ + │ ├── else_clause: ∅ + │ ├── ensure_clause: ∅ + │ └── end_node: + │ └── @ ERBEndNode (location: (3:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ ├── content: " end " (location: (3:2)-(3:7)) + │ └── tag_closing: "%>" (location: (3:7)-(3:9)) + │ + │ + ├── @ HTMLTextNode (location: (3:9)-(4:0)) + │ └── content: "\n" + │ + ├── @ ERBContentNode (location: (4:0)-(4:15)) + │ ├── tag_opening: "<%=" (location: (4:0)-(4:3)) + │ ├── content: " tag.name " (location: (4:3)-(4:13)) + │ ├── tag_closing: "%>" (location: (4:13)-(4:15)) + │ ├── parsed: true + │ └── valid: true + │ + └── @ HTMLTextNode (location: (4:15)-(5:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0097_tag_shadowed_by_block_argument_is_not_treated_as_tag_helper_with_iteration_nodes_c7f0d997281ad7650587e6260b8f6282-4c63ec08b6ab0e9cb1d6ac3f296576f6.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0097_tag_shadowed_by_block_argument_is_not_treated_as_tag_helper_with_iteration_nodes_c7f0d997281ad7650587e6260b8f6282-4c63ec08b6ab0e9cb1d6ac3f296576f6.txt new file mode 100644 index 000000000..c50501407 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0097_tag_shadowed_by_block_argument_is_not_treated_as_tag_helper_with_iteration_nodes_c7f0d997281ad7650587e6260b8f6282-4c63ec08b6ab0e9cb1d6ac3f296576f6.txt @@ -0,0 +1,52 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0097_tag shadowed by block argument is not treated as tag helper with iteration nodes" +input: |2- +<% @tags.each do |tag| %> + <%= tag.name %> +<% end %> +options: {action_view_helpers: true, iteration_nodes: true} +--- +@ DocumentNode (location: (1:0)-(4:0)) +└── children: (2 items) + ├── @ ERBIterationBlockNode (location: (1:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " @tags.each do |tag| " (location: (1:2)-(1:23)) + │ ├── tag_closing: "%>" (location: (1:23)-(1:25)) + │ ├── receiver: "@tags" (location: (1:3)-(1:8)) + │ ├── call_operator: "." (location: (1:8)-(1:9)) + │ ├── message: "each" (location: (1:9)-(1:13)) + │ ├── arguments: [] + │ ├── block_opening: "do" (location: (1:14)-(1:16)) + │ ├── body: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:25)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:17)) + │ │ │ ├── tag_opening: "<%=" (location: (2:2)-(2:5)) + │ │ │ ├── content: " tag.name " (location: (2:5)-(2:15)) + │ │ │ ├── tag_closing: "%>" (location: (2:15)-(2:17)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:17)-(3:0)) + │ │ └── content: "\n" + │ │ + │ ├── block_arguments: (1 item) + │ │ └── @ RubyParameterNode (location: (1:18)-(1:21)) + │ │ ├── name: "tag" (location: (1:18)-(1:21)) + │ │ ├── default_value: ∅ + │ │ ├── kind: "positional" + │ │ └── required: true + │ │ + │ ├── rescue_clause: ∅ + │ ├── else_clause: ∅ + │ ├── ensure_clause: ∅ + │ └── end_node: + │ └── @ ERBEndNode (location: (3:0)-(3:9)) + │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ ├── content: " end " (location: (3:2)-(3:7)) + │ └── tag_closing: "%>" (location: (3:7)-(3:9)) + │ + │ + └── @ HTMLTextNode (location: (3:9)-(4:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0098_tag_shadowed_by_a_rescue_reference_is_not_treated_as_tag_helper_c29cf7876303aa20dc206b4a579aea5d-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0098_tag_shadowed_by_a_rescue_reference_is_not_treated_as_tag_helper_c29cf7876303aa20dc206b4a579aea5d-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..a6f9a3065 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0098_tag_shadowed_by_a_rescue_reference_is_not_treated_as_tag_helper_c29cf7876303aa20dc206b4a579aea5d-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,62 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0098_tag shadowed by a rescue reference is not treated as tag helper" +input: |2- +<% begin %> + <%= render "thing" %> +<% rescue => tag %> + <%= tag.name %> +<% end %> +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(6:0)) +└── children: (2 items) + ├── @ ERBBeginNode (location: (1:0)-(5:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " begin " (location: (1:2)-(1:9)) + │ ├── tag_closing: "%>" (location: (1:9)-(1:11)) + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:11)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:23)) + │ │ │ ├── tag_opening: "<%=" (location: (2:2)-(2:5)) + │ │ │ ├── content: " render "thing" " (location: (2:5)-(2:21)) + │ │ │ ├── tag_closing: "%>" (location: (2:21)-(2:23)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:23)-(3:0)) + │ │ └── content: "\n" + │ │ + │ ├── rescue_clause: + │ │ └── @ ERBRescueNode (location: (3:0)-(5:0)) + │ │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ │ ├── content: " rescue => tag " (location: (3:2)-(3:17)) + │ │ ├── tag_closing: "%>" (location: (3:17)-(3:19)) + │ │ ├── statements: (3 items) + │ │ │ ├── @ HTMLTextNode (location: (3:19)-(4:2)) + │ │ │ │ └── content: "\n " + │ │ │ │ + │ │ │ ├── @ ERBContentNode (location: (4:2)-(4:17)) + │ │ │ │ ├── tag_opening: "<%=" (location: (4:2)-(4:5)) + │ │ │ │ ├── content: " tag.name " (location: (4:5)-(4:15)) + │ │ │ │ ├── tag_closing: "%>" (location: (4:15)-(4:17)) + │ │ │ │ ├── parsed: true + │ │ │ │ └── valid: true + │ │ │ │ + │ │ │ └── @ HTMLTextNode (location: (4:17)-(5:0)) + │ │ │ └── content: "\n" + │ │ │ + │ │ └── subsequent: ∅ + │ │ + │ ├── else_clause: ∅ + │ ├── ensure_clause: ∅ + │ └── end_node: + │ └── @ ERBEndNode (location: (5:0)-(5:9)) + │ ├── tag_opening: "<%" (location: (5:0)-(5:2)) + │ ├── content: " end " (location: (5:2)-(5:7)) + │ └── tag_closing: "%>" (location: (5:7)-(5:9)) + │ + │ + └── @ HTMLTextNode (location: (5:9)-(6:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0099_tag_shadowed_by_a_rescue_reference_with_an_exception_class_is_not_treated_as_tag_helper_2dd895016b10bcff0c9264c5f8cc8692-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0099_tag_shadowed_by_a_rescue_reference_with_an_exception_class_is_not_treated_as_tag_helper_2dd895016b10bcff0c9264c5f8cc8692-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..f9e219a48 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0099_tag_shadowed_by_a_rescue_reference_with_an_exception_class_is_not_treated_as_tag_helper_2dd895016b10bcff0c9264c5f8cc8692-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,62 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0099_tag shadowed by a rescue reference with an exception class is not treated as tag helper" +input: |2- +<% begin %> + <%= render "thing" %> +<% rescue StandardError => tag %> + <%= tag.name %> +<% end %> +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(6:0)) +└── children: (2 items) + ├── @ ERBBeginNode (location: (1:0)-(5:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " begin " (location: (1:2)-(1:9)) + │ ├── tag_closing: "%>" (location: (1:9)-(1:11)) + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:11)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:23)) + │ │ │ ├── tag_opening: "<%=" (location: (2:2)-(2:5)) + │ │ │ ├── content: " render "thing" " (location: (2:5)-(2:21)) + │ │ │ ├── tag_closing: "%>" (location: (2:21)-(2:23)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:23)-(3:0)) + │ │ └── content: "\n" + │ │ + │ ├── rescue_clause: + │ │ └── @ ERBRescueNode (location: (3:0)-(5:0)) + │ │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ │ ├── content: " rescue StandardError => tag " (location: (3:2)-(3:31)) + │ │ ├── tag_closing: "%>" (location: (3:31)-(3:33)) + │ │ ├── statements: (3 items) + │ │ │ ├── @ HTMLTextNode (location: (3:33)-(4:2)) + │ │ │ │ └── content: "\n " + │ │ │ │ + │ │ │ ├── @ ERBContentNode (location: (4:2)-(4:17)) + │ │ │ │ ├── tag_opening: "<%=" (location: (4:2)-(4:5)) + │ │ │ │ ├── content: " tag.name " (location: (4:5)-(4:15)) + │ │ │ │ ├── tag_closing: "%>" (location: (4:15)-(4:17)) + │ │ │ │ ├── parsed: true + │ │ │ │ └── valid: true + │ │ │ │ + │ │ │ └── @ HTMLTextNode (location: (4:17)-(5:0)) + │ │ │ └── content: "\n" + │ │ │ + │ │ └── subsequent: ∅ + │ │ + │ ├── else_clause: ∅ + │ ├── ensure_clause: ∅ + │ └── end_node: + │ └── @ ERBEndNode (location: (5:0)-(5:9)) + │ ├── tag_opening: "<%" (location: (5:0)-(5:2)) + │ ├── content: " end " (location: (5:2)-(5:7)) + │ └── tag_closing: "%>" (location: (5:7)-(5:9)) + │ + │ + └── @ HTMLTextNode (location: (5:9)-(6:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0100_real_tag_helper_is_still_transformed_outside_the_rescue_branch_8c92964ce90030b9e384d89cfc1e5c8e-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0100_real_tag_helper_is_still_transformed_outside_the_rescue_branch_8c92964ce90030b9e384d89cfc1e5c8e-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..85ec88835 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0100_real_tag_helper_is_still_transformed_outside_the_rescue_branch_8c92964ce90030b9e384d89cfc1e5c8e-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,60 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0100_real tag helper is still transformed outside the rescue branch" +input: |2- +<% begin %> + <%= tag.hr %> +<% rescue => tag %> + rescued +<% end %> +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(6:0)) +└── children: (2 items) + ├── @ ERBBeginNode (location: (1:0)-(5:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " begin " (location: (1:2)-(1:9)) + │ ├── tag_closing: "%>" (location: (1:9)-(1:11)) + │ ├── statements: (3 items) + │ │ ├── @ HTMLTextNode (location: (1:11)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ HTMLElementNode (location: (2:2)-(2:15)) + │ │ │ ├── open_tag: + │ │ │ │ └── @ ERBOpenTagNode (location: (2:2)-(2:15)) + │ │ │ │ ├── tag_opening: "<%=" (location: (2:2)-(2:5)) + │ │ │ │ ├── content: " tag.hr " (location: (2:5)-(2:13)) + │ │ │ │ ├── tag_closing: "%>" (location: (2:13)-(2:15)) + │ │ │ │ ├── tag_name: "hr" (location: (2:10)-(2:12)) + │ │ │ │ └── children: [] + │ │ │ │ + │ │ │ ├── tag_name: "hr" (location: (2:10)-(2:12)) + │ │ │ ├── body: [] + │ │ │ ├── close_tag: ∅ + │ │ │ ├── is_void: true + │ │ │ └── element_source: "ActionView::Helpers::TagHelper#tag" + │ │ │ + │ │ └── @ HTMLTextNode (location: (2:15)-(3:0)) + │ │ └── content: "\n" + │ │ + │ ├── rescue_clause: + │ │ └── @ ERBRescueNode (location: (3:0)-(5:0)) + │ │ ├── tag_opening: "<%" (location: (3:0)-(3:2)) + │ │ ├── content: " rescue => tag " (location: (3:2)-(3:17)) + │ │ ├── tag_closing: "%>" (location: (3:17)-(3:19)) + │ │ ├── statements: (1 item) + │ │ │ └── @ HTMLTextNode (location: (3:19)-(5:0)) + │ │ │ └── content: "\n rescued\n" + │ │ │ + │ │ └── subsequent: ∅ + │ │ + │ ├── else_clause: ∅ + │ ├── ensure_clause: ∅ + │ └── end_node: + │ └── @ ERBEndNode (location: (5:0)-(5:9)) + │ ├── tag_opening: "<%" (location: (5:0)-(5:2)) + │ ├── content: " end " (location: (5:2)-(5:7)) + │ └── tag_closing: "%>" (location: (5:7)-(5:9)) + │ + │ + └── @ HTMLTextNode (location: (5:9)-(6:0)) + └── content: "\n" \ No newline at end of file diff --git a/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0101_local_variable_assigned_inside_a_block_doesn't_shadow_the_tag_helper_outside_of_it_b8b55ad908011b311a1dcbc684e8cd59-ef4af315cb33925c38d24ea3c2e8a1cd.txt b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0101_local_variable_assigned_inside_a_block_doesn't_shadow_the_tag_helper_outside_of_it_b8b55ad908011b311a1dcbc684e8cd59-ef4af315cb33925c38d24ea3c2e8a1cd.txt new file mode 100644 index 000000000..41b5872f2 --- /dev/null +++ b/test/snapshots/analyze/action_view/tag_helper/tag_test/test_0101_local_variable_assigned_inside_a_block_doesn't_shadow_the_tag_helper_outside_of_it_b8b55ad908011b311a1dcbc684e8cd59-ef4af315cb33925c38d24ea3c2e8a1cd.txt @@ -0,0 +1,77 @@ +--- +source: "Analyze::ActionView::TagHelper::TagTest#test_0101_local variable assigned inside a block doesn't shadow the tag helper outside of it" +input: |2- +<% @groups.each do |group| %> + <% tag = group.tag %> + <%= tag.name %> +<% end %> +<%= tag.hr %> +options: {action_view_helpers: true} +--- +@ DocumentNode (location: (1:0)-(6:0)) +└── children: (4 items) + ├── @ ERBBlockNode (location: (1:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " @groups.each do |group| " (location: (1:2)-(1:27)) + │ ├── tag_closing: "%>" (location: (1:27)-(1:29)) + │ ├── body: (5 items) + │ │ ├── @ HTMLTextNode (location: (1:29)-(2:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (2:2)-(2:23)) + │ │ │ ├── tag_opening: "<%" (location: (2:2)-(2:4)) + │ │ │ ├── content: " tag = group.tag " (location: (2:4)-(2:21)) + │ │ │ ├── tag_closing: "%>" (location: (2:21)-(2:23)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ ├── @ HTMLTextNode (location: (2:23)-(3:2)) + │ │ │ └── content: "\n " + │ │ │ + │ │ ├── @ ERBContentNode (location: (3:2)-(3:17)) + │ │ │ ├── tag_opening: "<%=" (location: (3:2)-(3:5)) + │ │ │ ├── content: " tag.name " (location: (3:5)-(3:15)) + │ │ │ ├── tag_closing: "%>" (location: (3:15)-(3:17)) + │ │ │ ├── parsed: true + │ │ │ └── valid: true + │ │ │ + │ │ └── @ HTMLTextNode (location: (3:17)-(4:0)) + │ │ └── content: "\n" + │ │ + │ ├── block_arguments: (1 item) + │ │ └── @ RubyParameterNode (location: (1:20)-(1:25)) + │ │ ├── name: "group" (location: (1:20)-(1:25)) + │ │ ├── default_value: ∅ + │ │ ├── kind: "positional" + │ │ └── required: true + │ │ + │ ├── rescue_clause: ∅ + │ ├── else_clause: ∅ + │ ├── ensure_clause: ∅ + │ └── end_node: + │ └── @ ERBEndNode (location: (4:0)-(4:9)) + │ ├── tag_opening: "<%" (location: (4:0)-(4:2)) + │ ├── content: " end " (location: (4:2)-(4:7)) + │ └── tag_closing: "%>" (location: (4:7)-(4:9)) + │ + │ + ├── @ HTMLTextNode (location: (4:9)-(5:0)) + │ └── content: "\n" + │ + ├── @ HTMLElementNode (location: (5:0)-(5:13)) + │ ├── open_tag: + │ │ └── @ ERBOpenTagNode (location: (5:0)-(5:13)) + │ │ ├── tag_opening: "<%=" (location: (5:0)-(5:3)) + │ │ ├── content: " tag.hr " (location: (5:3)-(5:11)) + │ │ ├── tag_closing: "%>" (location: (5:11)-(5:13)) + │ │ ├── tag_name: "hr" (location: (5:8)-(5:10)) + │ │ └── children: [] + │ │ + │ ├── tag_name: "hr" (location: (5:8)-(5:10)) + │ ├── body: [] + │ ├── close_tag: ∅ + │ ├── is_void: true + │ └── element_source: "ActionView::Helpers::TagHelper#tag" + │ + └── @ HTMLTextNode (location: (5:13)-(6:0)) + └── content: "\n" \ No newline at end of file