From f729a3ec7aad1eac929a8a5632a52660e7669e08 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Thu, 17 Jun 2021 03:11:14 +0900 Subject: [PATCH] Fix an incorrect auto-correct for `Layout/LineLength` This PR fixes an incorrect auto-correct for `Layout/LineLength` when using heredoc as the first method argument and omitting parentheses. ```console % cat example.rb foo <<~RUBY, arg RUBY % bundle exec rubocop --only Layout/LineLength -a (snip) Inspecting 1 file C Offenses: example.rb:1:16: C: [Corrected] Layout/LineLength: Line is too long. [16/15] foo <<~RUBY, arg ^ 1 file inspected, 1 offense detected, 1 offense corrected % cat example.rb foo <<~RUBY, arg RUBY % ruby -c example.rb example.rb:1: syntax error, unexpected end-of-input ``` --- ...an_incorrect_autocorrect_for_layout_line_length.md | 1 + lib/rubocop/cop/mixin/check_line_breakable.rb | 11 ++++++++++- spec/rubocop/cop/layout/line_length_spec.rb | 11 +++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 changelog/fix_an_incorrect_autocorrect_for_layout_line_length.md diff --git a/changelog/fix_an_incorrect_autocorrect_for_layout_line_length.md b/changelog/fix_an_incorrect_autocorrect_for_layout_line_length.md new file mode 100644 index 00000000000..248e9ff3e5c --- /dev/null +++ b/changelog/fix_an_incorrect_autocorrect_for_layout_line_length.md @@ -0,0 +1 @@ +* [#9882](https://github.com/rubocop/rubocop/pull/9882): Fix an incorrect auto-correct for `Layout/LineLength` when using heredoc as the first method argument and omitting parentheses. ([@koic][]) diff --git a/lib/rubocop/cop/mixin/check_line_breakable.rb b/lib/rubocop/cop/mixin/check_line_breakable.rb index e921502ef78..7329fe6402a 100644 --- a/lib/rubocop/cop/mixin/check_line_breakable.rb +++ b/lib/rubocop/cop/mixin/check_line_breakable.rb @@ -72,7 +72,9 @@ def extract_first_element_over_column_limit(node, elements, max) # If a `send` node is not parenthesized, don't move the first element, because it # can result in changed behavior or a syntax error. - elements = elements.drop(1) if node.send_type? && !node.parenthesized? + if node.send_type? && !node.parenthesized? && !first_argument_is_heredoc?(node) + elements = elements.drop(1) + end i = 0 i += 1 while within_column_limit?(elements[i], max, line) @@ -84,6 +86,13 @@ def extract_first_element_over_column_limit(node, elements, max) elements[i - 1] end + # @api private + def first_argument_is_heredoc?(node) + first_argument = node.first_argument + + first_argument.respond_to?(:heredoc?) && first_argument.heredoc? + end + # @api private # If a send node contains a heredoc argument, splitting cannot happen # after the heredoc or else it will cause a syntax error. diff --git a/spec/rubocop/cop/layout/line_length_spec.rb b/spec/rubocop/cop/layout/line_length_spec.rb index a0a3bcee67e..5ad3d910af6 100644 --- a/spec/rubocop/cop/layout/line_length_spec.rb +++ b/spec/rubocop/cop/layout/line_length_spec.rb @@ -768,6 +768,17 @@ def baz(bar) expect_no_corrections end + it 'does not break up the line when parentheses are omitted' do + args = 'x' * 25 + expect_offense(<<~RUBY, args: args) + foo <<~STRING, #{args}xxx + _{args}^^^ Line is too long. [43/40] + STRING + RUBY + + expect_no_corrections + end + context 'and other arguments before the heredoc' do it 'can break up the line before the heredoc argument' do args = 'x' * 20