From c0a9b9ea746bc55ac4629dcf6706522c8fe50879 Mon Sep 17 00:00:00 2001 From: nobuyo Date: Tue, 19 Apr 2022 22:55:15 +0900 Subject: [PATCH] [Fix #10488] Fix autocorrection for `Layout/MultilineMethodCallIndentation` breaks indentation for nesting of method calls --- ...ine_method_call_indentation_for_nesting.md | 1 + .../multiline_method_call_indentation.rb | 21 +++++++++++++++++-- .../multiline_method_call_indentation_spec.rb | 8 +++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 changelog/fix_layout_multiline_method_call_indentation_for_nesting.md diff --git a/changelog/fix_layout_multiline_method_call_indentation_for_nesting.md b/changelog/fix_layout_multiline_method_call_indentation_for_nesting.md new file mode 100644 index 000000000000..f6db3c2e08cd --- /dev/null +++ b/changelog/fix_layout_multiline_method_call_indentation_for_nesting.md @@ -0,0 +1 @@ +* [#10488](https://github.com/rubocop/rubocop/issues/10488): Fix autocorrection for `Layout/MultilineMethodCallIndentation` breaks indentation for nesting of method calls. ([@nobuyo][]) diff --git a/lib/rubocop/cop/layout/multiline_method_call_indentation.rb b/lib/rubocop/cop/layout/multiline_method_call_indentation.rb index 3e74d16eef3c..c26c89397829 100644 --- a/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +++ b/lib/rubocop/cop/layout/multiline_method_call_indentation.rb @@ -201,14 +201,31 @@ def receiver_alignment_base(node) def semantic_alignment_node(node) return if argument_in_method_call(node, :with_parentheses) + dot_right_above = get_dot_right_above(node) + return dot_right_above if dot_right_above + + node = first_call_has_a_dot(node) + return if node.loc.dot.line != node.first_line + + node + end + + def get_dot_right_above(node) + node.each_ancestor.find do |a| + dot = a.loc.respond_to?(:dot) && a.loc.dot + next unless dot + + dot.line == node.loc.dot.line - 1 && dot.column == node.loc.dot.column + end + end + + def first_call_has_a_dot(node) # descend to root of method chain node = node.receiver while node.receiver # ascend to first call which has a dot node = node.parent node = node.parent until node.loc.respond_to?(:dot) && node.loc.dot - return if node.loc.dot.line != node.first_line - node end diff --git a/spec/rubocop/cop/layout/multiline_method_call_indentation_spec.rb b/spec/rubocop/cop/layout/multiline_method_call_indentation_spec.rb index 943230abe28d..2def04bffd1d 100644 --- a/spec/rubocop/cop/layout/multiline_method_call_indentation_spec.rb +++ b/spec/rubocop/cop/layout/multiline_method_call_indentation_spec.rb @@ -357,6 +357,14 @@ def foo end RUBY end + + it 'accepts nested method calls' do + expect_no_offenses(<<~RUBY) + expect { post :action, params: params, format: :json }.to change { Foo.bar }.by(0) + .and change { Baz.quux }.by(0) + .and raise_error(StandardError) + RUBY + end end it 'accepts correctly aligned methods in operands' do