rubocop 1.68.0 → 1.69.1
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 +1 -1
- data/config/default.yml +41 -6
- data/lib/rubocop/cop/base.rb +1 -1
- data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
- data/lib/rubocop/cop/generator.rb +6 -0
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -4
- data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +46 -0
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -3
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +3 -4
- data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +3 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +7 -7
- data/lib/rubocop/cop/layout/leading_comment_space.rb +15 -0
- data/lib/rubocop/cop/layout/line_length.rb +118 -4
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -3
- data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
- data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -35
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -2
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +16 -17
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +6 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -0
- data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +10 -12
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +6 -0
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +2 -1
- data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
- data/lib/rubocop/cop/lint/empty_file.rb +0 -2
- data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +14 -6
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -3
- data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
- data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +3 -0
- data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -0
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -5
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +1 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -3
- data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +106 -0
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -2
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +12 -7
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
- data/lib/rubocop/cop/lint/refinement_import_methods.rb +1 -1
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +2 -0
- data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +3 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +51 -2
- data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
- data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
- data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -0
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
- data/lib/rubocop/cop/lint/void.rb +3 -2
- data/lib/rubocop/cop/metrics/class_length.rb +7 -7
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -3
- data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
- data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -9
- data/lib/rubocop/cop/mixin/range_help.rb +0 -1
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
- data/lib/rubocop/cop/naming/accessor_method_name.rb +6 -6
- data/lib/rubocop/cop/naming/constant_name.rb +6 -7
- data/lib/rubocop/cop/naming/file_name.rb +0 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +11 -12
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -11
- data/lib/rubocop/cop/naming/variable_name.rb +3 -4
- data/lib/rubocop/cop/naming/variable_number.rb +2 -3
- data/lib/rubocop/cop/security/compound_hash.rb +1 -0
- data/lib/rubocop/cop/security/yaml_load.rb +3 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +54 -25
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +1 -1
- data/lib/rubocop/cop/style/array_intersect.rb +5 -4
- data/lib/rubocop/cop/style/bitwise_predicate.rb +1 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +10 -2
- data/lib/rubocop/cop/style/case_like_if.rb +8 -11
- data/lib/rubocop/cop/style/commented_keyword.rb +11 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +19 -21
- data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
- data/lib/rubocop/cop/style/dig_chain.rb +89 -0
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -0
- data/lib/rubocop/cop/style/file_null.rb +73 -0
- data/lib/rubocop/cop/style/file_touch.rb +75 -0
- data/lib/rubocop/cop/style/for.rb +0 -1
- data/lib/rubocop/cop/style/global_vars.rb +1 -3
- data/lib/rubocop/cop/style/guard_clause.rb +1 -1
- data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
- data/lib/rubocop/cop/style/hash_except.rb +19 -7
- data/lib/rubocop/cop/style/if_inside_else.rb +0 -1
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -2
- data/lib/rubocop/cop/style/if_with_semicolon.rb +14 -5
- data/lib/rubocop/cop/style/inverse_methods.rb +0 -1
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +2 -2
- data/lib/rubocop/cop/style/lambda_call.rb +3 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +7 -11
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
- data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +4 -5
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +6 -4
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
- data/lib/rubocop/cop/style/not.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +1 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +25 -4
- data/lib/rubocop/cop/style/operator_method_call.rb +5 -6
- data/lib/rubocop/cop/style/or_assignment.rb +3 -6
- data/lib/rubocop/cop/style/parallel_assignment.rb +8 -13
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +3 -1
- data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +36 -21
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +7 -6
- data/lib/rubocop/cop/style/redundant_parentheses.rb +2 -2
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +1 -0
- data/lib/rubocop/cop/style/redundant_return.rb +2 -2
- data/lib/rubocop/cop/style/redundant_self.rb +8 -15
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +7 -5
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +2 -3
- data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
- data/lib/rubocop/cop/style/select_by_regexp.rb +1 -1
- data/lib/rubocop/cop/style/self_assignment.rb +11 -17
- data/lib/rubocop/cop/style/signal_exception.rb +2 -3
- data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +13 -3
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -3
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +13 -12
- data/lib/rubocop/cop/style/swap_values.rb +4 -15
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
- data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
- data/lib/rubocop/cop/variable_force.rb +4 -10
- data/lib/rubocop/cops_documentation_generator.rb +9 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +8 -0
- metadata +23 -14
| @@ -0,0 +1,55 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module RuboCop
         | 
| 4 | 
            +
              module Cop
         | 
| 5 | 
            +
                module Lint
         | 
| 6 | 
            +
                  # Checks for the deprecated use of keyword arguments as a default in `Hash.new`.
         | 
| 7 | 
            +
                  #
         | 
