rubocop 1.75.8 → 1.81.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +20 -16
 - data/config/default.yml +121 -28
 - data/config/obsoletion.yml +6 -3
 - data/exe/rubocop +1 -8
 - data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
 - data/lib/rubocop/cli.rb +18 -3
 - data/lib/rubocop/config_loader.rb +4 -39
 - data/lib/rubocop/config_loader_resolver.rb +5 -4
 - data/lib/rubocop/config_store.rb +5 -0
 - data/lib/rubocop/cop/autocorrect_logic.rb +4 -4
 - data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
 - data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
 - data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
 - data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
 - data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
 - data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
 - data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
 - data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
 - data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
 - data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
 - data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +4 -1
 - data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
 - data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
 - data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
 - data/lib/rubocop/cop/layout/class_structure.rb +1 -1
 - data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
 - data/lib/rubocop/cop/layout/dot_position.rb +1 -1
 - data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
 - data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
 - data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
 - data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
 - data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
 - data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
 - data/lib/rubocop/cop/layout/line_length.rb +35 -6
 - data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
 - data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +8 -0
 - data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
 - data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
 - data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
 - data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
 - data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
 - data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
 - data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
 - data/lib/rubocop/cop/lint/cop_directive_syntax.rb +13 -7
 - data/lib/rubocop/cop/lint/debugger.rb +0 -2
 - data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
 - data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
 - data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
 - data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
 - data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
 - data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
 - data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
 - data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
 - data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
 - data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
 - data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
 - data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
 - data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
 - data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
 - data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
 - data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
 - data/lib/rubocop/cop/lint/self_assignment.rb +31 -5
 - data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
 - data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
 - data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
 - data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
 - data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
 - data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
 - data/lib/rubocop/cop/lint/useless_or.rb +98 -0
 - data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
 - data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
 - data/lib/rubocop/cop/lint/void.rb +7 -0
 - data/lib/rubocop/cop/message_annotator.rb +1 -1
 - data/lib/rubocop/cop/mixin/alignment.rb +1 -1
 - data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
 - data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
 - data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
 - data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
 - data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
 - data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
 - data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
 - data/lib/rubocop/cop/naming/file_name.rb +2 -2
 - data/lib/rubocop/cop/naming/method_name.rb +129 -13
 - data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
 - data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
 - data/lib/rubocop/cop/security/eval.rb +2 -1
 - data/lib/rubocop/cop/security/json_load.rb +33 -11
 - data/lib/rubocop/cop/security/open.rb +1 -0
 - data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
 - data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
 - data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
 - data/lib/rubocop/cop/style/array_intersect.rb +99 -35
 - data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
 - data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
 - data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
 - data/lib/rubocop/cop/style/case_like_if.rb +1 -1
 - data/lib/rubocop/cop/style/collection_querying.rb +167 -0
 - data/lib/rubocop/cop/style/conditional_assignment.rb +11 -5
 - data/lib/rubocop/cop/style/constant_visibility.rb +14 -9
 - data/lib/rubocop/cop/style/dig_chain.rb +1 -1
 - data/lib/rubocop/cop/style/double_negation.rb +1 -1
 - data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
 - data/lib/rubocop/cop/style/endless_method.rb +15 -2
 - data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
 - data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
 - data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
 - data/lib/rubocop/cop/style/float_division.rb +15 -1
 - data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
 - data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
 - data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
 - data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
 - data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
 - data/lib/rubocop/cop/style/it_assignment.rb +69 -12
 - data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
 - data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
 - data/lib/rubocop/cop/style/map_to_set.rb +1 -3
 - data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
 - data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
 - data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
 - data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
 - data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
 - data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
 - data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
 - data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
 - data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
 - data/lib/rubocop/cop/style/redundant_format.rb +26 -5
 - data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
 - data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
 - data/lib/rubocop/cop/style/redundant_parentheses.rb +55 -16
 - data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
 - data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
 - data/lib/rubocop/cop/style/redundant_self.rb +8 -5
 - data/lib/rubocop/cop/style/safe_navigation.rb +44 -12
 - data/lib/rubocop/cop/style/semicolon.rb +23 -7
 - data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
 - data/lib/rubocop/cop/style/sole_nested_conditional.rb +40 -3
 - data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
 - data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
 - data/lib/rubocop/cop/style/symbol_array.rb +1 -1
 - data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
 - data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
 - data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
 - data/lib/rubocop/cop/style/unless_else.rb +10 -9
 - data/lib/rubocop/cop/utils/format_string.rb +10 -0
 - data/lib/rubocop/cop/variable_force/variable.rb +1 -1
 - data/lib/rubocop/cop/variable_force.rb +25 -8
 - data/lib/rubocop/cops_documentation_generator.rb +5 -4
 - data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -5
 - data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
 - data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
 - data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
 - data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
 - data/lib/rubocop/lsp/diagnostic.rb +25 -24
 - data/lib/rubocop/lsp/routes.rb +65 -9
 - data/lib/rubocop/lsp/runtime.rb +2 -2
 - data/lib/rubocop/lsp/server.rb +2 -2
 - data/lib/rubocop/lsp/stdin_runner.rb +0 -16
 - data/lib/rubocop/pending_cops_reporter.rb +56 -0
 - data/lib/rubocop/result_cache.rb +14 -12
 - data/lib/rubocop/rspec/expect_offense.rb +9 -3
 - data/lib/rubocop/runner.rb +6 -4
 - data/lib/rubocop/server/cache.rb +4 -2
 - data/lib/rubocop/server/client_command/base.rb +10 -0
 - data/lib/rubocop/server/client_command/exec.rb +2 -1
 - data/lib/rubocop/server/client_command/start.rb +11 -1
 - data/lib/rubocop/target_finder.rb +9 -9
 - data/lib/rubocop/target_ruby.rb +10 -1
 - data/lib/rubocop/version.rb +1 -1
 - data/lib/rubocop.rb +12 -1
 - data/lib/ruby_lsp/rubocop/addon.rb +25 -10
 - data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
 - metadata +18 -7
 
| 
         @@ -6,22 +6,40 @@ module RuboCop 
     | 
|
| 
       6 
6 
     | 
    
         
             
                  # Checks for the use of JSON class methods which have potential
         
     | 
| 
       7 
7 
     | 
    
         
             
                  # security issues.
         
     | 
| 
       8 
8 
     | 
    
         
             
                  #
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # `JSON.load` and similar methods allow deserialization of arbitrary ruby objects:
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # [source,ruby]
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # ----
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # require 'json/add/string'
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # result = JSON.load('{ "json_class": "String", "raw": [72, 101, 108, 108, 111] }')
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # pp result # => "Hello"
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # ----
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # Never use `JSON.load` for untrusted user input. Prefer `JSON.parse` unless you have
         
     | 
| 
      
 19 
     | 
    
         
            +
                  # a concrete use-case for `JSON.load`.
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #
         
     | 
| 
      
 21 
     | 
    
         
            +
                  # NOTE: Starting with `json` gem version 2.8.0, triggering this behavior without explicitly
         
     | 
