diff --git a/changelog/fix_autocorrection_for_rails_delegate.md b/changelog/fix_autocorrection_for_rails_delegate.md new file mode 100644 index 0000000000..226c0cf8cc --- /dev/null +++ b/changelog/fix_autocorrection_for_rails_delegate.md @@ -0,0 +1 @@ +* [#1164](https://github.com/rubocop/rubocop-rails/issues/1164): Fix autocorrection for `Rails/Delegate` to preserve comments. ([@masato-bkn][]) diff --git a/lib/rubocop/cop/rails/delegate.rb b/lib/rubocop/cop/rails/delegate.rb index e381e81b44..aea4e2e51d 100644 --- a/lib/rubocop/cop/rails/delegate.rb +++ b/lib/rubocop/cop/rails/delegate.rb @@ -82,7 +82,11 @@ def on_def(node) def register_offense(node) add_offense(node.loc.keyword) do |corrector| - corrector.replace(node, build_delegation(node)) + comments = processed_source.ast_with_comments[node.body] + preferred = build_comment(comments) + preferred += build_delegation(node) + + corrector.replace(node, preferred) end end @@ -97,6 +101,20 @@ def build_delegation(node) delegation.join(', ') end + def build_comment(comments) + return '' if comments.empty? + + comments.map.with_index do |comment, i| + comment.text + ("\n" * newline_count_between_comments(comments, i)) + end.join << "\n" + end + + def newline_count_between_comments(comments, index) + return 0 if index >= comments.size - 1 + + comments[index + 1].loc.line - comments[index].loc.line + end + def trivial_delegate?(def_node) delegate?(def_node) && method_name_matches?(def_node.method_name, def_node.body) && diff --git a/spec/rubocop/cop/rails/delegate_spec.rb b/spec/rubocop/cop/rails/delegate_spec.rb index 401e19b19f..ef49143682 100644 --- a/spec/rubocop/cop/rails/delegate_spec.rb +++ b/spec/rubocop/cop/rails/delegate_spec.rb @@ -55,6 +55,80 @@ def bar_foo RUBY end + it 'finds trivial delegate with single line comment' do + expect_offense(<<~RUBY) + def foo + ^^^ Use `delegate` to define delegations. + # comment + bar.foo + end + RUBY + + expect_correction(<<~RUBY) + # comment + delegate :foo, to: :bar + RUBY + end + + it 'finds trivial delegate with multiline comments' do + expect_offense(<<~RUBY) + def foo + ^^^ Use `delegate` to define delegations. + # comment 1 + # comment 2 + bar.foo + end + RUBY + + expect_correction(<<~RUBY) + # comment 1 + # comment 2 + delegate :foo, to: :bar + RUBY + end + + it 'finds trivial delegate with multiline comments including blank lines' do + expect_offense(<<~RUBY) + def foo + ^^^ Use `delegate` to define delegations. + # comment 1 + + # comment 2 + + + # comment 3 + bar.foo + end + RUBY + + expect_correction(<<~RUBY) + # comment 1 + + # comment 2 + + + # comment 3 + delegate :foo, to: :bar + RUBY + end + + it 'finds trivial delegate with preceding comments' do + expect_offense(<<~RUBY) + # comment 1 + def foo + ^^^ Use `delegate` to define delegations. + # comment 2 + bar.foo + end + RUBY + + expect_correction(<<~RUBY) + # comment 1 + # comment 2 + delegate :foo, to: :bar + RUBY + end + it 'finds trivial delegate to `self` when underscored method' do expect_offense(<<~RUBY) def bar_foo