| 8 | 
            +
                  # This usage raises a warning in Ruby 3.3 and results in an error in Ruby 3.4.
         | 
| 9 | 
            +
                  # In Ruby 3.4, keyword arguments will instead be used to change the behavior of a hash.
         | 
| 10 | 
            +
                  # For example, the capacity option can be passed to create a hash with a certain size
         | 
| 11 | 
            +
                  # if you know it in advance, for better performance.
         | 
| 12 | 
            +
                  #
         | 
| 13 | 
            +
                  # NOTE: The following corner case may result in a false negative when upgrading from Ruby 3.3
         | 
| 14 | 
            +
                  # or earlier, but it is intentionally not detected to respect the expected usage in Ruby 3.4.
         | 
| 15 | 
            +
                  #
         | 
| 16 | 
            +
                  # [source,ruby]
         | 
| 17 | 
            +
                  # ----
         | 
| 18 | 
            +
                  # Hash.new(capacity: 42)
         | 
| 19 | 
            +
                  # ----
         | 
| 20 | 
            +
                  #
         | 
| 21 | 
            +
                  # @example
         | 
| 22 | 
            +
                  #
         | 
| 23 | 
            +
                  #   # bad
         | 
| 24 | 
            +
                  #   Hash.new(key: :value)
         | 
| 25 | 
            +
                  #
         | 
| 26 | 
            +
                  #   # good
         | 
| 27 | 
            +
                  #   Hash.new({key: :value})
         | 
| 28 | 
            +
                  #
         | 
| 29 | 
            +
                  class HashNewWithKeywordArgumentsAsDefault < Base
         | 
| 30 | 
            +
                    extend AutoCorrector
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    MSG = 'Use a hash literal instead of keyword arguments.'
         | 
| 33 | 
            +
                    RESTRICT_ON_SEND = %i[new].freeze
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    # @!method hash_new(node)
         | 
| 36 | 
            +
                    def_node_matcher :hash_new, <<~PATTERN
         | 
| 37 | 
            +
                      (send (const {nil? (cbase)} :Hash) :new $[hash !braces?])
         | 
| 38 | 
            +
                    PATTERN
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    def on_send(node)
         | 
| 41 | 
            +
                      return unless (first_argument = hash_new(node))
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                      if first_argument.pairs.one?
         | 
| 44 | 
            +
                        key = first_argument.pairs.first.key
         | 
| 45 | 
            +
                        return if key.respond_to?(:value) && key.value == :capacity
         | 
| 46 | 
            +
                      end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                      add_offense(first_argument) do |corrector|
         | 
| 49 | 
            +
                        corrector.wrap(first_argument, '{', '}')
         | 
| 50 | 
            +
                      end
         | 
| 51 | 
            +
                    end
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end
         | 
| 54 | 
            +
              end
         | 
| 55 | 
            +
            end
         | 
| @@ -24,14 +24,17 @@ module RuboCop | |
| 24 24 | 
             
                    MSG = 'Interpolation in single quoted string detected. ' \
         | 
| 25 25 | 
             
                          'Use double quoted strings if you need interpolation.'
         | 
| 26 26 |  | 
| 27 | 
            +
                    # rubocop:disable Metrics/CyclomaticComplexity
         | 
| 27 28 | 
             
                    def on_str(node)
         | 
| 28 29 | 
             
                      return if node.parent&.regexp_type?
         | 
| 29 30 | 
             
                      return unless /(?<!\\)#\{.*\}/.match?(node.source)
         | 
| 30 31 | 
             
                      return if heredoc?(node)
         | 
| 31 32 | 
             
                      return unless node.loc.begin && node.loc.end
         | 
| 33 | 
            +
                      return unless valid_syntax?(node)
         | 
| 32 34 |  | 
| 33 35 | 
             
                      add_offense(node) { |corrector| autocorrect(corrector, node) }
         | 
| 34 36 | 
             
                    end
         | 
| 37 | 
            +
                    # rubocop:enable Metrics/CyclomaticComplexity
         | 
| 35 38 |  | 
| 36 39 | 
             
                    private
         | 
| 37 40 |  | 
| @@ -49,6 +52,12 @@ module RuboCop | |
| 49 52 | 
             
                    def heredoc?(node)
         | 
| 50 53 | 
             
                      node.loc.is_a?(Parser::Source::Map::Heredoc) || (node.parent && heredoc?(node.parent))
         | 
| 51 54 | 
             
                    end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    def valid_syntax?(node)
         | 
| 57 | 
            +
                      double_quoted_string = node.source.gsub(/\A'|'\z/, '"')
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                      parse(double_quoted_string).valid_syntax?
         | 
| 60 | 
            +
                    end
         | 
| 52 61 | 
             
                  end
         | 