| 
      
 22 
     | 
    
         
            +
                  # passing the `create_additions` keyword argument emits a deprecation warning, with the
         
     | 
| 
      
 23 
     | 
    
         
            +
                  # goal of being secure by default in the next major version 3.0.0.
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #
         
     | 
| 
       9 
25 
     | 
    
         
             
                  # @safety
         
     | 
| 
       10 
26 
     | 
    
         
             
                  #   This cop's autocorrection is unsafe because it's potentially dangerous.
         
     | 
| 
       11 
     | 
    
         
            -
                  #   If using a stream, like `JSON.load(open('file'))`,  
     | 
| 
      
 27 
     | 
    
         
            +
                  #   If using a stream, like `JSON.load(open('file'))`, you will need to call
         
     | 
| 
       12 
28 
     | 
    
         
             
                  #   `#read` manually, like `JSON.parse(open('file').read)`.
         
     | 
| 
       13 
     | 
    
         
            -
                  #   If reading single values (rather than proper JSON objects), like
         
     | 
| 
       14 
     | 
    
         
            -
                  #   `JSON.load('false')`, it will need to pass the `quirks_mode: true`
         
     | 
| 
       15 
     | 
    
         
            -
                  #   option, like `JSON.parse('false', quirks_mode: true)`.
         
     | 
| 
       16 
29 
     | 
    
         
             
                  #   Other similar issues may apply.
         
     | 
| 
       17 
30 
     | 
    
         
             
                  #
         
     | 
| 
       18 
31 
     | 
    
         
             
                  # @example
         
     | 
| 
       19 
32 
     | 
    
         
             
                  #   # bad
         
     | 
| 
       20 
     | 
    
         
            -
                  #   JSON.load( 
     | 
| 
       21 
     | 
    
         
            -
                  #   JSON.restore( 
     | 
| 
      
 33 
     | 
    
         
            +
                  #   JSON.load('{}')
         
     | 
| 
      
 34 
     | 
    
         
            +
                  #   JSON.restore('{}')
         
     | 
| 
       22 
35 
     | 
    
         
             
                  #
         
     | 
| 
       23 
36 
     | 
    
         
             
                  #   # good
         
     | 
| 
       24 
     | 
    
         
            -
                  #   JSON.parse( 
     | 
| 
      
 37 
     | 
    
         
            +
                  #   JSON.parse('{}')
         
     | 
| 
      
 38 
     | 
    
         
            +
                  #   JSON.unsafe_load('{}')
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #   # good - explicit use of `create_additions` option
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #   JSON.load('{}', create_additions: true)
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #   JSON.load('{}', create_additions: false)
         
     | 
| 
       25 
43 
     | 
    
         
             
                  #
         
     | 
| 
       26 
44 
     | 
    
         
             
                  class JSONLoad < Base
         
     | 
| 
       27 
45 
     | 
    
         
             
                    extend AutoCorrector
         
     | 
| 
         @@ -29,13 +47,17 @@ module RuboCop 
     | 
|
| 
       29 
47 
     | 
    
         
             
                    MSG = 'Prefer `JSON.parse` over `JSON.%<method>s`.'
         
     | 
| 
       30 
48 
     | 
    
         
             
                    RESTRICT_ON_SEND = %i[load restore].freeze
         
     | 
| 
       31 
49 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                    # @!method  
     | 
| 
       33 
     | 
    
         
            -
                    def_node_matcher : 
     | 
