From 9c5c31b5ceac913913fb634b7a2f3921e9a7bc1e Mon Sep 17 00:00:00 2001 From: Alexandre Terrasa Date: Thu, 20 Aug 2026 17:32:10 -0400 Subject: [PATCH] Avoid unnecessary multiline parentheses --- .../cop/type_toolkit/prefer_not_nil.rb | 13 ++++++++++- .../cop/type_toolkit/prefer_not_nil_spec.rb | 23 +++++++++++++------ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/lib/rubocop/cop/type_toolkit/prefer_not_nil.rb b/lib/rubocop/cop/type_toolkit/prefer_not_nil.rb index d3d283d..c4db52a 100644 --- a/lib/rubocop/cop/type_toolkit/prefer_not_nil.rb +++ b/lib/rubocop/cop/type_toolkit/prefer_not_nil.rb @@ -63,7 +63,7 @@ def replacement_for(argument) #: (RuboCop::AST::SendNode, RuboCop::AST::Node, String) -> String def correction_for(node, argument, replacement) return replacement unless node.multiline? && node.parenthesized_call? - return replacement if argument.first_line == node.loc.begin.line && argument.last_line == node.loc.end.line + return replacement unless comments_inside_parentheses?(node) grouped_range = node.source_range.with(begin_pos: node.loc.begin.begin_pos, end_pos: node.loc.end.end_pos) grouped_source = grouped_range.source @@ -72,6 +72,17 @@ def correction_for(node, argument, replacement) "#{grouped_source}.not_nil!" end + #: (RuboCop::AST::SendNode) -> bool + def comments_inside_parentheses?(node) + contents_begin = node.loc.begin.end_pos + contents_end = node.loc.end.begin_pos + + processed_source.comments.any? do |comment| + comment_range = comment.loc.expression + contents_begin <= comment_range.begin_pos && comment_range.end_pos <= contents_end + end + end + #: (RuboCop::AST::SendNode) -> bool def nested_t_must?(node) node.each_ancestor(:send).any? do |ancestor| diff --git a/spec/rubocop/cop/type_toolkit/prefer_not_nil_spec.rb b/spec/rubocop/cop/type_toolkit/prefer_not_nil_spec.rb index 5629727..6f36da9 100644 --- a/spec/rubocop/cop/type_toolkit/prefer_not_nil_spec.rb +++ b/spec/rubocop/cop/type_toolkit/prefer_not_nil_spec.rb @@ -197,7 +197,7 @@ def explicit_super RUBY end - it "autocorrects multiline calls with whitespace before the method" do + it "drops unnecessary grouping from multiline calls without comments" do assert_offense(<<~RUBY) first = T .must( ^^^^^^^^ #{MSG} @@ -211,12 +211,21 @@ def explicit_super RUBY assert_correction(<<~RUBY) - first = ( - foo - ).not_nil! - second = ( - bar - ).not_nil! + first = foo.not_nil! + second = bar.not_nil! + RUBY + end + + it "preserves a multiline call chain without parentheses" do + assert_offense(<<~RUBY) + variant = T.must( + ^^^^^^^ #{MSG} + InventoryItemVariant.preload(:variant).where(inventory_item_id: @inventory_item_id).first!.variant + ) + RUBY + + assert_correction(<<~RUBY) + variant = InventoryItemVariant.preload(:variant).where(inventory_item_id: @inventory_item_id).first!.variant.not_nil! RUBY end