From e586f7f3c887e538fa1f5dd81f2be84ba6a04a0f Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Tue, 19 Sep 2023 12:29:54 +0900 Subject: [PATCH] Fix a false positive for `Rails/RedundantActiveRecordAllMethod` Resolves https://github.com/rubocop/rubocop-rails/pull/1114#issuecomment-1722974569 This PR fixes a false positive for `Rails/RedundantActiveRecordAllMethod` when using some `Enumerable`'s methods with block argument. e.g. `Enumerable#find` and `ActiveRecord::Base#find` have different arguments, So false positives can be prevented. --- ...ails_redundant_active_record_all_method.md | 1 + .../redundant_active_record_all_method.rb | 11 ++++- ...redundant_active_record_all_method_spec.rb | 42 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 changelog/fix_a_false_positive_for_rails_redundant_active_record_all_method.md diff --git a/changelog/fix_a_false_positive_for_rails_redundant_active_record_all_method.md b/changelog/fix_a_false_positive_for_rails_redundant_active_record_all_method.md new file mode 100644 index 0000000000..b722244ff4 --- /dev/null +++ b/changelog/fix_a_false_positive_for_rails_redundant_active_record_all_method.md @@ -0,0 +1 @@ +* [#1126](https://github.com/rubocop/rubocop-rails/pull/1126): Fix a false positive for `Rails/RedundantActiveRecordAllMethod` when using some `Enumerable`'s methods with block argument. ([@koic][]) diff --git a/lib/rubocop/cop/rails/redundant_active_record_all_method.rb b/lib/rubocop/cop/rails/redundant_active_record_all_method.rb index 0d206ad9b3..a2a7f645b0 100644 --- a/lib/rubocop/cop/rails/redundant_active_record_all_method.rb +++ b/lib/rubocop/cop/rails/redundant_active_record_all_method.rb @@ -133,12 +133,14 @@ class RedundantActiveRecordAllMethod < Base without ].to_set.freeze + POSSIBLE_ENUMERABLE_BLOCK_METHODS = %i[any? count find none? one? select sum].freeze + def_node_matcher :followed_by_query_method?, <<~PATTERN (send (send _ :all) QUERYING_METHODS ...) PATTERN def on_send(node) - return unless followed_by_query_method?(node.parent) + return if !followed_by_query_method?(node.parent) || possible_enumerable_block_method?(node) return if node.receiver ? allowed_receiver?(node.receiver) : !inherit_active_record_base?(node) range_of_all_method = offense_range(node) @@ -150,6 +152,13 @@ def on_send(node) private + def possible_enumerable_block_method?(node) + parent = node.parent + return false unless POSSIBLE_ENUMERABLE_BLOCK_METHODS.include?(parent.method_name) + + parent.parent&.block_type? || parent.parent&.numblock_type? || parent.first_argument&.block_pass_type? + end + def offense_range(node) range_between(node.loc.selector.begin_pos, node.source_range.end_pos) end diff --git a/spec/rubocop/cop/rails/redundant_active_record_all_method_spec.rb b/spec/rubocop/cop/rails/redundant_active_record_all_method_spec.rb index 804ce4fed2..1442a4bf83 100644 --- a/spec/rubocop/cop/rails/redundant_active_record_all_method_spec.rb +++ b/spec/rubocop/cop/rails/redundant_active_record_all_method_spec.rb @@ -387,6 +387,48 @@ class User < ::ActiveRecord::Base end RUBY end + + context 'using `any?`' do + it 'does not register an offense when using `any?` with block' do + expect_no_offenses(<<~RUBY) + User.all.any? { |item| item.do_something } + RUBY + end + + it 'does not register an offense when using `any?` with numbered block' do + expect_no_offenses(<<~RUBY) + User.all.any? { _1.do_something } + RUBY + end + + it 'does not register an offense when using `any?` with symbol block' do + expect_no_offenses(<<~RUBY) + User.all.any?(&:do_something) + RUBY + end + end + + described_class::POSSIBLE_ENUMERABLE_BLOCK_METHODS.each do |method| + context "using `#{method}`" do + it "does not register an offense when using `#{method}` with block" do + expect_no_offenses(<<~RUBY) + User.all.#{method} { |item| item.do_something } + RUBY + end + + it "does not register an offense when using `#{method}` with numbered block" do + expect_no_offenses(<<~RUBY) + User.all.#{method} { _1.do_something } + RUBY + end + + it "does not register an offense when using `#{method}` with symbol block" do + expect_no_offenses(<<~RUBY) + User.all.#{method}(&:do_something) + RUBY + end + end + end end context 'with `AllowedReceivers` config' do