Skip to content

Commit

Permalink
Fix an incorrect auto-correct for Style/IfUnlessModifier
Browse files Browse the repository at this point in the history
This PR fixes the following incorrect auto-correct for `Style/IfUnlessModifier`
when using a method with heredoc argument.

```console
% cat .rubocop.yml
Layout/LineLength:
  Max: 80

% cat example.rb
fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(<<~EOS) if condition
  string
EOS

% bundle exec rubocop --only Style/IfUnlessModifier -a
(snip)

Inspecting 1 file
C

Offenses:

example.rb:1:70: C: [Corrected] Style/IfUnlessModifier: Modifier form of
if makes the line too long.
fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(<<~EOS) if condition
                                                                     ^^

1 file inspected, 1 offense detected, 1 offense corrected
```

## Before

Auto-corrected to unexpected invalid syntax code.

```console
% cat example.rb
if condition
  fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(<<~EOS)
end
  string
EOS

% ruby -c example.rb
example.rb:2: syntax error, unexpected end-of-input, expecting `end'
```

## After

Auto-corrected to expected valid syntax code.

```console
% cat example.rb
if condition
  fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(<<~EOS)
    string
  EOS
end
```
  • Loading branch information
koic authored and bbatsov committed Apr 10, 2021
1 parent 0dbf272 commit 1f1e59c
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 3 deletions.
@@ -0,0 +1 @@
* [#9690](https://github.com/rubocop/rubocop/pull/9690): Fix an incorrect auto-correct for `Style/IfUnlessModifier` when using a method with heredoc argument. ([@koic][])
40 changes: 37 additions & 3 deletions lib/rubocop/cop/style/if_unless_modifier.rb
Expand Up @@ -38,6 +38,7 @@ class IfUnlessModifier < Base
include StatementModifier
include LineLengthHelp
include IgnoredPattern
include RangeHelp
extend AutoCorrector

MSG_USE_MODIFIER = 'Favor modifier `%<keyword>s` usage when having a ' \
Expand Down Expand Up @@ -66,7 +67,16 @@ def on_if(node)

def autocorrect(corrector, node)
replacement = if node.modifier_form?
to_normal_form(node)
indentation = ' ' * node.source_range.column
last_argument = node.if_branch.last_argument

if last_argument.respond_to?(:heredoc?) && last_argument.heredoc?
heredoc = extract_heredoc_from(last_argument)
remove_heredoc(corrector, heredoc)
to_normal_form_with_heredoc(node, indentation, heredoc)
else
to_normal_form(node, indentation)
end
else
to_modifier_form(node)
end
Expand Down Expand Up @@ -151,14 +161,38 @@ def another_statement_on_same_line?(node)
node && (sibling = node.children[index + 1]) && sibling.source_range.first_line == line_no
end

def to_normal_form(node)
indentation = ' ' * node.source_range.column
def to_normal_form(node, indentation)
<<~RUBY.chomp
#{node.keyword} #{node.condition.source}
#{indentation} #{node.body.source}
#{indentation}end
RUBY
end

def to_normal_form_with_heredoc(node, indentation, heredoc)
heredoc_body, heredoc_end = heredoc

<<~RUBY.chomp
#{node.keyword} #{node.condition.source}
#{indentation} #{node.body.source}
#{indentation} #{heredoc_body.source.chomp}
#{indentation} #{heredoc_end.source.chomp}
#{indentation}end
RUBY
end

def extract_heredoc_from(last_argument)
heredoc_body = last_argument.loc.heredoc_body
heredoc_end = last_argument.loc.heredoc_end

[heredoc_body, heredoc_end]
end

def remove_heredoc(corrector, heredoc)
heredoc.each do |range|
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
end
end
end
end
end
Expand Down
19 changes: 19 additions & 0 deletions spec/rubocop/cop/style/if_unless_modifier_spec.rb
Expand Up @@ -73,6 +73,25 @@ def f
end
end

context 'when using a method with heredoc argument' do
it 'accepts' do
expect_offense(<<~RUBY)
fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(<<~EOS) if condition
^^ Modifier form of `if` makes the line too long.
string
EOS
RUBY

expect_correction(<<~RUBY)
if condition
fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(<<~EOS)
string
EOS
end
RUBY
end
end

describe 'IgnoreCopDirectives' do
let(:spaces) { ' ' * 57 }
let(:comment) { '# rubocop:disable Style/For' }
Expand Down

0 comments on commit 1f1e59c

Please sign in to comment.