Skip to content

Commit

Permalink
Fix an error for Style/IfWithSemicolon
Browse files Browse the repository at this point in the history
This PR fixes the following error for `Style/IfWithSemicolon`
when when using nested single-line if/;/end in block of if/else branches.

```console
$ cat /tmpp/example.rb
if foo?;bar;else baz do if qux;else quux;end;end;end

$ bundle exec rubocop --only Style/IfWithSemicolon /tmp/example.rb -a -d
(snip)

An error occurred while Style/IfWithSemicolon cop was inspecting /tmp/example.rb:1:24.
Parser::Source::TreeRewriter detected clobbering
/Users/koic/.rbenv/versions/3.4-dev/lib/ruby/gems/3.4.0+0/gems/parser-3.3.4.2/lib/parser/source/tree_rewriter.rb:427
:in 'Parser::Source::TreeRewriter#trigger_policy'
```
  • Loading branch information
koic authored and bbatsov committed Sep 4, 2024
1 parent c2ae362 commit 08bed81
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 2 deletions.
1 change: 1 addition & 0 deletions changelog/fix_an_error_for_style_if_with_semicolon.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#13191](https://github.com/rubocop/rubocop/pull/13191): Fix an error for `Style/IfWithSemicolon` when using nested single-line if/;/end in block of if/else branches. ([@koic][])
11 changes: 9 additions & 2 deletions lib/rubocop/cop/style/if_with_semicolon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,26 +36,33 @@ def on_normal_if_unless(node)

private

# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def message(node)
template = if node.if_branch&.begin_type?
MSG_NEWLINE
elsif node.else_branch&.if_type? || node.else_branch&.begin_type?
elsif node.else_branch&.if_type? || node.else_branch&.begin_type? ||
use_block_in_branches?(node)
MSG_IF_ELSE
else
MSG_TERNARY
end

format(template, expr: node.condition.source)
end
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

def autocorrect(corrector, node)
if node.if_branch&.begin_type? || node.else_branch&.begin_type?
if node.branches.compact.any?(&:begin_type?) || use_block_in_branches?(node)
corrector.replace(node.loc.begin, "\n")
else
corrector.replace(node, replacement(node))
end
end

def use_block_in_branches?(node)
node.branches.compact.any? { |branch| branch.block_type? || branch.numblock_type? }
end

def replacement(node)
return correct_elsif(node) if node.else_branch&.if_type?

Expand Down
52 changes: 52 additions & 0 deletions spec/rubocop/cop/style/if_with_semicolon_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -203,5 +203,57 @@ class Hash
end
RUBY
end

it 'registers an offense and corrects when using nested single-line if/;/end in block of if body' do
expect_offense(<<~RUBY)
if foo?; bar { if qux?; quux else end } end
^^^^^^^^^^^^^^^^^^^^^^ Do not use `if qux?;` - use a ternary operator instead.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use `if foo?;` - use `if/else` instead.
RUBY

expect_correction(<<~RUBY)
if foo?
bar { qux? ? quux : nil } end
RUBY
end

it 'registers an offense and corrects when using nested single-line if/;/end in the block of else body' do
expect_offense(<<~RUBY)
if foo?; bar else baz { if qux?; quux else end } end
^^^^^^^^^^^^^^^^^^^^^^ Do not use `if qux?;` - use a ternary operator instead.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use `if foo?;` - use `if/else` instead.
RUBY

expect_correction(<<~RUBY)
if foo?
bar else baz { qux? ? quux : nil } end
RUBY
end

it 'registers an offense and corrects when using nested single-line if/;/end in numblock of if body' do
expect_offense(<<~RUBY)
if foo?; bar { if _1; quux else end } end
^^^^^^^^^^^^^^^^^^^^ Do not use `if _1;` - use a ternary operator instead.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use `if foo?;` - use `if/else` instead.
RUBY

expect_correction(<<~RUBY)
if foo?
bar { _1 ? quux : nil } end
RUBY
end

it 'registers an offense and corrects when using nested single-line if/;/end in the numblock of else body' do
expect_offense(<<~RUBY)
if foo?; bar else baz { if _1; quux else end } end
^^^^^^^^^^^^^^^^^^^^ Do not use `if _1;` - use a ternary operator instead.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not use `if foo?;` - use `if/else` instead.
RUBY

expect_correction(<<~RUBY)
if foo?
bar else baz { _1 ? quux : nil } end
RUBY
end
end
end

0 comments on commit 08bed81

Please sign in to comment.