From 26300fa23c32084f4dc6813fd5081187c4fc3c41 Mon Sep 17 00:00:00 2001 From: ydah Date: Thu, 25 Dec 2025 23:03:29 +0900 Subject: [PATCH] Fix block detection to exclude closed brace blocks without yield Fixes: https://github.com/marcoroth/herb/issues/995 --- src/analyze.c | 16 +++++++++++++--- test/analyze/block_test.rb | 6 ++++++ ...th_yield_5f025404565a9875df5ffa171e8fb7b4.txt | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 test/snapshots/analyze/block_test/test_0023_closed_brace_block_with_yield_5f025404565a9875df5ffa171e8fb7b4.txt diff --git a/src/analyze.c b/src/analyze.c index f84b29be1..656c84bc4 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -192,9 +192,19 @@ static bool find_earliest_control_keyword_walker(const pm_node_t* node, void* da case PM_CALL_NODE: { pm_call_node_t* call = (pm_call_node_t*) node; - if (call->block != NULL) { - current_type = CONTROL_TYPE_BLOCK; - keyword_offset = (uint32_t) (node->location.start - context->source_start); + if (call->block != NULL && call->block->type == PM_BLOCK_NODE) { + pm_block_node_t* block_node = (pm_block_node_t*) call->block; + size_t opening_length = block_node->opening_loc.end - block_node->opening_loc.start; + bool has_do_opening = + opening_length == 2 && block_node->opening_loc.start[0] == 'd' && block_node->opening_loc.start[1] == 'o'; + bool has_brace_opening = opening_length == 1 && block_node->opening_loc.start[0] == '{'; + bool has_closing_location = block_node->closing_loc.start != NULL && block_node->closing_loc.end != NULL + && (block_node->closing_loc.end - block_node->closing_loc.start) > 0; + + if (has_do_opening || (has_brace_opening && !has_closing_location)) { + current_type = CONTROL_TYPE_BLOCK; + keyword_offset = (uint32_t) (node->location.start - context->source_start); + } } break; } diff --git a/test/analyze/block_test.rb b/test/analyze/block_test.rb index 05cde2cdd..282c82cc1 100644 --- a/test/analyze/block_test.rb +++ b/test/analyze/block_test.rb @@ -194,5 +194,11 @@ class BlockTest < Minitest::Spec <% end %> HTML end + + test "closed brace block with yield" do + assert_parsed_snapshot(<<~HTML) + <% content = capture { yield } if block_given? %> + HTML + end end end diff --git a/test/snapshots/analyze/block_test/test_0023_closed_brace_block_with_yield_5f025404565a9875df5ffa171e8fb7b4.txt b/test/snapshots/analyze/block_test/test_0023_closed_brace_block_with_yield_5f025404565a9875df5ffa171e8fb7b4.txt new file mode 100644 index 000000000..b421e58b8 --- /dev/null +++ b/test/snapshots/analyze/block_test/test_0023_closed_brace_block_with_yield_5f025404565a9875df5ffa171e8fb7b4.txt @@ -0,0 +1,14 @@ +--- +source: "Analyze::BlockTest#test_0023_closed brace block with yield" +input: |2- +<% content = capture { yield } if block_given? %> +--- +@ DocumentNode (location: (1:0)-(2:0)) +└── children: (2 items) + ├── @ ERBYieldNode (location: (1:0)-(1:49)) + │ ├── tag_opening: "<%" (location: (1:0)-(1:2)) + │ ├── content: " content = capture { yield } if block_given? " (location: (1:2)-(1:47)) + │ └── tag_closing: "%>" (location: (1:47)-(1:49)) + │ + └── @ HTMLTextNode (location: (1:49)-(2:0)) + └── content: "\n" \ No newline at end of file