| 53 62 | 
             
                end
         | 
| 54 63 | 
             
              end
         | 
| @@ -26,6 +26,9 @@ module RuboCop | |
| 26 26 | 
             
                  #
         | 
| 27 27 | 
             
                  class ItWithoutArgumentsInBlock < Base
         | 
| 28 28 | 
             
                    include NodePattern::Macros
         | 
| 29 | 
            +
                    extend TargetRubyVersion
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    maximum_target_ruby_version 3.3
         | 
| 29 32 |  | 
| 30 33 | 
             
                    MSG = '`it` calls without arguments will refer to the first block param in Ruby 3.4; ' \
         | 
| 31 34 | 
             
                          'use `it()` or `self.it`.'
         | 
| @@ -40,7 +40,7 @@ module RuboCop | |
| 40 40 | 
             
                      traverse_node(node.condition) do |asgn_node|
         | 
| 41 41 | 
             
                        next unless asgn_node.loc.operator
         | 
| 42 42 |  | 
| 43 | 
            -
                        rhs = asgn_node. | 
| 43 | 
            +
                        rhs = asgn_node.rhs
         | 
| 44 44 | 
             
                        next if !all_literals?(rhs) || parallel_assignment_with_splat_operator?(rhs)
         | 
| 45 45 |  | 
| 46 46 | 
             
                        range = offense_range(asgn_node, rhs)
         | 
| @@ -36,12 +36,9 @@ module RuboCop | |
| 36 36 |  | 
| 37 37 | 
             
                    def on_irange(node)
         | 
| 38 38 | 
             
                      return unless node.children.compact.all?(&:str_type?)
         | 
| 39 | 
            +
                      return if node.begin.nil? || node.end.nil?
         | 
| 39 40 |  | 
| 40 | 
            -
                       | 
| 41 | 
            -
             | 
| 42 | 
            -
                      return if range_start.nil? || range_end.nil?
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                      add_offense(node) if unsafe_range?(range_start.value, range_end.value)
         | 
| 41 | 
            +
                      add_offense(node) if unsafe_range?(node.begin.value, node.end.value)
         | 
| 45 42 | 
             
                    end
         | 
| 46 43 | 
             
                    alias on_erange on_irange
         | 
| 47 44 |  | 
| @@ -95,7 +95,7 @@ module RuboCop | |
| 95 95 | 
             
                    MSG = 'Method definitions must not be nested. Use `lambda` instead.'
         | 
| 96 96 |  | 
| 97 97 | 
             
                    def on_def(node)
         | 
| 98 | 
            -
                      subject, = *node
         | 
| 98 | 
            +
                      subject, = *node # rubocop:disable InternalAffairs/NodeDestructuring
         | 
| 99 99 | 
             
                      return if node.defs_type? && subject.variable?
         | 
| 100 100 |  | 
| 101 101 | 
             
                      def_ancestor = node.each_ancestor(:def, :defs).first
         | 
| @@ -95,7 +95,7 @@ module RuboCop | |
| 95 95 | 
             
                    end
         | 
| 96 96 |  | 
| 97 97 | 
             
                    def allowable_use_with_if?(if_node)
         | 
| 98 | 
            -
                      if_node.condition. | 
| 98 | 
            +
                      if_node.condition.operator_keyword? || if_node.else_branch
         | 
| 99 99 | 
             
                    end
         | 
| 100 100 |  | 
| 101 101 | 
             
                    def register_offense(node, exist_node)
         | 
| @@ -59,11 +59,13 @@ module RuboCop | |
| 59 59 | 
             
                  #
         | 
| 60 60 | 
             
                  class NonDeterministicRequireOrder < Base
         | 
| 61 61 | 
             
                    extend AutoCorrector
         | 
| 62 | 
            +
                    extend TargetRubyVersion
         | 
| 62 63 |  | 
| 63 64 | 
             
                    MSG = 'Sort files before requiring them.'
         | 
| 64 65 |  | 
| 66 | 
            +
                    maximum_target_ruby_version 2.7
         | 
| 67 | 
            +
             | 
| 65 68 | 
             
                    def on_block(node)
         | 
| 66 | 
            -
                      return if target_ruby_version >= 3.0
         | 
| 67 69 | 
             
                      return unless node.body
         | 
| 68 70 | 
             
                      return unless unsorted_dir_loop?(node.send_node)
         | 
| 69 71 |  | 
| @@ -75,7 +77,6 @@ module RuboCop | |
| 75 77 | 
             
                    end
         | 
| 76 78 |  | 
| 77 79 | 
             
                    def on_numblock(node)
         | 
| 78 | 
            -
                      return if target_ruby_version >= 3.0
         | 
| 79 80 | 
             
                      return unless node.body
         | 