| 
       34 
     | 
    
         
            -
                      ( 
     | 
| 
      
 50 
     | 
    
         
            +
                    # @!method insecure_json_load(node)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    def_node_matcher :insecure_json_load, <<~PATTERN
         
     | 
| 
      
 52 
     | 
    
         
            +
                      (
         
     | 
| 
      
 53 
     | 
    
         
            +
                        send (const {nil? cbase} :JSON) ${:load :restore}
         
     | 
| 
      
 54 
     | 
    
         
            +
                        ...
         
     | 
| 
      
 55 
     | 
    
         
            +
                        !(hash `(sym $:create_additions))
         
     | 
| 
      
 56 
     | 
    
         
            +
                      )
         
     | 
| 
       35 
57 
     | 
    
         
             
                    PATTERN
         
     | 
| 
       36 
58 
     | 
    
         | 
| 
       37 
59 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
       38 
     | 
    
         
            -
                       
     | 
| 
      
 60 
     | 
    
         
            +
                      insecure_json_load(node) do |method|
         
     | 
| 
       39 
61 
     | 
    
         
             
                        add_offense(node.loc.selector, message: format(MSG, method: method)) do |corrector|
         
     | 
| 
       40 
62 
     | 
    
         
             
                          corrector.replace(node.loc.selector, 'parse')
         
     | 
| 
       41 
63 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -348,7 +348,7 @@ module RuboCop 
     | 
|
| 
       348 
348 
     | 
    
         
             
                    end
         
     | 
| 
       349 
349 
     | 
    
         | 
| 
       350 
350 
     | 
    
         
             
                    def remove_modifier_node_within_begin(corrector, modifier_node, begin_node)
         
     | 
| 
       351 
     | 
    
         
            -
                      def_node = begin_node.children[1]
         
     | 
| 
      
 351 
     | 
    
         
            +
                      def_node = begin_node.children[begin_node.children.index(modifier_node) + 1]
         
     | 
| 
       352 
352 
     | 
    
         
             
                      range = modifier_node.source_range.begin.join(def_node.source_range.begin)
         
     | 
| 
       353 
353 
     | 
    
         
             
                      corrector.remove(range)
         
     | 
| 
       354 
354 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -84,7 +84,10 @@ module RuboCop 
     | 
|
| 
       84 
84 
     | 
    
         | 
| 
       85 
85 
     | 
    
         
             
                    def autocorrect(corrector, node)
         
     | 
| 
       86 
86 
     | 
    
         
             
                      if (preferred_accessors = preferred_accessors(node))
         
     | 
| 
       87 
     | 
    
         
            -
                        corrector.replace( 
     | 
| 
      
 87 
     | 
    
         
            +
                        corrector.replace(
         
     | 
| 
      
 88 
     | 
    
         
            +
                          grouped_style? ? node : range_with_trailing_argument_comment(node),
         
     | 
| 
      
 89 
     | 
    
         
            +
                          preferred_accessors
         
     | 
| 
      
 90 
     | 
    
         
            +
                        )
         
     | 
| 
       88 
91 
     | 
    
         
             
                      else
         
     | 
| 
       89 
92 
     | 
    
         
             
                        range = range_with_surrounding_space(node.source_range, side: :left)
         
     | 
| 
       90 
93 
     | 
    
         
             
                        corrector.remove(range)
         
     | 
| 
         @@ -196,6 +199,15 @@ module RuboCop 
     | 
|
| 
       196 
199 
     | 
    
         
             
                        end
         
     | 
| 
       197 
200 
     | 
    
         
             
                      end.join("\n")
         
     | 
| 
       198 
201 
     | 
    
         
             
                    end
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
                    def range_with_trailing_argument_comment(node)
         
     | 
| 
      
 204 
     | 
    
         
            +
                      comment = processed_source.ast_with_comments[node.last_argument].last
         
     | 
| 
      
 205 
     | 
    
         
            +
                      if comment
         
     | 
| 
      
 206 
     | 
    
         
            +
                        add_range(node.source_range, comment.source_range)
         
     | 
| 
      
 207 
     | 
    
         
            +
                      else
         
     | 
| 
      
 208 
     | 
    
         
            +
                        node
         
     | 
| 
      
 209 
     | 
    
         
            +
                      end
         
     | 
| 
      
 210 
     | 
    
         
            +
                    end
         
     | 
| 
       199 
211 
     | 
    
         
             
                  end
         
     | 
| 
       200 
212 
     | 
    
         
             
                end
         
     | 
| 
       201 
213 
     | 
    
         
             
              end
         
     | 
| 
         @@ -146,7 +146,6 @@ module RuboCop 
     | 
|
| 
       146 
146 
     | 
    
         
             
                    minimum_target_ruby_version 2.7
         
     | 
| 
       147 
147 
     | 
    
         | 
| 
       148 
148 
     | 
    
         
             
                    FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
         
     | 
| 
       149 
     | 
    
         
            -
                    ADDITIONAL_ARG_TYPES = %i[lvar arg optarg].freeze
         
     | 
| 
       150 
149 
     | 
    
         | 
| 
       151 
150 
     | 
    
         
             
                    FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
         
     | 
| 
       152 
151 
     | 
    
         
             
                    ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
         
     | 
| 
         @@ -198,9 +197,9 @@ module RuboCop 
     | 
|
| 
       198 
197 
     | 
    
         
             
                      send_classifications.all? { |_, c, _, _| all_classifications.include?(c) }
         
     | 
| 
       199 
198 
     | 
    
         
             
                    end
         
     | 
| 
       200 
199 
     | 
    
         | 
| 
       201 
     | 
    
         
            -
                    # rubocop:disable Metrics/MethodLength
         
     | 
| 
      
 200 
     | 
    
         
            +
                    # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
         
     | 
| 
       202 
201 
     | 
    
         
             
                    def add_forward_all_offenses(node, send_classifications, forwardable_args)
         
     | 
| 
       203 
     | 
    
         
            -
                       
     | 
| 
      
 202 
     | 
    
         
            +
                      rest_arg, kwrest_arg, block_arg = *forwardable_args
         
     | 
| 
       204 
203 
     | 
    
         
             
                      registered_block_arg_offense = false
         
     | 
| 
       205 
204 
     | 
    
         | 
| 
       206 
205 
     | 
    
         
             
                      send_classifications.each do |send_node, c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
         
     | 
| 
         @@ -212,16 +211,20 @@ module RuboCop 
     | 
|
| 
       212 
211 
     | 
    
         
             
                          registered_block_arg_offense = true
         
     | 
| 
       213 
212 
     | 
    
         
             
                          break
         
     | 
| 
       214 
213 
     | 
    
         
             
                        else
         
     | 
| 
       215 
     | 
    
         
            -
                           
     | 
| 
      
 214 
     | 
    
         
            +
                          first_arg = forward_rest || forward_kwrest || forward_all_first_argument(send_node)
         
     | 
| 
      
 215 
     | 
    
         
            +
                          register_forward_all_offense(send_node, send_node, first_arg)
         
     | 
| 
       216 
216 
     | 
    
         
             
                        end
         
     | 
| 
       217 
217 
     | 
    
         
             
                      end
         
     | 
| 
       218 
218 
     | 
    
         | 
| 
       219 
219 
     | 
    
         
             
                      return if registered_block_arg_offense
         
     | 
| 
       220 
220 
     | 
    
         | 
| 
       221 
     | 
    
         
            -
                       
     | 
| 
       222 
     | 
    
         
            -
             
     | 
| 
      
 221 
     | 
    
         
            +
                      register_forward_all_offense(node, node.arguments, rest_arg || kwrest_arg)
         
     | 
| 
      
 222 
     | 
    
         
            +
                    end
         
     | 
| 
      
 223 
     | 
    
         
            +
                    # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
      
 225 
     | 
    
         
            +
                    def forward_all_first_argument(node)
         
     | 
| 
      
 226 
     | 
    
         
            +
                      node.arguments.reverse_each.find(&:forwarded_restarg_type?)
         
     | 
| 
       223 
227 
     | 
    
         
             
                    end
         
     | 
| 
       224 
     | 
    
         
            -
                    # rubocop:enable Metrics/MethodLength
         
     | 
| 
       225 
228 
     | 
    
         | 
| 
       226 
229 
     | 
    
         
             
                    # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
         
     | 
| 
       227 
230 
     | 
    
         
             
                    def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
         
     | 
| 
         @@ -361,18 +364,9 @@ module RuboCop 
     | 
|
| 
       361 
364 
     | 
    
         
             
                      end
         
     | 
| 
       362 
365 
     | 
    
         
             
                    end
         
     | 
| 
       363 
366 
     | 
    
         | 
| 
       364 
     | 
    
         
            -
                    # rubocop:disable Metrics/AbcSize
         
     | 
| 
       365 
367 
     | 
    
         
             
                    def arguments_range(node, first_node)
         
     | 
| 
       366 
     | 
    
         
            -
                       
     | 
| 
       367 
     | 
    
         
            -
                        next true if ADDITIONAL_ARG_TYPES.include?(arg.type) || arg.variable? || arg.call_type?
         
     | 
| 
       368 
     | 
    
         
            -
             
     | 
| 
       369 
     | 
    
         
            -
                        arg.literal? && arg.each_descendant(:kwsplat).none?
         
     | 
| 
       370 
     | 
    
         
            -
                      end
         
     | 
| 
       371 
     | 
    
         
            -
             
     | 
| 
       372 
     | 
    
         
            -
                      start_node = first_node || arguments.first
         
     | 
| 
       373 
     | 
    
         
            -
                      start_node.source_range.begin.join(arguments.last.source_range.end)
         
     | 
| 
      
 368 
     | 
    
         
            +
                      first_node.source_range.begin.join(node.last_argument.source_range.end)
         
     | 
| 
       374 
369 
     | 
    
         
             
                    end
         
     | 
| 
       375 
     | 
    
         
            -
                    # rubocop:enable Metrics/AbcSize
         
     | 
| 
       376 
370 
     | 
    
         | 
| 
       377 
371 
     | 
    
         
             
                    def allow_only_rest_arguments?
         
     | 
| 
       378 
372 
     | 
    
         
             
                      cop_config.fetch('AllowOnlyRestArgument', true)
         
     | 
| 
         @@ -5,12 +5,17 @@ module RuboCop 
     | 
|
| 
       5 
5 
     | 
    
         
             
                module Style
         
     | 
| 
       6 
6 
     | 
    
         
             
                  # In Ruby 3.1, `Array#intersect?` has been added.
         
     | 
| 
       7 
7 
     | 
    
         
             
                  #
         
     | 
| 
       8 
     | 
    
         
            -
                  # This cop identifies places where 
     | 
| 
       9 
     | 
    
         
            -
                  # or `(array1.intersection(array2)).any?` can be replaced by
         
     | 
| 
       10 
     | 
    
         
            -
                  # `array1.intersect?(array2)`.
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # This cop identifies places where:
         
     | 
| 
       11 
9 
     | 
    
         
             
                  #
         
     | 
| 
       12 
     | 
    
         
            -
                  #  
     | 
| 
       13 
     | 
    
         
            -
                  # `(array1 
     | 
| 
      
 10 
     | 
    
         
            +
                  # * `(array1 & array2).any?`
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # * `(array1.intersection(array2)).any?`
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # * `array1.any? { |elem| array2.member?(elem) }`
         
     | 
| 
      
 13 
     | 
    
         
            +
                  # * `(array1 & array2).count > 0`
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # * `(array1 & array2).size > 0`
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # can be replaced with `array1.intersect?(array2)`.
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # `array1.intersect?(array2)` is faster and more readable.
         
     | 
| 
       14 
19 
     | 
    
         
             
                  #
         
     | 
| 
       15 
20 
     | 
    
         
             
                  # In cases like the following, compatibility is not ensured,
         
     | 
| 
       16 
21 
     | 
    
         
             
                  # so it will not be detected when using block argument.
         
     | 
| 
         @@ -40,10 +45,27 @@ module RuboCop 
     | 
|
| 
       40 
45 
     | 
    
         
             
                  #   array1.intersection(array2).empty?
         
     | 
| 
       41 
46 
     | 
    
         
             
                  #   array1.intersection(array2).none?
         
     | 
| 
       42 
47 
     | 
    
         
             
                  #
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #   array1.any? { |elem| array2.member?(elem) }
         
     | 
| 
      
 50 
     | 
    
         
            +
                  #   array1.none? { |elem| array2.member?(elem) }
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #
         
     | 
| 
       43 
52 
     | 
    
         
             
                  #   # good
         
     | 
| 
       44 
53 
     | 
    
         
             
                  #   array1.intersect?(array2)
         
     | 
| 
       45 
54 
     | 
    
         
             
                  #   !array1.intersect?(array2)
         
     | 
| 
       46 
55 
     | 
    
         
             
                  #
         
     | 
| 
      
 56 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 57 
     | 
    
         
            +
                  #   (array1 & array2).count > 0
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #   (array1 & array2).count.positive?
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #   (array1 & array2).count != 0
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #   (array1 & array2).count == 0
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #   (array1 & array2).count.zero?
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 65 
     | 
    
         
            +
                  #   array1.intersect?(array2)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #
         
     | 
| 
      
 67 
     | 
    
         
            +
                  #   !array1.intersect?(array2)
         
     | 
| 
      
 68 
     | 
    
         
            +
                  #
         
     | 
| 
       47 
69 
     | 
    
         
             
                  # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
         
     | 
| 
       48 
70 
     | 
    
         
             
                  #   # good
         
     | 
| 
       49 
71 
     | 
    
         
             
                  #   (array1 & array2).present?
         
     | 
| 
         @@ -66,64 +88,106 @@ module RuboCop 
     | 
|
| 
       66 
88 
     | 
    
         
             
                    PREDICATES = %i[any? empty? none?].to_set.freeze
         
     | 
| 
       67 
89 
     | 
    
         
             
                    ACTIVE_SUPPORT_PREDICATES = (PREDICATES + %i[present? blank?]).freeze
         
     | 
| 
       68 
90 
     | 
    
         | 
| 
      
 91 
     | 
    
         
            +
                    ARRAY_SIZE_METHODS = %i[count length size].to_set.freeze
         
     | 
| 
      
 92 
     | 
    
         
            +
             
     | 
| 
       69 
93 
     | 
    
         
             
                    # @!method bad_intersection_check?(node, predicates)
         
     | 
| 
       70 
94 
     | 
    
         
             
                    def_node_matcher :bad_intersection_check?, <<~PATTERN
         
     | 
| 
       71 
     | 
    
         
            -
                      (call
         
     | 
| 
      
 95 
     | 
    
         
            +
                      $(call
         
     | 
| 
       72 
96 
     | 
    
         
             
                        {
         
     | 
| 
       73 
97 
     | 
    
         
             
                          (begin (send $_ :& $_))
         
     | 
| 
       74 
     | 
    
         
            -
                          (call  
     | 
| 
      
 98 
     | 
    
         
            +
                          (call $!nil? :intersection $_)
         
     | 
| 
       75 
99 
     | 
    
         
             
                        }
         
     | 
| 
       76 
100 
     | 
    
         
             
                        $%1
         
     | 
| 
       77 
101 
     | 
    
         
             
                      )
         
     | 
| 
       78 
102 
     | 
    
         
             
                    PATTERN
         
     | 
| 
       79 
103 
     | 
    
         | 
| 
       80 
     | 
    
         
            -
                     
     | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
     | 
    
         
            -
             
     | 
| 
       83 
     | 
    
         
            -
             
     | 
| 
      
 104 
     | 
    
         
            +
                    # @!method intersection_size_check?(node, predicates)
         
     | 
| 
      
 105 
     | 
    
         
            +
                    def_node_matcher :intersection_size_check?, <<~PATTERN
         
     | 
| 
      
 106 
     | 
    
         
            +
                      (call
         
     | 
| 
      
 107 
     | 
    
         
            +
                        $(call
         
     | 
| 
      
 108 
     | 
    
         
            +
                          {
         
     | 
| 
      
 109 
     | 
    
         
            +
                            (begin (send $_ :& $_))
         
     | 
| 
      
 110 
     | 
    
         
            +
                            (call $!nil? :intersection $_)
         
     | 
| 
      
 111 
     | 
    
         
            +
                          }
         
     | 
| 
      
 112 
     | 
    
         
            +
                          %ARRAY_SIZE_METHODS
         
     | 
| 
      
 113 
     | 
    
         
            +
                        )
         
     | 
| 
      
 114 
     | 
    
         
            +
                        {$:> (int 0) | $:positive? | $:!= (int 0) | $:== (int 0) | $:zero?}
         
     | 
| 
      
 115 
     | 
    
         
            +
                      )
         
     | 
| 
      
 116 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                    # @!method any_none_block_intersection(node)
         
     | 
| 
      
 119 
     | 
    
         
            +
                    def_node_matcher :any_none_block_intersection, <<~PATTERN
         
     | 
| 
      
 120 
     | 
    
         
            +
                      {
         
     | 
| 
      
 121 
     | 
    
         
            +
                        (block
         
     | 
| 
      
 122 
     | 
    
         
            +
                          (call $_receiver ${:any? :none?})
         
     | 
| 
      
 123 
     | 
    
         
            +
                          (args (arg _key))
         
     | 
| 
      
 124 
     | 
    
         
            +
                          (send $_argument :member? (lvar _key))
         
     | 
| 
      
 125 
     | 
    
         
            +
                        )
         
     | 
| 
      
 126 
     | 
    
         
            +
                        (numblock
         
     | 
| 
      
 127 
     | 
    
         
            +
                          (call $_receiver ${:any? :none?}) 1
         
     | 
| 
      
 128 
     | 
    
         
            +
                          (send $_argument :member? (lvar :_1))
         
     | 
| 
      
 129 
     | 
    
         
            +
                        )
         
     | 
| 
      
 130 
     | 
    
         
            +
                        (itblock
         
     | 
| 
      
 131 
     | 
    
         
            +
                          (call $_receiver ${:any? :none?}) :it
         
     | 
| 
      
 132 
     | 
    
         
            +
                          (send $_argument :member? (lvar :it))
         
     | 
| 
      
 133 
     | 
    
         
            +
                        )
         
     | 
| 
      
 134 
     | 
    
         
            +
                      }
         
     | 
| 
      
 135 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                    MSG = 'Use `%<replacement>s` instead of `%<existing>s`.'
         
     | 
| 
      
 138 
     | 
    
         
            +
                    STRAIGHT_METHODS = %i[present? any? > positive? !=].freeze
         
     | 
| 
      
 139 
     | 
    
         
            +
                    NEGATED_METHODS = %i[blank? empty? none? == zero?].freeze
         
     | 
| 
       84 
140 
     | 
    
         
             
                    RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
         
     | 
| 
       85 
141 
     | 
    
         | 
| 
       86 
142 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
       87 
143 
     | 
    
         
             
                      return if node.block_literal?
         
     | 
| 
       88 
     | 
    
         
            -
                      return unless (receiver, argument, method_name = bad_intersection?(node))
         
     | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
       90 
     | 
    
         
            -
                      dot = node.loc.dot.source
         
     | 
| 
       91 
     | 
    
         
            -
                      message = message(receiver.source, argument.source, method_name, dot, node.source)
         
     | 
| 
      
 144 
     | 
    
         
            +
                      return unless (dot_node, receiver, argument, method_name = bad_intersection?(node))
         
     | 
| 
       92 
145 
     | 
    
         | 
| 
       93 
     | 
    
         
            -
                       
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
      
 146 
     | 
    
         
            +
                      dot = dot_node.loc.dot.source
         
     | 
| 
      
 147 
     | 
    
         
            +
                      bang = straight?(method_name) ? '' : '!'
         
     | 
| 
      
 148 
     | 
    
         
            +
                      replacement = "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})"
         
     | 
| 
       95 
149 
     | 
    
         | 
| 
       96 
     | 
    
         
            -
             
     | 
| 
       97 
     | 
    
         
            -
                      end
         
     | 
| 
      
 150 
     | 
    
         
            +
                      register_offense(node, replacement)
         
     | 
| 
       98 
151 
     | 
    
         
             
                    end
         
     | 
| 
       99 
152 
     | 
    
         
             
                    alias on_csend on_send
         
     | 
| 
       100 
153 
     | 
    
         | 
| 
      
 154 
     | 
    
         
            +
                    def on_block(node)
         
     | 
| 
      
 155 
     | 
    
         
            +
                      return unless (receiver, method_name, argument = any_none_block_intersection(node))
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
                      dot = node.send_node.loc.dot.source
         
     | 
| 
      
 158 
     | 
    
         
            +
                      bang = method_name == :any? ? '' : '!'
         
     | 
| 
      
 159 
     | 
    
         
            +
                      replacement = "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})"
         
     | 
| 
      
 160 
     | 
    
         
            +
             
     | 
| 
      
 161 
     | 
    
         
            +
                      register_offense(node, replacement)
         
     | 
| 
      
 162 
     | 
    
         
            +
                    end
         
     | 
| 
      
 163 
     | 
    
         
            +
                    alias on_numblock on_block
         
     | 
| 
      
 164 
     | 
    
         
            +
                    alias on_itblock on_block
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
       101 
166 
     | 
    
         
             
                    private
         
     | 
| 
       102 
167 
     | 
    
         | 
| 
       103 
168 
     | 
    
         
             
                    def bad_intersection?(node)
         
     | 
| 
       104 
     | 
    
         
            -
                       
     | 
| 
       105 
     | 
    
         
            -
             
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
       107 
     | 
    
         
            -
                                     PREDICATES
         
     | 
| 
       108 
     | 
    
         
            -
                                   end
         
     | 
| 
      
 169 
     | 
    
         
            +
                      bad_intersection_check?(node, bad_intersection_predicates) ||
         
     | 
| 
      
 170 
     | 
    
         
            +
                        intersection_size_check?(node)
         
     | 
| 
      
 171 
     | 
    
         
            +
                    end
         
     | 
| 
       109 
172 
     | 
    
         | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
      
 173 
     | 
    
         
            +
                    def bad_intersection_predicates
         
     | 
| 
      
 174 
     | 
    
         
            +
                      if active_support_extensions_enabled?
         
     | 
| 
      
 175 
     | 
    
         
            +
                        ACTIVE_SUPPORT_PREDICATES
         
     | 
| 
      
 176 
     | 
    
         
            +
                      else
         
     | 
| 
      
 177 
     | 
    
         
            +
                        PREDICATES
         
     | 
| 
      
 178 
     | 
    
         
            +
                      end
         
     | 
| 
       111 
179 
     | 
    
         
             
                    end
         
     | 
| 
       112 
180 
     | 
    
         | 
| 
       113 
181 
     | 
    
         
             
                    def straight?(method_name)
         
     | 
| 
       114 
182 
     | 
    
         
             
                      STRAIGHT_METHODS.include?(method_name.to_sym)
         
     | 
| 
       115 
183 
     | 
    
         
             
                    end
         
     | 
| 
       116 
184 
     | 
    
         | 
| 
       117 
     | 
    
         
            -
                    def  
     | 
| 
       118 
     | 
    
         
            -
                       
     | 
| 
       119 
     | 
    
         
            -
             
     | 
| 
       120 
     | 
    
         
            -
             
     | 
| 
       121 
     | 
    
         
            -
                         
     | 
| 
       122 
     | 
    
         
            -
             
     | 
| 
       123 
     | 
    
         
            -
                        argument: argument,
         
     | 
| 
       124 
     | 
    
         
            -
                        dot: dot,
         
     | 
| 
       125 
     | 
    
         
            -
                        existing: existing
         
     | 
| 
       126 
     | 
    
         
            -
                      )
         
     | 
| 
      
 185 
     | 
    
         
            +
                    def register_offense(node, replacement)
         
     | 
| 
      
 186 
     | 
    
         
            +
                      message = format(MSG, replacement: replacement, existing: node.source)
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                      add_offense(node, message: message) do |corrector|
         
     | 
| 
      
 189 
     | 
    
         
            +
                        corrector.replace(node, replacement)
         
     | 
| 
      
 190 
     | 
    
         
            +
                      end
         
     | 
| 
       127 
191 
     | 
    
         
             
                    end
         
     | 
| 
       128 
192 
     | 
    
         
             
                  end
         
     | 
| 
       129 
193 
     | 
    
         
             
                end
         
     | 
| 
         @@ -0,0 +1,47 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Style
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # Use `include?(element)` instead of `intersect?([element])`.
         
     | 
| 
      
 7 
     | 
    
         
            +
                  #
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # @safety
         
     | 
| 
      
 9 
     | 
    
         
            +
                  #   The receiver might not be an array.
         
     | 
| 
      
 10 
     | 
    
         
            +
                  #
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 12 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #   array.intersect?([element])
         
     | 
| 
      
 14 
     | 
    
         
            +
                  #
         
     | 
| 
      
 15 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 16 
     | 
    
         
            +
                  #   array.include?(element)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  class ArrayIntersectWithSingleElement < Base
         
     | 
| 
      
 18 
     | 
    
         
            +
                    extend AutoCorrector
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    MSG = 'Use `include?(element)` instead of `intersect?([element])`.'
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    RESTRICT_ON_SEND = %i[intersect?].freeze
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                    # @!method single_element(node)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    def_node_matcher :single_element, <<~PATTERN
         
     | 
| 
      
 26 
     | 
    
         
            +
                      (send _ _ $(array $_))
         
     | 
| 
      
 27 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    def on_send(node)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      array, element = single_element(node)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      return unless array
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                      add_offense(
         
     | 
| 
      
 34 
     | 
    
         
            +
                        node.source_range.with(begin_pos: node.loc.selector.begin_pos)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      ) do |corrector|
         
     | 
| 
      
 36 
     | 
    
         
            +
                        corrector.replace(node.loc.selector, 'include?')
         
     | 
| 
      
 37 
     | 
    
         
            +
                        corrector.replace(
         
     | 
| 
      
 38 
     | 
    
         
            +
                          array,
         
     | 
| 
      
 39 
     | 
    
         
            +
                          array.percent_literal? ? element.value.inspect : element.source
         
     | 
| 
      
 40 
     | 
    
         
            +
                        )
         
     | 
| 
      
 41 
     | 
    
         
            +
                      end
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
                    alias on_csend on_send
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -70,18 +70,25 @@ module RuboCop 
     | 
|
| 
       70 
70 
     | 
    
         
             
                        (send _ :& _))
         
     | 
| 
       71 
71 
     | 
    
         
             
                    PATTERN
         
     | 
| 
       72 
72 
     | 
    
         | 
| 
      
 73 
     | 
    
         
            +
                    # rubocop:disable Metrics/AbcSize
         
     | 
| 
       73 
74 
     | 
    
         
             
                    def on_send(node)
         
     | 
| 
       74 
75 
     | 
    
         
             
                      return unless node.receiver&.begin_type?
         
     | 
| 
       75 
76 
     | 
    
         
             
                      return unless (preferred_method = preferred_method(node))
         
     | 
| 
       76 
77 
     | 
    
         | 
| 
       77 
78 
     | 
    
         
             
                      bit_operation = node.receiver.children.first
         
     | 
| 
       78 
79 
     | 
    
         
             
                      lhs, _operator, rhs = *bit_operation
         
     | 
| 
       79 
     | 
    
         
            -
             
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                      preferred = if preferred_method == 'allbits?' && lhs.source == node.first_argument.source
         
     | 
| 
      
 82 
     | 
    
         
            +
                                    "#{rhs.source}.allbits?(#{lhs.source})"
         
     | 
| 
      
 83 
     | 
    
         
            +
                                  else
         
     | 
| 
      
 84 
     | 
    
         
            +
                                    "#{lhs.source}.#{preferred_method}(#{rhs.source})"
         
     | 
| 
      
 85 
     | 
    
         
            +
                                  end
         
     | 
| 
       80 
86 
     | 
    
         | 
| 
       81 
87 
     | 
    
         
             
                      add_offense(node, message: format(MSG, preferred: preferred)) do |corrector|
         
     | 
| 
       82 
88 
     | 
    
         
             
                        corrector.replace(node, preferred)
         
     | 
| 
       83 
89 
     | 
    
         
             
                      end
         
     | 
| 
       84 
90 
     | 
    
         
             
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
                    # rubocop:enable Metrics/AbcSize
         
     | 
| 
       85 
92 
     | 
    
         | 
| 
       86 
93 
     | 
    
         
             
                    private
         
     | 
| 
       87 
94 
     | 
    
         | 
| 
         @@ -0,0 +1,167 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # frozen_string_literal: true
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module RuboCop
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Cop
         
     | 
| 
      
 5 
     | 
    
         
            +
                module Style
         
     | 
| 
      
 6 
     | 
    
         
            +
                  # Prefer `Enumerable` predicate methods over expressions with `count`.
         
     | 
| 
      
 7 
     | 
    
         
            +
                  #
         
     | 
| 
      
 8 
     | 
    
         
            +
                  # The cop checks calls to `count` without arguments, or with a
         
     | 
| 
      
 9 
     | 
    
         
            +
                  # block. It doesn't register offenses for `count` with a positional
         
     | 
| 
      
 10 
     | 
    
         
            +
                  # argument because its behavior differs from predicate methods (`count`
         
     | 
| 
      
 11 
     | 
    
         
            +
                  # matches the argument using `==`, while `any?`, `none?` and `one?` use
         
     | 
| 
      
 12 
     | 
    
         
            +
                  # `===`).
         
     | 
| 
      
 13 
     | 
    
         
            +
                  #
         
     | 
| 
      
 14 
     | 
    
         
            +
                  # NOTE: This cop doesn't check `length` and `size` methods because they
         
     | 
| 
      
 15 
     | 
    
         
            +
                  # would yield false positives. For example, `String` implements `length`
         
     | 
| 
      
 16 
     | 
    
         
            +
                  # and `size`, but it doesn't include `Enumerable`.
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #
         
     | 
| 
      
 18 
     | 
    
         
            +
                  # @safety
         
     | 
| 
      
 19 
     | 
    
         
            +
                  #   The cop is unsafe because receiver might not include `Enumerable`, or
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #   it has nonstandard implementation of `count` or any replacement
         
     | 
| 
      
 21 
     | 
    
         
            +
                  #   methods.
         
     | 
| 
      
 22 
     | 
    
         
            +
                  #
         
     | 
| 
      
 23 
     | 
    
         
            +
                  #   It's also unsafe because for collections with falsey values, expressions
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #   with `count` without a block return a different result than methods `any?`,
         
     | 
| 
      
 25 
     | 
    
         
            +
                  #   `none?` and `one?`:
         
     | 
| 
      
 26 
     | 
    
         
            +
                  #
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #   [source,ruby]
         
     | 
| 
      
 28 
     | 
    
         
            +
                  #   ----
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #   [nil, false].count.positive?
         
     | 
| 
      
 30 
     | 
    
         
            +
                  #   [nil].count == 1
         
     | 
| 
      
 31 
     | 
    
         
            +
                  #   # => true
         
     | 
| 
      
 32 
     | 
    
         
            +
                  #
         
     | 
| 
      
 33 
     | 
    
         
            +
                  #   [nil, false].any?
         
     | 
| 
      
 34 
     | 
    
         
            +
                  #   [nil].one?
         
     | 
| 
      
 35 
     | 
    
         
            +
                  #   # => false
         
     | 
| 
      
 36 
     | 
    
         
            +
                  #
         
     | 
| 
      
 37 
     | 
    
         
            +
                  #   [nil].count == 0
         
     | 
| 
      
 38 
     | 
    
         
            +
                  #   # => false
         
     | 
| 
      
 39 
     | 
    
         
            +
                  #
         
     | 
| 
      
 40 
     | 
    
         
            +
                  #   [nil].none?
         
     | 
| 
      
 41 
     | 
    
         
            +
                  #   # => true
         
     | 
| 
      
 42 
     | 
    
         
            +
                  #   ----
         
     | 
| 
      
 43 
     | 
    
         
            +
                  #
         
     | 
| 
      
 44 
     | 
    
         
            +
                  #   Autocorrection is unsafe when replacement methods don't iterate over
         
     | 
| 
      
 45 
     | 
    
         
            +
                  #   every element in collection and the given block runs side effects:
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #
         
     | 
| 
      
 47 
     | 
    
         
            +
                  #   [source,ruby]
         
     | 
| 
      
 48 
     | 
    
         
            +
                  #   ----
         
     | 
| 
      
 49 
     | 
    
         
            +
                  #   x.count(&:method_with_side_effects).positive?
         
     | 
| 
      
 50 
     | 
    
         
            +
                  #   # calls `method_with_side_effects` on every element
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #
         
     | 
| 
      
 52 
     | 
    
         
            +
                  #   x.any?(&:method_with_side_effects)
         
     | 
| 
      
 53 
     | 
    
         
            +
                  #   # calls `method_with_side_effects` until first element returns a truthy value
         
     | 
| 
      
 54 
     | 
    
         
            +
                  #   ----
         
     | 
| 
      
 55 
     | 
    
         
            +
                  #
         
     | 
| 
      
 56 
     | 
    
         
            +
                  # @example
         
     | 
| 
      
 57 
     | 
    
         
            +
                  #
         
     | 
| 
      
 58 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #   x.count.positive?
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #   x.count > 0
         
     | 
| 
      
 61 
     | 
    
         
            +
                  #   x.count != 0
         
     | 
| 
      
 62 
     | 
    
         
            +
                  #
         
     | 
| 
      
 63 
     | 
    
         
            +
                  #   x.count(&:foo?).positive?
         
     | 
| 
      
 64 
     | 
    
         
            +
                  #   x.count { |item| item.foo? }.positive?
         
     | 
| 
      
 65 
     | 
    
         
            +
                  #
         
     | 
| 
      
 66 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 67 
     | 
    
         
            +
                  #   x.any?
         
     | 
| 
      
 68 
     | 
    
         
            +
                  #
         
     | 
| 
      
 69 
     | 
    
         
            +
                  #   x.any?(&:foo?)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #   x.any? { |item| item.foo? }
         
     | 
| 
      
 71 
     | 
    
         
            +
                  #
         
     | 
| 
      
 72 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 73 
     | 
    
         
            +
                  #   x.count.zero?
         
     | 
| 
      
 74 
     | 
    
         
            +
                  #   x.count == 0
         
     | 
| 
      
 75 
     | 
    
         
            +
                  #
         
     | 
| 
      
 76 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 77 
     | 
    
         
            +
                  #   x.none?
         
     | 
| 
      
 78 
     | 
    
         
            +
                  #
         
     | 
| 
      
 79 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 80 
     | 
    
         
            +
                  #   x.count == 1
         
     | 
| 
      
 81 
     | 
    
         
            +
                  #   x.one?
         
     | 
| 
      
 82 
     | 
    
         
            +
                  #
         
     | 
| 
      
 83 
     | 
    
         
            +
                  # @example AllCops:ActiveSupportExtensionsEnabled: false (default)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  #
         
     | 
| 
      
 85 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 86 
     | 
    
         
            +
                  #   x.count > 1
         
     | 
| 
      
 87 
     | 
    
         
            +
                  #
         
     | 
| 
      
 88 
     | 
    
         
            +
                  # @example AllCops:ActiveSupportExtensionsEnabled: true
         
     | 
| 
      
 89 
     | 
    
         
            +
                  #
         
     | 
| 
      
 90 
     | 
    
         
            +
                  #   # bad
         
     | 
| 
      
 91 
     | 
    
         
            +
                  #   x.count > 1
         
     | 
| 
      
 92 
     | 
    
         
            +
                  #
         
     | 
| 
      
 93 
     | 
    
         
            +
                  #   # good
         
     | 
| 
      
 94 
     | 
    
         
            +
                  #   x.many?
         
     | 
| 
      
 95 
     | 
    
         
            +
                  #
         
     | 
| 
      
 96 
     | 
    
         
            +
                  class CollectionQuerying < Base
         
     | 
| 
      
 97 
     | 
    
         
            +
                    include RangeHelp
         
     | 
| 
      
 98 
     | 
    
         
            +
                    extend AutoCorrector
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                    MSG = 'Use `%<prefer>s` instead.'
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    RESTRICT_ON_SEND = %i[positive? > != zero? ==].freeze
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                    REPLACEMENTS = {
         
     | 
| 
      
 105 
     | 
    
         
            +
                      [:positive?, nil] => :any?,
         
     | 
| 
      
 106 
     | 
    
         
            +
                      [:>, 0] => :any?,
         
     | 
| 
      
 107 
     | 
    
         
            +
                      [:!=, 0] => :any?,
         
     | 
| 
      
 108 
     | 
    
         
            +
                      [:zero?, nil] => :none?,
         
     | 
| 
      
 109 
     | 
    
         
            +
                      [:==, 0] => :none?,
         
     | 
| 
      
 110 
     | 
    
         
            +
                      [:==, 1] => :one?,
         
     | 
| 
      
 111 
     | 
    
         
            +
                      [:>, 1] => :many?
         
     | 
| 
      
 112 
     | 
    
         
            +
                    }.freeze
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                    # @!method count_predicate(node)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    def_node_matcher :count_predicate, <<~PATTERN
         
     | 
| 
      
 116 
     | 
    
         
            +
                      (send
         
     | 
| 
      
 117 
     | 
    
         
            +
                        {
         
     | 
| 
      
 118 
     | 
    
         
            +
                          (any_block $(call !nil? :count) _ _)
         
     | 
| 
      
 119 
     | 
    
         
            +
                          $(call !nil? :count (block-pass _)?)
         
     | 
| 
      
 120 
     | 
    
         
            +
                        }
         
     | 
| 
      
 121 
     | 
    
         
            +
                        {
         
     | 
| 
      
 122 
     | 
    
         
            +
                          :positive? |
         
     | 
| 
      
 123 
     | 
    
         
            +
                          :> (int 0) |
         
     | 
| 
      
 124 
     | 
    
         
            +
                          :!= (int 0) |
         
     | 
| 
      
 125 
     | 
    
         
            +
                          :zero? |
         
     | 
| 
      
 126 
     | 
    
         
            +
                          :== (int 0) |
         
     | 
| 
      
 127 
     | 
    
         
            +
                          :== (int 1) |
         
     | 
| 
      
 128 
     | 
    
         
            +
                          :> (int 1)
         
     | 
| 
      
 129 
     | 
    
         
            +
                        })
         
     | 
| 
      
 130 
     | 
    
         
            +
                    PATTERN
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
                    def on_send(node)
         
     | 
| 
      
 133 
     | 
    
         
            +
                      return unless (count_node = count_predicate(node))
         
     | 
| 
      
 134 
     | 
    
         
            +
             
     | 
| 
      
 135 
     | 
    
         
            +
                      replacement_method = replacement_method(node)
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                      return unless replacement_supported?(replacement_method)
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                      offense_range = count_node.loc.selector.join(node.source_range.end)
         
     | 
| 
      
 140 
     | 
    
         
            +
                      add_offense(offense_range,
         
     | 
| 
      
 141 
     | 
    
         
            +
                                  message: format(MSG, prefer: replacement_method)) do |corrector|
         
     | 
| 
      
 142 
     | 
    
         
            +
                        corrector.replace(count_node.loc.selector, replacement_method)
         
     | 
| 
      
 143 
     | 
    
         
            +
                        corrector.remove(removal_range(node))
         
     | 
| 
      
 144 
     | 
    
         
            +
                      end
         
     | 
| 
      
 145 
     | 
    
         
            +
                    end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                    private
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
      
 149 
     | 
    
         
            +
                    def replacement_method(node)
         
     | 
| 
      
 150 
     | 
    
         
            +
                      REPLACEMENTS.fetch([node.method_name, node.first_argument&.value])
         
     | 
| 
      
 151 
     | 
    
         
            +
                    end
         
     | 
| 
      
 152 
     | 
    
         
            +
             
     | 
| 
      
 153 
     | 
    
         
            +
                    def replacement_supported?(method_name)
         
     | 
| 
      
 154 
     | 
    
         
            +
                      return true if active_support_extensions_enabled?
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                      method_name != :many?
         
     | 
| 
      
 157 
     | 
    
         
            +
                    end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                    def removal_range(node)
         
     | 
| 
      
 160 
     | 
    
         
            +
                      range = (node.loc.dot || node.loc.selector).join(node.source_range.end)
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                      range_with_surrounding_space(range, side: :left)
         
     | 
| 
      
 163 
     | 
    
         
            +
                    end
         
     | 
| 
      
 164 
     | 
    
         
            +
                  end
         
     | 
| 
      
 165 
     | 
    
         
            +
                end
         
     | 
| 
      
 166 
     | 
    
         
            +
              end
         
     | 
| 
      
 167 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -111,7 +111,7 @@ module RuboCop 
     | 
|
| 
       111 
111 
     | 
    
         
             
                    end
         
     | 
| 
       112 
112 
     | 
    
         
             
                  end
         
     | 
| 
       113 
113 
     | 
    
         | 
| 
       114 
     | 
    
         
            -
                  #  
     | 
| 
      
 114 
     | 
    
         
            +
                  # Checks for `if` and `case` statements where each branch is used for
         
     | 
| 
       115 
115 
     | 
    
         
             
                  # both the assignment and comparison of the same variable
         
     | 
| 
       116 
116 
     | 
    
         
             
                  # when using the return of the condition can be used instead.
         
     | 
| 
       117 
117 
     | 
    
         
             
                  #
         
     | 
| 
         @@ -444,14 +444,16 @@ module RuboCop 
     | 
|
| 
       444 
444 
     | 
    
         
             
                        next if child.parent.dstr_type?
         
     | 
| 
       445 
445 
     | 
    
         | 
| 
       446 
446 
     | 
    
         
             
                        white_space = white_space_range(child, column)
         
     | 
| 
       447 
     | 
    
         
            -
                        corrector.remove(white_space) if white_space 
     | 
| 
      
 447 
     | 
    
         
            +
                        corrector.remove(white_space) if white_space
         
     | 
| 
       448 
448 
     | 
    
         
             
                      end
         
     | 
| 
       449 
449 
     | 
    
         | 
| 
       450 
450 
     | 
    
         
             
                      if condition.loc.else && !same_line?(condition.else_branch, condition)
         
     | 
| 
       451 
451 
     | 
    
         
             
                        corrector.remove_preceding(condition.loc.else, condition.loc.else.column - column)
         
     | 
| 
       452 
452 
     | 
    
         
             
                      end
         
     | 
| 
       453 
453 
     | 
    
         | 
| 
       454 
     | 
    
         
            -
                      return unless condition.loc.end && !same_line?( 
     | 
| 
      
 454 
     | 
    
         
            +
                      return unless condition.loc.end && !same_line?(
         
     | 
| 
      
 455 
     | 
    
         
            +
                        condition.branches.last.parent.else_branch, condition.loc.end
         
     | 
| 
      
 456 
     | 
    
         
            +
                      )
         
     | 
| 
       455 
457 
     | 
    
         | 
| 
       456 
458 
     | 
    
         
             
                      corrector.remove_preceding(condition.loc.end, condition.loc.end.column - column)
         
     | 
| 
       457 
459 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -463,9 +465,13 @@ module RuboCop 
     | 
|
| 
       463 
465 
     | 
    
         | 
| 
       464 
466 
     | 
    
         
             
                    def white_space_range(node, column)
         
     | 
| 
       465 
467 
     | 
    
         
             
                      expression = node.source_range
         
     | 
| 
       466 
     | 
    
         
            -
                       
     | 
| 
      
 468 
     | 
    
         
            +
                      end_pos = expression.begin_pos
         
     | 
| 
      
 469 
     | 
    
         
            +
                      begin_pos = end_pos - (expression.column - column - 2)
         
     | 
| 
       467 
470 
     | 
    
         | 
| 
       468 
     | 
    
         
            -
                       
     | 
| 
      
 471 
     | 
    
         
            +
                      return nil if begin_pos > end_pos
         
     | 
| 
      
 472 
     | 
    
         
            +
             
     | 
| 
      
 473 
     | 
    
         
            +
                      white_space = Parser::Source::Range.new(expression.source_buffer, begin_pos, end_pos)
         
     | 
| 
      
 474 
     | 
    
         
            +
                      white_space if white_space.source.strip.empty?
         
     | 
| 
       469 
475 
     | 
    
         
             
                    end
         
     | 
| 
       470 
476 
     | 
    
         | 
| 
       471 
477 
     | 
    
         
             
                    def assignment(node)
         
     |