Skip to content

Commit

Permalink
[Fix #7670] Handle offenses inside heredocs for --disable-uncorrectable
Browse files Browse the repository at this point in the history
The `# rubocop:todo` and `# rubocop:enable` must be placed outside the
heredoc. Otherwise they won't have any effect and we will just add more and
more comments until we crash.
  • Loading branch information
jonas054 authored and bbatsov committed Nov 25, 2020
1 parent 3f7d0c7 commit c155789
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 6 deletions.
1 change: 1 addition & 0 deletions changelog/fix_infinite_disable_uncorrectable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#7670](https://github.com/rubocop-hq/rubocop/issues/7670): Handle offenses inside heredocs for `-a --disable-uncorrectable`. ([@jonas054][])
32 changes: 26 additions & 6 deletions lib/rubocop/cop/autocorrect_logic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,36 @@ def autocorrect_enabled?
private

def disable_offense(range)
eol_comment = " # rubocop:todo #{cop_name}"
needed_line_length = (range.source_line + eol_comment).length
if needed_line_length <= max_line_length
disable_offense_at_end_of_line(range_of_first_line(range),
eol_comment)
heredoc_range = surrounding_heredoc(range)
if heredoc_range
disable_offense_before_and_after(range_by_lines(heredoc_range))
else
disable_offense_before_and_after(range_by_lines(range))
eol_comment = " # rubocop:todo #{cop_name}"
needed_line_length = (range.source_line + eol_comment).length
if needed_line_length <= max_line_length
disable_offense_at_end_of_line(range_of_first_line(range), eol_comment)
else
disable_offense_before_and_after(range_by_lines(range))
end
end
end

def surrounding_heredoc(offense_range)
# The empty offense range is an edge case that can be reached from the Lint/Syntax cop.
return nil if offense_range.empty?

@heredoc_ranges ||= begin
ranges = []
processed_source.ast.each_descendant do |node|
if node.respond_to?(:heredoc?) && node.heredoc?
ranges << node.loc.expression.join(node.loc.heredoc_end)
end
end
ranges
end
@heredoc_ranges.find { |range| range.contains?(offense_range) }
end

def range_of_first_line(range)
begin_of_first_line = range.begin_pos - range.column
end_of_first_line = begin_of_first_line + range.source_line.length
Expand Down
34 changes: 34 additions & 0 deletions spec/rubocop/cli/cli_disable_uncorrectable_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,40 @@ def choose_move(who_to_move) # rubocop:todo Metrics/CyclomaticComplexity
# last line
RUBY
end

context 'and the offense is inside a heredoc' do
it 'adds before-and-after disable statement around the heredoc' do
create_file('example.rb', <<~'RUBY')
# frozen_string_literal: true
def our_function
ourVariable = "foo"
script = <<~JS
<script>
window.stuff = "#{ourVariable}"
</script>
JS
puts(script)
end
RUBY
expect(exit_code).to eq(0)
expect(IO.read('example.rb')).to eq(<<~'RUBY')
# frozen_string_literal: true
def our_function
ourVariable = 'foo' # rubocop:todo Naming/VariableName
# rubocop:todo Naming/VariableName
script = <<~JS
<script>
window.stuff = "#{ourVariable}"
</script>
JS
# rubocop:enable Naming/VariableName
puts(script)
end
RUBY
end
end
end
end
end

0 comments on commit c155789

Please sign in to comment.