| 80 81 | 
             
                      return unless unsorted_dir_loop?(node.send_node)
         | 
| 81 82 |  | 
| @@ -87,7 +88,6 @@ module RuboCop | |
| 87 88 | 
             
                    end
         | 
| 88 89 |  | 
| 89 90 | 
             
                    def on_block_pass(node)
         | 
| 90 | 
            -
                      return if target_ruby_version >= 3.0
         | 
| 91 91 | 
             
                      return unless method_require?(node)
         | 
| 92 92 | 
             
                      return unless unsorted_dir_pass?(node.parent)
         | 
| 93 93 |  | 
| @@ -33,8 +33,7 @@ module RuboCop | |
| 33 33 | 
             
                    NUMBERED_PARAMETER_RANGE = (1..9).freeze
         | 
| 34 34 |  | 
| 35 35 | 
             
                    def on_lvasgn(node)
         | 
| 36 | 
            -
                       | 
| 37 | 
            -
                      return unless /\A_(\d+)\z/ =~ lhs
         | 
| 36 | 
            +
                      return unless /\A_(\d+)\z/ =~ node.name
         | 
| 38 37 |  | 
| 39 38 | 
             
                      number = Regexp.last_match(1).to_i
         | 
| 40 39 | 
             
                      template = NUMBERED_PARAMETER_RANGE.include?(number) ? NUM_PARAM_MSG : LVAR_MSG
         | 
| @@ -0,0 +1,106 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module RuboCop
         | 
| 4 | 
            +
              module Cop
         | 
| 5 | 
            +
                module Lint
         | 
| 6 | 
            +
                  # Certain numeric operations have a constant result, usually 0 or 1.
         | 
| 7 | 
            +
                  # Subtracting a number from itself or multiplying it by 0 will always return 0.
         | 
| 8 | 
            +
                  # Additionally, a variable modulo 0 or itself will always return 0.
         | 
| 9 | 
            +
                  # Dividing a number by itself or raising it to the power of 0 will always return 1.
         | 
| 10 | 
            +
                  # As such, they can be replaced with that result.
         | 
| 11 | 
            +
                  # These are probably leftover from debugging, or are mistakes.
         | 
| 12 | 
            +
                  # Other numeric operations that are similarly leftover from debugging or mistakes
         | 
| 13 | 
            +
                  # are handled by Lint/UselessNumericOperation.
         | 
| 14 | 
            +
                  #
         | 
| 15 | 
            +
                  # @example
         | 
| 16 | 
            +
                  #
         | 
| 17 | 
            +
                  #   # bad
         | 
| 18 | 
            +
                  #   x - x
         | 
| 19 | 
            +
                  #   x * 0
         | 
| 20 | 
            +
                  #   x % 1
         | 
| 21 | 
            +
                  #   x % x
         | 
| 22 | 
            +
                  #
         | 
| 23 | 
            +
                  #   # good
         | 
| 24 | 
            +
                  #   0
         | 
| 25 | 
            +
                  #
         | 
| 26 | 
            +
                  #   # bad
         | 
| 27 | 
            +
                  #   x -= x
         | 
| 28 | 
            +
                  #   x *= 0
         | 
| 29 | 
            +
                  #   x %= 1
         | 
| 30 | 
            +
                  #   x %= x
         | 
| 31 | 
            +
                  #
         | 
| 32 | 
            +
                  #   # good
         | 
| 33 | 
            +
                  #   x = 0
         | 
| 34 | 
            +
                  #
         | 
| 35 | 
            +
                  #   # bad
         | 
| 36 | 
            +
                  #   x / x
         | 
| 37 | 
            +
                  #   x ** 0
         | 
| 38 | 
            +
                  #
         | 
| 39 | 
            +
                  #   # good
         | 
| 40 | 
            +
                  #   1
         | 
| 41 | 
            +
                  #
         | 
| 42 | 
            +
                  #   # bad
         | 
| 43 | 
            +
                  #   x /= x
         | 
| 44 | 
            +
                  #   x **= 0
         | 
| 45 | 
            +
                  #
         | 
| 46 | 
            +
                  #   # good
         | 
| 47 | 
            +
                  #   x = 1
         | 
| 48 | 
            +
                  #
         | 
| 49 | 
            +
                  class NumericOperationWithConstantResult < Base
         | 
| 50 | 
            +
                    extend AutoCorrector
         | 
| 51 | 
            +
                    MSG = 'Numeric operation with a constant result detected.'
         | 
| 52 | 
            +
                    RESTRICT_ON_SEND = %i[- * / % **].freeze
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    # @!method operation_with_constant_result?(node)
         | 
| 55 | 
            +
                    def_node_matcher :operation_with_constant_result?,
         | 
| 56 | 
            +
                                     '(send (send nil? $_) $_ ({int | send nil?} $_))'
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    # @!method abbreviated_assignment_with_constant_result?(node)
         | 
| 59 | 
            +
                    def_node_matcher :abbreviated_assignment_with_constant_result?,
         | 
| 60 | 
            +
                                     '(op-asgn (lvasgn $_) $_ ({int | lvar} $_))'
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                    def on_send(node)
         | 
| 63 | 
            +
                      return unless operation_with_constant_result?(node)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                      variable, operation, number = operation_with_constant_result?(node)
         | 
| 66 | 
            +
                      result = constant_result?(variable, operation, number)
         | 
| 67 | 
            +
                      return unless result
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                      add_offense(node) do |corrector|
         | 
| 70 | 
            +
                        corrector.replace(node, result.to_s)
         | 
| 71 | 
            +
                      end
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    def on_op_asgn(node)
         | 
| 75 | 
            +
                      return unless abbreviated_assignment_with_constant_result?(node)
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                      variable, operation, number = abbreviated_assignment_with_constant_result?(node)
         | 
| 78 | 
            +
                      result = constant_result?(variable, operation, number)
         | 
| 79 | 
            +
                      return unless result
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                      add_offense(node) do |corrector|
         | 
| 82 | 
            +
                        corrector.replace(node, "#{variable} = #{result}")
         | 
| 83 | 
            +
                      end
         | 
| 84 | 
            +
                    end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                    private
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                    # rubocop :disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
         | 
| 89 | 
            +
                    def constant_result?(variable, operation, number)
         | 
| 90 | 
            +
                      if number.to_s == '0'
         | 
| 91 | 
            +
                        return 0 if operation == :*
         | 
| 92 | 
            +
                        return 1 if operation == :**
         | 
| 93 | 
            +
                      elsif number.to_s == '1'
         | 
| 94 | 
            +
                        return 0 if operation == :%
         | 
| 95 | 
            +
                      elsif number == variable
         | 
| 96 | 
            +
                        return 0 if %i[- %].include?(operation)
         | 
| 97 | 
            +
                        return 1 if operation == :/
         | 
| 98 | 
            +
                      end
         | 
| 99 | 
            +
                      # If we weren't able to find any matches, return false so we can bail out.
         | 
| 100 | 
            +
                      false
         | 
| 101 | 
            +
                    end
         | 
| 102 | 
            +
                    # rubocop :enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
         | 
| 103 | 
            +
                  end
         | 
| 104 | 
            +
                end
         | 
| 105 | 
            +
              end
         | 
| 106 | 
            +
            end
         | 
| @@ -27,8 +27,7 @@ module RuboCop | |
| 27 27 | 
             
                    MSG = 'Avoid using or-assignment with constants.'
         | 
| 28 28 |  | 
| 29 29 | 
             
                    def on_or_asgn(node)
         | 
| 30 | 
            -
                       | 
| 31 | 
            -
                      return unless lhs&.casgn_type?
         | 
| 30 | 
            +
                      return unless node.lhs&.casgn_type?
         | 
| 32 31 |  | 
| 33 32 | 
             
                      add_offense(node.loc.operator) do |corrector|
         | 
| 34 33 | 
             
                        next if node.each_ancestor(:def, :defs).any?
         | 
| @@ -111,7 +111,7 @@ module RuboCop | |
| 111 111 | 
             
                      range_between(start + begin_pos - 1, start + end_pos)
         | 
| 112 112 | 
             
                    end
         | 
| 113 113 |  | 
| 114 | 
            -
                    # If the list of cops is comma-separated, but without  | 
| 114 | 
            +
                    # If the list of cops is comma-separated, but without an empty space after the comma,
         | 
| 115 115 | 
             
                    # we should **not** remove the prepending empty space, thus begin_pos += 1
         | 
| 116 116 | 
             
                    def range_with_comma_after(comment, start, begin_pos, end_pos)
         | 
| 117 117 | 
             
                      begin_pos += 1 if comment.source[end_pos + 1] != ' '
         | 
| @@ -6,7 +6,7 @@ module RuboCop | |
| 6 6 | 
             
                  # Checks for redundant safe navigation calls.
         | 
| 7 7 | 
             
                  # Use cases where a constant, named in camel case for classes and modules is `nil` are rare,
         | 
| 8 8 | 
             
                  # and an offense is not detected when the receiver is a constant. The detection also applies
         | 
| 9 | 
            -
                  # to literal receivers, except for `nil`.
         | 
| 9 | 
            +
                  # to `self`, and to literal receivers, except for `nil`.
         | 
| 10 10 | 
             
                  #
         | 
| 11 11 | 
             
                  # For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
         | 
| 12 12 | 
             
                  # and `equal?` methods are checked by default.
         | 
| @@ -29,6 +29,9 @@ module RuboCop | |
| 29 29 | 
             
                  #   # bad
         | 
| 30 30 | 
             
                  #   CamelCaseConst&.do_something
         | 
| 31 31 | 
             
                  #
         | 
| 32 | 
            +
                  #   # good
         | 
| 33 | 
            +
                  #   CamelCaseConst.do_something
         | 
| 34 | 
            +
                  #
         | 
| 32 35 | 
             
                  #   # bad
         | 
| 33 36 | 
             
                  #   do_something if attrs&.respond_to?(:[])
         | 
| 34 37 | 
             
                  #
         | 
| @@ -41,9 +44,6 @@ module RuboCop | |
| 41 44 | 
             
                  #   end
         | 
| 42 45 | 
             
                  #
         | 
| 43 46 | 
             
                  #   # good
         | 
| 44 | 
            -
                  #   CamelCaseConst.do_something
         | 
| 45 | 
            -
                  #
         | 
| 46 | 
            -
                  #   # good
         | 
| 47 47 | 
             
                  #   while node.is_a?(BeginNode)
         | 
| 48 48 | 
             
                  #     node = node.parent
         | 
| 49 49 | 
             
                  #   end
         | 
| @@ -67,6 +67,12 @@ module RuboCop | |
| 67 67 | 
             
                  #   foo.to_f
         | 
| 68 68 | 
             
                  #   foo.to_s
         | 
| 69 69 | 
             
                  #
         | 
| 70 | 
            +
                  #   # bad
         | 
| 71 | 
            +
                  #   self&.foo
         | 
| 72 | 
            +
                  #
         | 
| 73 | 
            +
                  #   # good
         | 
| 74 | 
            +
                  #   self.foo
         | 
| 75 | 
            +
                  #
         | 
| 70 76 | 
             
                  # @example AllowedMethods: [nil_safe_method]
         | 
| 71 77 | 
             
                  #   # bad
         | 
| 72 78 | 
             
                  #   do_something if attrs&.nil_safe_method(:[])
         | 
| @@ -133,7 +139,7 @@ module RuboCop | |
| 133 139 | 
             
                    def assume_receiver_instance_exists?(receiver)
         | 
| 134 140 | 
             
                      return true if receiver.const_type? && !receiver.short_name.match?(SNAKE_CASE)
         | 
| 135 141 |  | 
| 136 | 
            -
                      receiver.literal? && !receiver.nil_type?
         | 
| 142 | 
            +
                      receiver.self_type? || (receiver.literal? && !receiver.nil_type?)
         | 
| 137 143 | 
             
                    end
         | 
| 138 144 |  | 
| 139 145 | 
             
                    def check?(node)
         | 
| @@ -141,8 +147,7 @@ module RuboCop | |
| 141 147 | 
             
                      return false unless parent
         | 
| 142 148 |  | 
| 143 149 | 
             
                      condition?(parent, node) ||
         | 
| 144 | 
            -
                        parent. | 
| 145 | 
            -
                        parent.or_type? ||
         | 
| 150 | 
            +
                        parent.operator_keyword? ||
         | 
| 146 151 | 
             
                        (parent.send_type? && parent.negation_method?)
         | 
| 147 152 | 
             
                    end
         | 
| 148 153 |  | 
| @@ -135,10 +135,10 @@ module RuboCop | |
| 135 135 | 
             
                      grandparent.array_type? && grandparent.children.size > 1
         | 
| 136 136 | 
             
                    end
         | 
| 137 137 |  | 
| 138 | 
            +
                    # rubocop:disable Metrics/AbcSize
         | 
| 138 139 | 
             
                    def replacement_range_and_content(node)
         | 
| 139 | 
            -
                      variable | 
| 140 | 
            -
                       | 
| 141 | 
            -
                      expression = loc.expression
         | 
| 140 | 
            +
                      variable = node.children.first
         | 
| 141 | 
            +
                      expression = node.source_range
         | 
| 142 142 |  | 
| 143 143 | 
             
                      if array_new?(variable)
         | 
| 144 144 | 
             
                        expression = node.parent.source_range if node.parent.array_type?
         | 
| @@ -148,16 +148,17 @@ module RuboCop | |
| 148 148 | 
             
                      elsif redundant_brackets?(node)
         | 
| 149 149 | 
             
                        [expression, remove_brackets(variable)]
         | 
| 150 150 | 
             
                      else
         | 
| 151 | 
            -
                        [loc.operator, '']
         | 
| 151 | 
            +
                        [node.loc.operator, '']
         | 
| 152 152 | 
             
                      end
         | 
| 153 153 | 
             
                    end
         | 
| 154 | 
            +
                    # rubocop:enable Metrics/AbcSize
         | 
| 154 155 |  | 
| 155 156 | 
             
                    def array_splat?(node)
         | 
| 156 157 | 
             
                      node.children.first.array_type?
         | 
| 157 158 | 
             
                    end
         | 
| 158 159 |  | 
| 159 160 | 
             
                    def method_argument?(node)
         | 
| 160 | 
            -
                      node.parent. | 
| 161 | 
            +
                      node.parent.call_type?
         | 
| 161 162 | 
             
                    end
         | 
| 162 163 |  | 
| 163 164 | 
             
                    def part_of_an_array?(node)
         | 
| @@ -171,7 +172,7 @@ module RuboCop | |
| 171 172 | 
             
                      parent = node.parent
         | 
| 172 173 | 
             
                      grandparent = node.parent.parent
         | 
| 173 174 |  | 
| 174 | 
            -
                      parent.when_type? ||  | 
| 175 | 
            +
                      parent.when_type? || method_argument?(node) || part_of_an_array?(node) ||
         | 
| 175 176 | 
             
                        grandparent&.resbody_type?
         | 
| 176 177 | 
             
                    end
         | 
| 177 178 |  | 
| @@ -196,7 +197,7 @@ module RuboCop | |
| 196 197 | 
             
                    def use_percent_literal_array_argument?(node)
         | 
| 197 198 | 
             
                      argument = node.children.first
         | 
| 198 199 |  | 
| 199 | 
            -
                      node | 
| 200 | 
            +
                      method_argument?(node) &&
         | 
| 200 201 | 
             
                        (argument.percent_literal?(:string) || argument.percent_literal?(:symbol))
         | 
| 201 202 | 
             
                    end
         | 
| 202 203 |  | 
| @@ -6,7 +6,7 @@ module RuboCop | |
| 6 6 | 
             
                  # Checks if `include` or `prepend` is called in `refine` block.
         | 
| 7 7 | 
             
                  # These methods are deprecated and should be replaced with `Refinement#import_methods`.
         | 
| 8 8 | 
             
                  #
         | 
| 9 | 
            -
                  # It emulates deprecation warnings in Ruby 3.1.
         | 
| 9 | 
            +
                  # It emulates deprecation warnings in Ruby 3.1. Functionality has been removed in Ruby 3.2.
         | 
| 10 10 | 
             
                  #
         | 
| 11 11 | 
             
                  # @safety
         | 
| 12 12 | 
             
                  #   This cop's autocorrection is unsafe because `include M` will affect the included class
         | 
| @@ -42,15 +42,11 @@ module RuboCop | |
| 42 42 | 
             
                    INVALID_TYPES = %i[array dstr float hash nil int str sym].freeze
         | 
| 43 43 |  | 
| 44 44 | 
             
                    def on_resbody(node)
         | 
| 45 | 
            -
                       | 
| 46 | 
            -
                      return if rescued.nil?
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                      exceptions = *rescued
         | 
| 49 | 
            -
                      invalid_exceptions = invalid_exceptions(exceptions)
         | 
| 45 | 
            +
                      invalid_exceptions = invalid_exceptions(node.exceptions)
         | 
| 50 46 | 
             
                      return if invalid_exceptions.empty?
         | 
| 51 47 |  | 
| 52 48 | 
             
                      add_offense(
         | 
| 53 | 
            -
                        node.loc.keyword.join( | 
| 49 | 
            +
                        node.loc.keyword.join(node.children.first.source_range),
         | 
| 54 50 | 
             
                        message: format(MSG, invalid_exceptions: invalid_exceptions.map(&:source).join(', '))
         | 
| 55 51 | 
             
                      ) do |corrector|
         | 
| 56 52 | 
             
                        autocorrect(corrector, node)
         | 
| @@ -58,7 +54,7 @@ module RuboCop | |
| 58 54 | 
             
                    end
         | 
| 59 55 |  | 
| 60 56 | 
             
                    def autocorrect(corrector, node)
         | 
| 61 | 
            -
                      rescued | 
| 57 | 
            +
                      rescued = node.children.first
         | 
| 62 58 | 
             
                      range = node.loc.keyword.end.join(rescued.source_range.end)
         | 
| 63 59 |  | 
| 64 60 | 
             
                      corrector.replace(range, correction(*rescued))
         | 
| @@ -83,6 +83,8 @@ module RuboCop | |
| 83 83 | 
             
                    def find_consistent_parts(grouped_operands)
         | 
| 84 84 | 
             
                      csend_in_and, csend_in_or, send_in_and, send_in_or = most_left_indices(grouped_operands)
         | 
| 85 85 |  | 
| 86 | 
            +
                      return if csend_in_and && csend_in_or && csend_in_and < csend_in_or
         | 
| 87 | 
            +
             | 
| 86 88 | 
             
                      if csend_in_and
         | 
| 87 89 | 
             
                        ['.', (send_in_and ? [send_in_and, csend_in_and].min : csend_in_and) + 1]
         | 
| 88 90 | 
             
                      elsif send_in_or && csend_in_or
         | 
| @@ -43,23 +43,21 @@ module RuboCop | |
| 43 43 | 
             
                    alias on_csend on_send
         | 
| 44 44 |  | 
| 45 45 | 
             
                    def on_lvasgn(node)
         | 
| 46 | 
            -
                       | 
| 47 | 
            -
                      return unless rhs
         | 
| 46 | 
            +
                      return unless node.rhs
         | 
| 48 47 |  | 
| 49 48 | 
             
                      rhs_type = ASSIGNMENT_TYPE_TO_RHS_TYPE[node.type]
         | 
| 50 49 |  | 
| 51 | 
            -
                      add_offense(node) if rhs.type == rhs_type && rhs.source == lhs.to_s
         | 
| 50 | 
            +
                      add_offense(node) if node.rhs.type == rhs_type && node.rhs.source == node.lhs.to_s
         | 
| 52 51 | 
             
                    end
         | 
| 53 52 | 
             
                    alias on_ivasgn on_lvasgn
         | 
| 54 53 | 
             
                    alias on_cvasgn on_lvasgn
         | 
| 55 54 | 
             
                    alias on_gvasgn on_lvasgn
         | 
| 56 55 |  | 
| 57 56 | 
             
                    def on_casgn(node)
         | 
| 58 | 
            -
                       | 
| 59 | 
            -
                      return unless rhs&.const_type?
         | 
| 57 | 
            +
                      return unless node.rhs&.const_type?
         | 
| 60 58 |  | 
| 61 | 
            -
                       | 
| 62 | 
            -
             | 
| 59 | 
            +
                      add_offense(node) if node.namespace == node.rhs.namespace &&
         | 
| 60 | 
            +
                                           node.short_name == node.rhs.short_name
         | 
| 63 61 | 
             
                    end
         | 
| 64 62 |  | 
| 65 63 | 
             
                    def on_masgn(node)
         | 
| @@ -67,15 +65,15 @@ module RuboCop | |
| 67 65 | 
             
                    end
         | 
| 68 66 |  | 
| 69 67 | 
             
                    def on_or_asgn(node)
         | 
| 70 | 
            -
                       | 
| 71 | 
            -
                      add_offense(node) if rhs_matches_lhs?(rhs, lhs)
         | 
| 68 | 
            +
                      add_offense(node) if rhs_matches_lhs?(node.rhs, node.lhs)
         | 
| 72 69 | 
             
                    end
         | 
| 73 70 | 
             
                    alias on_and_asgn on_or_asgn
         | 
| 74 71 |  | 
| 75 72 | 
             
                    private
         | 
| 76 73 |  | 
| 77 74 | 
             
                    def multiple_self_assignment?(node)
         | 
| 78 | 
            -
                      lhs | 
| 75 | 
            +
                      lhs = node.lhs
         | 
| 76 | 
            +
                      rhs = node.rhs
         | 
| 79 77 | 
             
                      return false unless rhs.array_type?
         | 
| 80 78 | 
             
                      return false unless lhs.children.size == rhs.children.size
         | 
| 81 79 |  | 
| @@ -67,7 +67,7 @@ module RuboCop | |
| 67 67 | 
             
                    def on_rescue(node)
         | 
| 68 68 | 
             
                      return if rescue_modifier?(node)
         | 
| 69 69 |  | 
| 70 | 
            -
                       | 
| 70 | 
            +
                      rescues = node.resbody_branches
         | 
| 71 71 | 
             
                      rescued_groups = rescued_groups_for(rescues)
         | 
| 72 72 |  | 
| 73 73 | 
             
                      rescue_group_rescues_multiple_levels = rescued_groups.any? do |group|
         | 
| @@ -58,6 +58,9 @@ module RuboCop | |
| 58 58 | 
             
                        Regexp::Parser.parse(text.value)&.each_expression do |expr|
         | 
| 59 59 | 
             
                          detect_offenses(text, expr)
         | 
| 60 60 | 
             
                        end
         | 
| 61 | 
            +
                      rescue Regexp::Parser::ParserError
         | 
| 62 | 
            +
                        # Upon encountering an invalid regular expression,
         | 
| 63 | 
            +
                        # we aim to proceed and identify any remaining potential offenses.
         | 
| 61 64 | 
             
                      end
         | 
| 62 65 | 
             
                    end
         | 
| 63 66 |  |